これまでこのサイトではJavascriptライブラリのLeafletを使ってGISデータの一種であるラスターデータを地図上に表示させる方法を解説してきました。これまでは、ラスター表示はすべて静止画でしたが、この記事では複数のラスターデータをアニメーション表示する方法について解説していきたいと思います。
1. はじめに
この記事では、Leafletを使って複数のラスターデータをアニメーション表示する方法を解説します。この記事ではラスターデータとしてGeoTIFFデータを使います。ASCII-Gridデータの方がテキスト形式なので数値を確認しやすいですが、Leaflet上では表示に制約があるので、GeoTIFFデータを用います。GeoTIFFデータのもととなったデータは気象庁速報版解析雨量GPVです。
降雨量等の時間的に変化があるデータはアニメーション表示するとその時系列変化を把握しやすくなります。アニメーション表示をする機能はLeaflet自体にも備わっているようですが、ここではJavascriptを用いて独自に実装しています。
2. アニメーション表示の方法
「はじめに」でも書いた通り、アニメーション表示をする機能はLeaflet自体にも備わっているようですが、ここではJavascriptを用いて独自に実装しています。
ここでのアニメーション表示は、パラパラ・アニメのように単一のラスターデータ表示を一定時間間隔で表示することによって実現しています。単一のラスターデータを表示する方法については他の記事で述べている書いている通りです。それをここでは、JavascriptのsetTimeout関数を使って一定時間間隔で表示しています。
アニメーションを停止するときは、clearTimeout関数を実行します。
3. ソースコードの解説
LeafletはJavascriptのライブラリですので、基本的にhtml中にJavascriptのコードを埋め込む形で記述します。下記にLeafletを使ってGeoTIFFファイルのアニメーションを地図上に表示するためのサンプルコード「simple_geotiff_animation.html」を示します。
4~7行目は、Leafletを動かすためのリファレンスリンクです。特に6、7行目はGeoTIFFファイルを表示するためのものですので、この部分をなくすと背景地図は表示されてもGeoTIFFファイルが表示されなくなります。
17行目のdiv要素の場所にLeafletによる地図が表示しされます。18から24行目のdiv要素でアニメーションをコントロールするボタン(Start, Stop)等を配置しています。
27~30行目で背景地図の中心座標(この場合、北緯37N 東経137)と地図の拡大率を指定しています。
33~36行目は背景地図を表示させるコードです。
38から45行目で表示する一連のGeoTIFFファイルのパスを配列geotiff_filesに格納しています。
65~78行目のshow_geotiff()関数で、この関数の引数となっているGeoTIFFファイルを表示します。この関数は49行目のアニメーション表示を実行するための関数play()の中で呼び出されています。
49~59行目がアニメーションを実行する関数で、「Start」ボタンがクリックされたとき実行されます。50行目でform要素のinputボックスの文字列に表示するGeoTIFFファイルのパスを表示します。そして、51~58行目で配列geotiff_filesに格納されたGeoTIFFファイルをsetTimeout関数によって1,000ミリ秒ごとに繰り返し表示します。繰り返しの制御はコールバック関数よって行われます。配列の最後の要素を表示し終わったら、先頭の要素に戻ります。
61行目は「Stop」ボタンがクリックされたときに実行される関数stop()です。setTimeout関数で実行された繰り返し実行をclearTimeout関数を使ってキャンセルしています。
Leafletのサンプルコード「simple_geotiff_animation.html」
<html lang="ja"> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJLQ==" crossorigin=""/> <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js" integrity="sha512-/Nsx9X4HebavoBvEBuyp3I7od5tA0UzAxs+j83KgC8PU0kgB4XiK4Lfe4y4cgBtaRJQEIFCW+oC506aPT2L1zw==" crossorigin=""></script> <script src="https://unpkg.com/georaster"></script> <script src="https://unpkg.com/georaster-layer-for-leaflet"></script> <style> #mapid { width: 100%; height: 90%; } </style> </head> <body> <div id="mapid"></div> <div> <form name="time_control"> <input type="button" value="Start"> <input type="button" value="Stop"><br> <input type="text" name="file_name" size="100" value=""> </form> </div> <script type="text/javascript"> let map = L.map('mapid', { center: [37.0, 137.], zoom: 5.5, }); let tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>', }); tileLayer.addTo(map); let geotiff_files = []; geotiff_files.push("./geotiff/Z__C_RJTD_20190630200000_SRF_GPV_Ggis1km_Prr60lv_Aper10min_ANAL_grib2.tif"); geotiff_files.push("./geotiff/Z__C_RJTD_20190630201000_SRF_GPV_Ggis1km_Prr60lv_Aper10min_ANAL_grib2.tif"); geotiff_files.push("./geotiff/Z__C_RJTD_20190630202000_SRF_GPV_Ggis1km_Prr60lv_Aper10min_ANAL_grib2.tif"); geotiff_files.push("./geotiff/Z__C_RJTD_20190630203000_SRF_GPV_Ggis1km_Prr60lv_Aper10min_ANAL_grib2.tif"); geotiff_files.push("./geotiff/Z__C_RJTD_20190630204000_SRF_GPV_Ggis1km_Prr60lv_Aper10min_ANAL_grib2.tif"); geotiff_files.push("./geotiff/Z__C_RJTD_20190630205000_SRF_GPV_Ggis1km_Prr60lv_Aper10min_ANAL_grib2.tif"); geotiff_files.push("./geotiff/Z__C_RJTD_20190630210000_SRF_GPV_Ggis1km_Prr60lv_Aper10min_ANAL_grib2.tif"); let i = 0; let play_motion; function play() { document.time_control.file_name.value = geotiff_files[i]; show_geotiff(geotiff_files[i]); if (i < geotiff_files.length - 1) { i++; play_motion = setTimeout("play()",1000); } else { i = 0; play_motion = setTimeout("play()",1000); } } function stop() { clearTimeout(play_motion); } function show_geotiff(geotiff_file_path) { fetch(geotiff_file_path) .then(response => response.arrayBuffer()) .then(arrayBuffer => { parseGeoraster(arrayBuffer).then(georaster => { let layer = new GeoRasterLayer({ georaster: georaster, opacity: 0.7 }); layer.addTo(map); map.fitBounds(layer.getBounds()); }); }); } </script> </body> </html>
4. ソースコードの動かし方
この記事で使うソースコードは、下記のリンクからダウンロードすることができます。だだ、その中にあるhtmlのソースコード「simple_geotiff_animation.html」をブラウザから開くと背景の日本地図しか表示されません。
GeoTIFFファイルを表示しようと思ったら、simple_geotiff_animation.htmlとGeoTIFFファイルの両方をウェブサーバー上の同一ディレクトリに配置する必要があります。
ウェブサーバーを用意するのはなかなか大変だと思いますので、ここで配布するサンプルプログラムではnode.jsというサーバサイドJavascriptのプラットフォームを用いています。よって、このサンプルプログラムを動かす前に、node.jsをインストールする必要があります。
ダウンロードしたzipファイルを解凍すると、package.jsonを始めとする3つのファイルとGeoTIFFファイルが格納されたフォルダが現れます。そのディレクトリ上でコマンドプロンプトまたはターミナル画面から下記のコマンドを打ち込みます。
npm install npm start
1行目のコマンドを打ち込むと、node.jsの必要なモジュールがインストールされます。これには数分かかると思います。そして、2行目のコマンドを打ち込むと、下図のようにウィンドウに日本地図が表示されます。そして、ウィンドウ下部の「Start」ボタンをクリックするとアニメーションが始まります。それと同時に、ウィンドウ最下部のテキストボックスに地図上に表示されているGeoTIFFファイルのパスが表示されます。
「Stop」ボタンをクリックするとするとアニメーションが止まります。
5. まとめ
この記事では、Javascriptのライブラリ「Leaflet」で複数のラスターデータをアニメーション表示させる方法を解説しました。
Leaflet自体にもアニメーション表示を行う機能はあるようですが、ここではJavascriptを使って実装しました。
ここで解説した方法では、アニメーション表示はパラパラ・アニメのように複数のラスターファイルを1枚ずつ一定時間間隔で地図上に表示することによって実現しています。
複数のラスターファイルの1枚ずつ一定時間間隔の表示はJavascriptのsetTimeout関数を使って実現しています。アニメーションを停止するときは、clearTimeout関数を使っています。
以上、最後まで読んでいただきありがとうございました。