こんにちは、Smart Designの伊藤です。
前回の記事(開発備忘録 #1)では、Angularを使ってお天気アプリを開発するための事前準備を紹介しました。
今回はその続編として、
- 取得した天気データとそのグラフの表示(Chart.js)
を中心に紹介していきます。
5.グラフで天気を可視化
天気予報といえば、数値だけでなく「視覚的なグラフ表示」があると分かりやすくなりますよね。このアプリでも、Chart.js を用いて、天気データ(気温)を折れ線グラフで可視化する機能を実装しました。
ここでは、
・どのような手順で天気情報を取得しグラフ表示しているか
・使用しているコンポーネントとその役割
・各コンポーネントで実行している処理
について解説します。
5-1.表示までの流れ
1.weather.component
がフォームから都市名を受け取る
2.weather.service.ts
で OpenWeatherMap API にリクエストを送り、天気データを取得
3.取得データを整形し、テンプレートで表示
4.同時にweather-chart.component
に気温の時系列データを渡し、グラフ表示を行う
5-2. コンポーネント
weather.component
(親)
ファイル | 説明 |
---|---|
weather.component.ts | ユーザーの入力(都市名)を受け取り、APIリクエストを実行。結果データをテンプレートと子コンポーネントへ渡す。 |
weather.component.html | 検索フォームと天気データ表示、 を配置し、チャートデータを渡す。 |
weather-chart.component
(子)
ファイル | 説明 |
---|---|
weather-chart.component.ts | @ Input() で受け取った気温データを元に Chart.js グラフを描画。※ここで表記されているInput()は、リンクを消すためにわざとスペースを入れています |
weather-chart.component.html | Chart.js コンポーネントをテンプレート内に定義。 |
weather.service.ts
(サービス)
ファイル | 説明 |
---|---|
weather.service.ts | OpenWeatherMap API など外部APIとの通信を担う。HttpClient を用いて天気データを取得し、Observable で返す。 |
5-3.各コンポーネントの処理の流れ
weather.component.ts
export class WeatherComponent {
weatherData: any;
chartData: number[] = [];
chartLabels: string[] = [];
constructor(private weatherService: WeatherService) {}
search(city: string) {
this.weatherService.getWeather(city).subscribe(data => {
this.weatherData = data;
// グラフ用のデータ抽出(例: 3時間ごとの気温)
this.chartLabels = data.list.map((item: any) =>
new Date(item.dt_txt).getHours() + '時'
);
this.chartData = data.list.map((item: any) =>
Math.round(item.main.temp)
);
});
}
}
WeatherComponent
で行っている処理
このコンポーネントは、天気検索とグラフ表示の中核的な役割を担っています。主な処理の流れは以下の通りです:
1. ユーザーが都市名を入力して検索を実行
search(city: string)
メソッドが呼び出され、入力された都市名を引数に WeatherService
を通じて API リクエストを送信。
2. 取得した天気データを受け取り保持
this.weatherData
に API から返された天気予報(5日分/3時間刻みのデータ)をそのまま保持。
3. グラフ描画用のデータを抽出・整形
chartLabels
: 各予報の時刻を「○時」の形式に変換し、横軸のラベルとして使う。
chartData
: 各予報時点の気温を取り出して、縦軸のデータセットとして使用。
これらはそのまま子コンポーネントの weather-chart に渡され、グラフ表示に利用されます。
weather.component.html
<form (ngSubmit)="search(cityInput.value)">
<input #cityInput type="text" placeholder="都市名を入力" />
<button type="submit">検索</button>
</form>
<!-- 天気の概要表示 -->
<div *ngIf="weatherData">
<h2>{{ weatherData.city.name }} の天気</h2>
<p>現在の気温: {{ weatherData.list[0].main.temp }}℃</p>
<!-- グラフ表示コンポーネント -->
<app-weather-chart
[labels]="chartLabels"
[data]="chartData">
</app-weather-chart>
</div>
weather.component.html
の構成と処理の流れ
1. 天気検索フォーム
<input type="text" [(ngModel)]="city" placeholder="都市名を入力" />
<button (click)="search(city)">検索</button>
-
双方向バインディング([(
ngModel
)]) により、入力欄とcity
変数が常に同期 - 検索ボタン押下で
search()
メソッドを呼び出し、APIリクエストを実行
2. 天気情報の表示(検索結果)
<div *ngIf="weatherData">
<h2>{{ weatherData.city.name }} の天気</h2>
<ul>
<li *ngFor="let item of weatherData.list.slice(0, 5)">
{{ item.dt_txt }} - {{ item.weather[0].description }} - {{ item.main.temp }}°C
</li>
</ul>
</div>
-
*ngIf
で天気データがある場合のみ結果を表示 -
*ngFor
で最初の数件(例:5件)の予報を簡易表示 - 日時・天気概要・気温 をシンプルに出力
3. グラフコンポーネントの表示
<app-weather-chart
[labels]="chartLabels"
[data]="chartData">
</app-weather-chart>
- 子コンポーネント
WeatherChartComponent
をテンプレート内に配置 -
@Input()
で渡されたlabels
(時刻ラベル)とdata
(気温データ)を使ってグラフを描画
weather-chart.component.ts
import { Component, Input, OnChanges } from '@angular/core';
@Component({
selector: 'app-weather-chart',
templateUrl: './weather-chart.component.html',
styleUrls: ['./weather-chart.component.css']
})
export class WeatherChartComponent implements OnChanges {
@Input() data: number[] = [];
@Input() labels: string[] = [];
public chart: any;
ngOnChanges() {
this.renderChart();
}
renderChart() {
this.chart = {
type: 'line',
data: {
labels: this.labels,
datasets: [{
label: '気温 (℃)',
data: this.data,
borderColor: 'rgba(75, 192, 192, 1)',
fill: false,
}]
},
options: {
responsive: true,
plugins: {
legend: { display: true },
},
scales: {
y: {
beginAtZero: false
}
}
}
};
}
}
weather-chart.component.ts
の処理
このコンポーネントは、親コンポーネントから渡された天気データをグラフで可視化する専用パーツです。表示ロジックに特化し、グラフ描画を担当します。
主な役割と処理
@Input() labels: string[] = [];
@Input() data: number[] = [];
- 親コンポーネント(
WeatherComponent
)から、グラフのラベル(時刻)とデータ(気温)を受け取る -
@Input()
デコレーターで双方向バインディングなしに受け取る「受信専用プロパティ」を定義
グラフライブラリへのデータ提供
chartOptions = {
responsive: true,
plugins: { legend: { display: false } }
};
chartData = [{ data: [], label: '気温' }];
chartLabels: string[] = [];
-
ngOnChanges()
などで@Input()
で受け取ったデータを、グラフ用の構造に整形 - 使用しているグラフライブラリ(Chart.js、ng2-charts)に合わせた構造へ変換して渡す
weather-chart.component.html
<canvas baseChart
[data]="chart.data"
[type]="chart.type"
[options]="chart.options">
</canvas>
このテンプレートは、グラフライブラリ(Chart.js + ng2-charts)を使って気温の変化を可視化するビューです。描画部分は非常にシンプルながら、動的なデータバインディングに対応しています。
処理のポイント
-
baseChart
ディレクティブは、ng2-charts ライブラリのコンポーネント機能 -
[data]
:グラフに表示する系列データ(例:気温)をバインド -
[type]
:グラフの種類(例:'line', 'bar' など)を指定 -
[options]
:凡例や軸の表示設定などの各種カスタマイズオプション
データの流れ
-
weather.component.ts
で都市の天気データを取得 -
weather-chart.component.ts
で@Input()
を通じて受け取ったデータをchart.data
に変換 - テンプレートの
<canvas baseChart>
に反映され、気温のグラフが自動描画される
weather.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';
@Injectable({
providedIn: 'root'
})
export class WeatherService {
private apiUrl = 'https://api.openweathermap.org/data/2.5/forecast';
constructor(private http: HttpClient) {}
getWeather(city: string): Observable<any> {
return this.http.get(this.apiUrl, {
params: {
q: city,
units: 'metric',
appid: environment.weatherApiKey
}
});
}
}
天気データを取得するサービス:WeatherService
WeatherService
は、アプリケーション内の他のコンポーネントから呼び出され、OpenWeatherMap の天気予報 API にアクセスして天気情報を取得するサービスです。HTTP通信の実装を専用のクラスに分離することで、保守性とテスト性が向上します。
主な役割と処理
1.サービスとしてアプリに登録
@Injectable({ providedIn: 'root' })
- この1行で、アプリ全体でこのサービスをシングルトンとして利用可能にした
- 各コンポーネントで DI(依存性注入)を通じて呼び出すだけで使える
2.HTTP通信の実装
constructor(private http: HttpClient) {}
- Angular の
HttpClient
を使って外部 API にアクセス - 必要なモジュールは
HttpClientModule
をAppModule
にインポートして使用
3.天気APIの呼び出し
getWeather(city: string): Observable<any> {
return this.http.get(this.apiUrl, {
params: {
q: city,
units: 'metric',
appid: environment.weatherApiKey
}
});
}
-
city
を引数に取り、OpenWeatherMap API に GET リクエストを送信 -
メトリック単位(摂氏)で取得し、APIキーは環境変数
environment.weatherApiKey
から安全に参照 - 戻り値は
Observable<any
> 型で返却され、呼び出し元(コンポーネント)で.subscribe()
によって非同期的に取得・処理
5-4.まとめ
このように、親コンポーネントでAPIから取得した天気データを加工し、子コンポーネントに渡すことで、Angularらしい責務分離と再利用性のある設計が実現できました。
-
データ取得はサービス層に集約(
weather.service.ts
) -
表示とグラフ描画はコンポーネントごとに責任分担
-
@Input()
によるデータの受け渡しで柔軟な連携
次回は、検索履歴の保存や、位置情報との連携について掘り下げていきます。