今回はapi/ajaxを使って天気アプリを作ってみる。
参考サイトはこちら
あらすじとシナリオは
今回はOpenWeatherMapのapiを使う。
OpenWeatherMapは、Webやモバイルアプリケーションの開発者に、現在の天候や予測履歴を含む各種気象データの無料APIを提供するオンラインサービスである。(Wikipediaより)
まずアカウントを作る
https://home.openweathermap.org/users/sign_up
そしたら登録したメールアドレスにメールが来るはずなのでそこのリンクを踏んだら完了
自分のapiは右上で確認できる。
(取得してから10分から60分ほどかかるらしいです)
この間にAdvanced REST clientを入れといた。
apiでどんな情報が取れているかを確認出来る物だ。
けど、そもそもどうやってopenweathermapのapiを導入するのか?w
調べていくと、ajax
とXMLHttpRequest
が関わっているそうだ。
XHMHttpsRequestについて
https://ja.javascript.info/xmlhttprequest
https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&exclude={part}&appid={API key}
apiの取り方をそもそもわからないので他のサイトさんを参考に実際に叩いてみたい。
記事の通りにやってみたが叩けなかった。
今回はコマンドラインでディレクトリを作ってその中でやっていたが、エクスプローラーで開いたらなぜか起動した。
突き詰めたいが現状の時間的にも能力的にもコスパが悪いので次回にしたいと思う。
まずapiを叩けないとお話にならないので参考記事からそのまま使わせてもらう。
そこから分解しながら今回のアプリの使用に落とし込んでいく。
こちらの記事から引っ張らせてもらった
なんとかconsoleで出力することが出来た。
まずは単純にページを開いたら表示できるようにしたい。
スタート画面作成
htmlで書いて数値や画像だけdomで書き換えていく。
都市はラジオボタンを使う。
ラジオボタンについて
https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/radio
<body>
<main>
<div class="weather">
<div>
<div>
<h1>各地のお天気は?</h1>
</div>
<div>
<h2>都市の選択</h2>
</div>
<div>
<input type="radio" name="weather" value="選択肢1" checked>tokyo
<input type="radio" name="weather" value="選択肢2">選択肢2
<input type="radio" name="weather" value="選択肢3">選択肢3
<input type="submit" value="送信する">
</div>
<div>
<h3>現在の天気は</h3>
<p>気温<span id="tem"></span>℃</p>
<p>湿度<span id="hum"></span>%</p>
</div>
</div>
</div>
</main>
<script src="main.js"></script>
</body>
とりあえずhtmlはこんな感じ
(labelとか書いたほうがいいが余裕があったら取り組む)
立ち上げたページに表示させる
domでtem
とhum
を取得してこちらに東京の天気を入れたい。
const Tem = document.getElementById("tem");
Tem.innerHTML = temp
で入れる事が出来た。
しかし湿度は上記のサイトでは取得してないため自分で取ってくる必要がある。
公式サイトでパラメーターについて調べ、湿度はhumidity
らしいので、気温と同じようにとってきたら完了した。
次にアイコン画像を引っ張りたい。
アイコンも同じように探すとweather.icon
としてあった。
これの属性はどうするか。
imgタグでやってみる。
表示されなかった。デベロッパーツールで確認したらwidth/heightが0になってたのでcssを設定する。
そしたら枠だけ出来た。
恐らくアイコンを取得できてないと考えられる。
しかしエラーなども出ていない。
公式によると天気それぞれのidを取得し、それを使ってsrc属性を書かないといけないことが分かった。そしてそれは天気によって変更出来るようにしないといけない。
だからjsからsrc属性を書きたい。
天気のデータをconsoleに出力させるとundifined
になっている。
調べていくと原因がわかった。
通常ではあればテキストで取得するのでlet weather = obj.weather[0].description;
を使いまわすことが出来るがアイコンは画像のため使えないらしい。
だからlet icon = obj.weather[0].icon;
とするとconsoleに出力させることが出来た。
それを使ってdomでsrc属性を変更する。
Icon.setAttribute('src','http://openweathermap.org/img/w/'+icon+'.png')
で無事にアイコンを表示させることが出来た。
domによるsrc属性の変更
http://sarchitect.net/10364
ここまでのコード
let targetCityName = 'tokyo'
let appId = '~~~~~~~~~~~~~~~~~~~~~~~~'
const requestUrl = "https://api.openweathermap.org/data/2.5/weather?APPID=" + appId + "&lang=ja&units=metric&q=" + targetCityName + ",jp;"
let xhr = new XMLHttpRequest();
xhr.open('GET', requestUrl);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
ShowTodayWeather(xhr.responseText);
}
}
function ShowTodayWeather(response) {
let obj = JSON.parse(response)
let weather = obj.weather[0].description;
let city = obj.name;
let temp = obj.main.temp;
let humi = obj.main.humidity;
let icon = obj.weather[0].icon;
console.log("現在" + city + "の天気は" + weather);
console.log(`気温は ${temp} 度です`);
console.log(icon)
const Tem = document.getElementById("tem");
const Hum = document.getElementById("hum");
const Icon = document.getElementById("icon")
Tem.innerHTML = temp
Hum.innerHTML = humi
Icon.setAttribute('src','http://openweathermap.org/img/w/'+icon+'.png')
}
これで基本的なものを表示させることが出来た。
後は都市ごとに見れるようにする。
都市ごとに見れるようにする。
現状は東京を示しているのは一番最初のlet targetCityName = 'tokyo'
で定義しているからである。
だからここを変数にしたい。
(本当は座標で指定したいのだが、いっぺんにやるとキャパオーバーになるのでとりあえずと指名でやる)
今回は東京・京都・沖縄の3都市を扱う。
const selectCityName = ['tokyo','sapporo','okinawa']
let targetCityName = selectCityName[num]
としてラジオボタンでnumを指定してその都市の天気を表示させる。
まずどの都市にチェックが入ってるかをalertで表示させたい。
function clickbtn(weather) {
var elements = document.getElementsByName("weather")
var result;
for (var i = 0; i < elements.length; i++){
if (elements[i].checked) {
result = elements[i].value;
check()
break;
})
}
alert(result)
}
ここの記事を参考にして組んでみたがundefinede
が返ってきた。
clickbtn
の引数を空欄したら0が返ってきた。
しかし404エラー not foundと出てきた。
で、今まで最初に書いたものをcheck関数に入れてたが、そのままコピペしたら反映させることが出来た。
なぜ?
これでとりあえず完成である。
しかし都市を指定する前にアイコンを表示するところに灰色の線が出てきてしまう。
cssでどうにか消そうとしたが厳しそうなので、都市を指定してからimgタグを追加するようにする。
domで追加しようとした所
Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
が返ってきた。コイツ嫌い、、、、
けど、前も見た気がするかちゃんと理解したい。
恐らくうっかりミスの
iconimg.appendChild("Icon")
となっていたのが原因であると考えらえられる。
これを関数の中に入れると東京の後に京都を表示させると2つ目のアイコンが表れてしまうので、関数のそとに置く。
とりあえずこれで一通り完成である。
場所を都市名ではなく座標指定にする
恐らく2次元配列で可能だと考える。
const selectCityName2 = [
["kandamyouzin", "35.7020186", "139.7657056"],
["kyoutoUzi", 35.2926336, 136.633759]
];
var targetCityName2 = selectCityName2[result][1]
var targetCityName3 = selectCityName2[result][2]
const requestUrl = `https://api.openweathermap.org/data/2.5/weather?lat=${targetCityName2}&lon=${targetCityName3}&appid=${appId}&units=metric
座標でのapiの叩き方は公式参照
最後に&units=metric
を足した。
これを足さないと華氏になる。
これで問題ない
(けどqiitaテンプレートリテラルはダメなんですかね、、、)