摂氏⇔華氏の単位切り替え機能を追加する
次は少し発展的な機能として、温度の単位を「摂氏」と「華氏」で切り替えられるようにしてみよう。Copilot Chatに次のように頼んでみる。
温度を摂氏と華氏で切り替えられるトグルスイッチを追加してください。
初期状態は摂氏で、スイッチをクリックすると単位が切り替わるようにしてください
index.htmlには、検索ボタンのタグの次に、トグルスイッチを表示する次のコードが追加された。同時に、style.cssにも見た目を整えるためのスタイル指定が追加されている。(コードは省略)。
<div class="unit-wrapper" title="表示単位を切り替え">
<span class="unit-label">℃</span>
<label class="switch">
<input type="checkbox" id="unit-toggle">
<span class="slider"></span>
</label>
<span class="unit-label">°F</span>
</div
script.jsは、筆者の環境では次のように書き換えられた。
// OpenWeather APIキー(ダミー)
const API_KEY = "YOUR_API_KEY_HERE";
// 現在の表示単位('C' または 'F')、初期は摂氏
let currentUnit = 'C';
// 最後に取得したデータを保持(再描画用)
let lastData = null;
// ヘルパー:摂氏から華氏に変換
function cToF(c) {
return (c * 9 / 5) + 32;
}
// 天気データを受け取って表示する共通処理
function renderWeather(data) {
const infoEl = document.getElementById('weather-info');
// 必要なフィールドを取り出す(存在チェック)
const name = data.name || '';
const country = data.sys && data.sys.country ? data.sys.country : '';
const cTemp = data.main && typeof data.main.temp === 'number' ? data.main.temp : null;
const temp = cTemp !== null
? (currentUnit === 'C' ? Math.round(cTemp) : Math.round(cToF(cTemp)))
: '―';
const unitLabel = currentUnit === 'C' ? '°C' : '°F';
const description = data.weather && data.weather[0] && data.weather[0].description ? data.weather[0].description : '';
const iconCode = data.weather && data.weather[0] && data.weather[0].icon ? data.weather[0].icon : null;
const iconUrl = iconCode ? `https://openweathermap.org/img/wn/${iconCode}@2x.png` : '';
// 表示用HTMLを組み立てて挿入
infoEl.innerHTML = `
<div class="weather-card">
<div class="weather-main">
<div class="weather-location">${name}${country ? ', ' + country : ''}</div>
<div class="weather-temp">${temp}${unitLabel}</div>
<div class="weather-desc">${description}</div>
</div>
${iconUrl ? `<div class="weather-icon"><img src="${iconUrl}" alt="${description}"></div>` : ''}
</div>
`;
}
// 検索実行関数(fetch処理)
function fetchWeather(city) {
const url = `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(city)}&appid=${API_KEY}&lang=ja&units=metric`;
const infoEl = document.getElementById('weather-info');
infoEl.textContent = '読み込み中...';
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log(data);
lastData = data; // 保持しておく
renderWeather(data);
})
.catch(error => {
console.error('天気情報の取得に失敗しました:', error);
infoEl.textContent = '天気情報の取得に失敗しました。都市名を確認してください。';
});
}
// 初期イベント設定
document.getElementById('search-btn').addEventListener('click', () => {
const city = document.getElementById('city-input').value.trim();
if (!city) return;
fetchWeather(city);
});
// 単位トグルのイベント:切替時に現在表示を再描画する
document.getElementById('unit-toggle').addEventListener('change', (e) => {
currentUnit = e.target.checked ? 'F' : 'C';
// 既にデータがあれば再描画して単位だけ切り替える
if (lastData) {
renderWeather(lastData);
}
});
以前のコードと比べると、かなりの部分が変更されている。Copilotからの提案を確定した後で、変更箇所をもう一度確認したい場合には、チャット欄に表示されているファイル名をクリックすればよい。次のようにエディターで差分を表示してくれる。赤い部分が古いコード、緑の部分が新しいコードだ。
この差分をよく見比べると、APIへのリクエストを送る処理が「fetchWeather()」という関数に分割され、さらにAPIからのリクエストを受け取ってデータの取り出しや表示の処理をする部分は「renderWeather()」という関数に切り出されていることがわかる。
もしもCopilotがこのような変更を行った意図がわからなければ、素直にチャットで聞いてみるといいだろう。今回であれば、次のように質問すれば、Copilotがなぜこのような書き換えを提案したのかを説明してくれるはずだ。
fetchWeatherやrenderWeatherを関数として切り分けた理由を教えてください
最初に生成したコードで関数化しなかったのはなぜですか
些細なことでも、コードの理解を深めるには、納得ができるまで質問して確認するのが大切だ。
さて肝心の気温の単位についてだが、チャット欄でも説明されていたように、APIへは「metric」つまり「摂氏」を指定して問い合わせており、画面表示の際に、トグルスイッチで指定した単位に切り替える処理になっている。
それでは、Webブラウザでindex.htmlをリロードしてみよう。次のように、[検索]ボタンの右側に単位を指定するスイッチが追加されており、検索結果の表示もスイッチを押して切り替えられるようになった。
日本語での検索に対応するには
さて、先程も書いたように、OpenWeather APIは日本語の都市名に対応していないので、このアプリでは「東京」のように日本語での天気の検索ができない。これを修正するにはどうしたらいいだろうか。Copilot Chatに聞いてみよう。まだ実装は開始したくないので、ここではあえて説明だけをしてもらうように明確に指示している。
日本語の都市名での検索にも対応させたい場合は、どのようにすればいいですか。
まずは手順を教えてください
Copilot Chatの返答は次のようなものだった。
手順(簡潔):
1. 入力を正規化する
・前後の空白除去、全角/半角の統一(必要なら)、大文字小文字の統一などを行う。
2. ジオコーディングAPIで名前を解決する(推奨)
・OpenWeather の Geocoding API を使って日本語の地名を緯度・経度に変換する。
・例: GET https://api.openweathermap.org/geo/1.0/direct?q={encodeURIComponent(都市名)}&limit=5&appid={APIキー}
・結果に複数候補が来た場合は国コード(country === "JP")や州名で絞るか、ユーザーに候補選択を促す。
3. 緯度・経度で気象データを取得する
・ジオコーディングで得た lat, lon を使って天気APIを呼ぶ:
https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={APIキー}&lang=ja&units=metric
4. 直接 q パラメータでも試す(簡易実装)
・小規模なら encodeURIComponent(都市名) を q に渡して /weather を直接呼ぶ実装でも動作することが多いが、同名都市の曖昧さや表記揺れに弱い。
5. ユーザーへのフィードバックを用意する
・候補が複数あるときの選択UI、該当なしのメッセージ、読み込み中表示、エラー表示を実装する。
6. 実装上の注意点
・APIキーは安全に管理する(公開リポジトリに直書きしない)。
・リクエスト数制限に注意(Geocoding を毎回呼ぶと消費が早い)。キャッシュを入れると良い。
・エンコーディングは UTF-8 を前提にし、必ず encodeURIComponent を使う。
テスト例:
・「東京」「大坂」「さいたま」「札幌」など日本語表記でジオコーディング→天気取得が期待通り動くことを確認する
重要なのは2と3の手順だろう。実は、Openweather APIのエンドポイントには、緯度と経度を指定するパラメーターも用意されている。これを使えば、正確な位置の天気が取得できる。それでは、緯度・軽度はどうやって調べればいいか。Openweatherのサービスの1つにGeocoading APIというものがあり、これを使えば、都市名から緯度・軽度を取得できると、Copilot Chatは提案しているわけだ。
方法がわかったら、あとはこれまでと同様に、Copilot Chatに指示を出して順番に実装を追加していけばいい。新たに登場したGeocoading APIの使い方も、Copilot Chatが詳しく教えてくれるはずだ。ただし、本連載第1回で説明したように、Copilot ChatはFreeプランの場合は1カ月あたりのメッセージ数が限られているので、使いすぎには注意しよう。


