カテゴリー
HTML jQuery Webサイト作成

現在地の天気予報表示

こんにちは、エムケーワイです。

これまでJavaScriptを使った位置情報の取得に関連し、現在地の位置情報の取得および現在地の地図表示を行いましたが、今回は第3弾として現在地の天気予報の表示にトライしてみます。

天気予報データの取得にはイギリスのOpenWeather社が提供しているWeather APIを使用します。Weather APIには様々なサービスがありますが、今回は「5 day / 3 hour weather forecast」というサービスを利用します。これは、指定した位置の3時間毎5日間の天気予報データが取得できるサービスで、無料で利用することができます。

現在地の地図表示」ではGoogle Maps APIを使用するためにAPIキーを取得する必要がありましたが、今回もOpenWeather社のWebサイトでアカウントを作成し、APIキーを取得する必要があります。その手順については別記事にて説明します。

では、説明に移ります。今回も最初に実際の動作を確認していただき、その後実現方法の説明を行います。

目次 [閉じる]
  1. 現在地の位置情報の取得と天気予報表示
  2. HTMLコード
  3. JavaScriptコード
  4. CSS設定
  5. まとめ

1. 現在地の位置情報の取得と天気予報表示

現在地の地図表示」と同じく下の「現在地を取得」ボタンのクリックにより、現在地の位置情報を取得し、緯度、経度、精度を表示した上で現在地の3時間毎5日間の天気予報を表示します。下図のようなメッセージが表示されたら「許可する」をクリックしてください(下図はFirefoxの例です)。

OpenWeather社の天気予報は10分間に1回です。申し訳ありませんが、「現在地を取得」ボタンのクリックは10分間で1回以下としてください。

現在地は

 緯度:°

 経度:°

 精度(半径):m

 ()

です。

の天気予報

2. HTMLコード

今回作成したHTMLコードは下記の通りです。

<section class="mkyPosSection">
    <input type="button" value="現在地を取得" id="button1">
    <div class="mkyPosInfo">
        <p>現在地は</p>
        <p> 緯度:<span id="pos1" class="mkyPosition"></span>°</p>
        <p> 経度:<span id="pos2" class="mkyPosition"></span>°</p>
        <p> 精度(半径):<span id="pos3" class="mkyPosition"></span>m</p>
        <p><span id="pos4" class="mkyPosition"> ()</span></p>
        <p>です。</p>
    </div>
    <h3 class="mkyCity"><span id="city"></span>の天気予報</h3>
    <div id="immediate">
    </div>
    <table id="forecast">
    </table>
</section>

前半は「位置情報の取得」、「現在地の地図表示」と同じなので、後半部分のみ説明します。

  1. 位置情報の最後に都市名と国コードを表示するためのp要素とspan要素を追加しています。span要素の内容として、JavaScriptにより都市名と国コード(日本の場合は”JP”)が挿入されます。都市名と国コードは位置情報データからではなく、天気予報データから取得します。
  2. 天気予報のタイトルを表示するためのh3要素とspan要素を配置します。span要素の内容として、JavaScriptにより都市名が挿入されます。これによりタイトルは「〇〇市の天気予報」のように表示されます。
  3. 直近の天気予報を表示する領域をdivタグで囲みます。このdivタグ内にJavaScriptで直近の天気予報データを表示するHTMLコードを挿入します。
  4. その後の天気予報を表示する領域をtableタグで囲みます。tableタグ内にJavaScriptでその後の天気予報データを表示するHTMLコードを挿入します。

3. JavaScriptコード

今回作成したJavaScriptコードは下記の通りです。

'use strict';

function success(pos) {
    const lat = pos.coords.latitude;
    const long = pos.coords.longitude;
    const accuracy = pos.coords.accuracy;

    document.getElementById('pos1').textContent = lat;
    document.getElementById('pos2').textContent = long;
    document.getElementById('pos3').textContent = accuracy;

    getWeatherForecast(lat, long);
}

function fail(error) {
    alert('現在地の取得に失敗しました。エラーコード:' + error.code);
}

document.getElementById('button1').onclick = function() {
    navigator.geolocation.getCurrentPosition(success, fail);
    this.blur();
}

// 天気予報データ取得
function getWeatherForecast(lat, long) {
    const url = 'https://api.openweathermap.org/data/2.5/forecast';
    const appId = 'API key';

    jQuery.ajax({
        url: url,
        data: {
            appid: appId,
            lat: lat,
            lon: long,
            units: 'metric',
            lang: 'ja'
        }
    })
    .done(function(data) {
        // 都市名、国名
        jQuery('#pos4').text(' ' + data.city.name + ' (' + data.city.country + ')');
        jQuery('#city').text(data.city.name);

        // 天気予報データ
        data.list.forEach(function(forecast, index) {
            const dateTime = new Date(forecast.dt * 1000);
            const month = dateTime.getMonth() + 1;
            const date = dateTime.getDate();
            const hours = dateTime.getHours();
            const minutes = String(dateTime.getMinutes()).padStart(2, '0');
            const temperature = Math.round(forecast.main.temp * 10) / 10;
            const description = forecast.weather[0].description;
            const iconPath = `https://openweathermap.org/img/wn/${forecast.weather[0].icon}@2x.png`;

            if (index === 0) {
                const forecast0 = `
                <p>${month}/${date} ${hours}:${minutes}</p>
                <div class="icon"><img src="${iconPath}"></div>
                <div class="info">
                    <p>
                        <span class="description">${description}</span>
                        <span class="temp">${temperature}</span>℃
                    </p>
                </div>`;
                jQuery('#immediate').html(forecast0);
            } else {
                const forecast =`
                <tr>
                    <td class="info">
                        ${month}/${date} ${hours}:${minutes}
                    </td>
                    <td class="icon"><img src="${iconPath}"></td>
                    <td><span class="description">${description}</span></td>
                    <td><span class="temp">${temperature}</span>℃</td>
                </tr>`;
                jQuery('#forecast').append(forecast);
            }
        });
    })
    .fail(function() {
        console.log('jQuery.ajax failed!');
    })
}

位置情報の取得」のJavaScriptコードに対して追加された関数getWeatherForecast()について説明します。

3-1. 関数getWeatherForecast()の呼び出し

関数success()内で緯度、経度、精度を表示した後、緯度と経度を引数として関数getWeatherForecast()を呼び出します。

3-2. function getWeatherForecast()

Weather APIを使ってOpenWeather社のサイトから天気予報データを取得し、必要なデータを抽出して表示します。天気予報データを取得する際はAjax(非同期通信)を使用します。AjaxはJavaScriptの機能ですが、記述が簡単になるので、今回はjQuery.ajaxメソッドを使用します。

  1. 定数urlに天気予報データを取得するサイトのURLを格納します。
  2. 定数appIdにOpenWeather社のWebサイトで取得したAPIキーを格納します。
  3. jQuery.ajaxメソッドを使ってOpenWeather社のWebサイトにアクセスし、天気予報データを取得します。パラメータとしては”url”と”data”があり、”url”には定数urlを渡します。”data”はオブジェクト構成になっており、”appid”には定数appIdを、”lat”、”lon”にはそれぞれ関数の引数であるlat(緯度)、long(経度)を渡します。”units”には’metric’を渡します。これにより気温の単位が摂氏(℃)になります。”lang”には’ja’を渡します。これにより取得データの一部が日本語化されます。取得データのフォーマットはJSONフォーマットです。
  4. 天気予報データの取得に成功すると、.done()の処理が実行されます。処理内容については後述します。
  5. 天気予報データが取得できなかった場合は、.fail()の処理が実行され、ブラウザの開発ツールのコンソールにエラーメッセージが表示されます。

天気予報データは緯度および経度を指定する以外に、都市名または都市ID(city ID)を指定することができます。都市名で指定する場合、”data”内で”lat”、”lon”の代わりに”q”を、都市IDで指定する場合”id”を使用します。詳細はOpwnWeather社のAPI documentationのサイトでご確認ください。

3-3. 天気予報データ取得成功時の処理

取得したデータから都市名・国コード、日時、天気予報データを抽出し、表示します。

  1. id “pos4″を持つ要素(位置情報に追加されたspan要素)の内容として、都市名と国コードを挿入します。取得データ全体を”data”とすると、都市名は”data.city.name”、国コードは”data.city.country”です。なお、都市名は日本語、国コードは2文字のアルファベットです。
  2. id “city”を持つ要素(天気予報のタイトル内のspan要素)の内容として都市名を挿入します。
  3. 天気予報データは取得データの”list”内に配列として格納されています。forEachメソッドを使ってひとつずつ処理します。
  4. 定数dateTimeに天気予報データの日時を格納します。”list”内のひとつひとつのデータを”forecast”とすると、日時は”forecast.dt”です。取得データの日時はUNIX UTC時間で1970年1月1日午前0時からの経過秒です。Dateオブジェクトの日時の単位はミリ秒なので、1000倍した値を格納します。
  5. 定数dateTimeのgetMonthメソッド等を使って月、日、時、分を取得し、それぞれ定数month、date、hours、minutesに格納します。月は0から始まるので+1する必要があります。分は常に2桁表示されるようにしています。
  6. 定数tenperatureに気温を格納します。”list”内のひとつひとつのデータを”forecast”とすると、気温は”forecast.main.temp”です。小数点以下1桁まで表示するために、10倍した値を四捨五入後10で割っています。
  7. 定数descriptionに天気の説明を格納します。”list”内のひとつひとつのデータを”forecast”とすると、天気の説明は”forecast.weather[0].description”です。”weather”は何故か配列になっており、先頭の要素から取得します。
  8. 定数iconPathにアイコン画像へのパスを格納します。”list”内のひとつひとつのデータを”forecast”とすると、アイコンは”forecast.weather[0].icon”です。”icon”プロパティには”10d”(雨、日中)、”10n”(雨、夜)等の文字列が設定されており、”10d”の場合アイコン画像へのパスは”https://openweathermap.org/img/wn/10d@2x.png”となります。
  9. “list”内の先頭データは直近の天気予報で、以降の予報より大きく表示します。日時、アイコン画像、説明&気温を縦に並べて配置するHTMLコードを生成し、id “immediate”を持つ要素(div要素)の内容として挿入します。
  10. “list”内の2番目以降のデータはテーブル表示します。各データの日時、アイコン画像、説明、気温をテーブルの1行に配置するHTMLコードを生成し、id “forecast”を持つ要素(table要素)の内容として追加していきます。

4. CSS設定

天気予報データの表示に関するCSS設定を以下に示します。

.mkyCity {
    text-align: center;
}

#immediate {
    margin: 0 auto;
    border: 1px solid #ccc;
    max-width: 400px;
    min-height: 300px;
}
#immediate .icon img {
    width: 200px;
    margin: 0 auto;
}
#immediate p {
    text-align: center;
    font-weight: bold;
}
#immediate .temp {
    padding-left: 36px;
}

#forecast {
    border-collapse: collapse;
    margin: 2rem auto 0;
    max-width: 400px;
}
#forecast th, #forecast td {
    border-top: 1px solid #ccc;
    border-right: none;
    border-bottom: none;
    border-left: none;
    padding: 8px;
}
#forecast tr td:first-of-type {
    border-left: 1px solid #ccc;
}
#forecast tr td:last-of-type {
    border-right: 1px solid #ccc;
    text-align: right;
}
#forecast tr:last-of-type {
    border-bottom: 1px solid #ccc;
}
#forecast .icon {
    width: 64px;
}
#forecast .icon img {
    width: 48px;
}
#forecast .info p {
    margin: 0;
}

主な設定内容は下記の通りです。

  1. 天気予報データは、タイトル(クラス”mkyCity”)、直近の予報(id”immediate”)、その後の予報(id”forecast”)とも左右中心に表示します。
  2. 直近の予報は全体を枠で囲み、最大幅を400px、最小高さを300pxとしています。日時、アイコン画像、説明&気温を枠内の左右中心に表示します。アイコン画像の幅を200pxとしています。
  3. その後の予報はテーブル全体を枠で囲み、テーブルの最大幅を400pxとしています。日時、アイコン画像、説明、気温の間は枠線なしとしています。アイコン画像の幅は48pxとしています。気温は右詰め表示としています。

5. まとめ

JavaScriptを使って現在地の位置情報と天気予報の表示を行いました。

天気予報データの取得には、OpenWeather社が提供しているWeather APIの「5 day / 3 hour weather forecast」というサービスを利用しました。そして、実際に天気予報データを取得する際はAjax(jQquery.ajaxメソッド)を使用しました。

今回は天気予報データの中から都市名、国コード、日時、アイコン画像、天気の説明(description)、気温を抽出・表示しました。データ取得の際”lang”に’ja’を指定したことにより、都市名と天気の説明は日本語で返されました。また、”units”に’metric’を指定したことにより、気温の単位が℃になりました。

アイコン画像はひとつの天気に対し日中用と夜用が用意されています。オリジナルのサイズは100px x 100pxの様です。晴天がただのオレンジ(日中)の丸か黒(夜)の丸なのがちょっと残念でした。イギリスではこのようなアイコンが使われているのでしょうか?

天気の説明は、同じアイコン画像でも「曇りがち」と「厚い雲」、「小雨」と「適度な雨」のように複数用意されているものがあります。気象庁の用語とは必ずしも一致しないようです^_^;

今回はWeather APIを使用って天気予報データを取得しました。地図表示ではGoogle Maps APIを使いましたが、APIを使うことによりWebサイトで出来ることが広がることが実感できました。Weather APIやGoogle Maps API以外にも有用なAPIがたくさんあると思うので、今後も色々調べて活用して行きたいと思います。

最後までお読みいただきありがとうございました。