😍
OpenLayersでGeoTIFFを直接表示できるようになった!
OpenLayersがv6.7.0でついにGeoTIFFに対応しました。
めでたい。
https://openlayers.org/en/latest/examples/cog.html
https://openlayers.org/en/latest/examples/cog-math-multisource.html
https://openlayers.org/en/latest/examples/cog-math.html
読み込んで画像が表示されるまで少し時間がかかります。
衛星データは一般的にGeoTIFFという形式で配布されますが、そのデータをブラウザで表示するには、地図タイルと呼ばれる形式でpngを事前に出力しておきそれを呼び出すのが一般的でした。
もしくはアプリを経由して動的にpngを生成する方法もあります。
それが今回のOpenlayersバージョンアップでpngを事前に作ることなく直にGeoTIFFを呼び出せるようになりました。
GeoTIFFをベースマップ(OSM)と一緒に表示してみます。
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>sample cog</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.8.1/css/ol.css" type="text/css">
<style>
.map {
height: 600px;
width: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.8.1/build/ol.js"></script>
<script src="https://cdn.jsdelivr.net/npm/proj4@2.7.5/dist/proj4-src.min.js"></script>
</head>
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
const source = new ol.source.GeoTIFF({
sources: [
{
url: 'https://s3-us-west-2.amazonaws.com/planet-disaster-data/hurricane-harvey/SkySat_Freeport_s03_20170831T162740Z3.tif',
nodata: 0,
},
],
});
(async ()=>{
const view = await source.getView();
const code = view.projection.getCode();
console.log(code); // EPSG:32615
// https://www.npmjs.com/package/epsg-index などを利用してgeotiffごとに設定する
// このサンプルではepsg-indexにcdnがなかったのでdefを決め打ち
const proj4Def = '+proj=utm +zone=15 +datum=WGS84 +units=m +no_defs'
proj4.defs(
code,
proj4Def
);
ol.proj.proj4.register(proj4); // projを設定しておかないとベースマップがずれる
new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.WebGLTile({
source: source,
}),
],
view: source.getView(),
// わざわざコメントに"Get a promise for view properties based on the source. Use the result of this function as the `view` option in a map constructor."と書いてある
});
})();
</script>
</body>
</html>
- nodataを設定しないとデータの無い部分が黒く表示され、ベースマップが見えなくなります。
- GeoTIFFの投影方法がEPSG:4326やEPSG:3857以外だとデフォルトでproj設定がないため、ベースマップがずれてしまいます。viewからcodeを読み取り、epsg-indexなどを使って設定します。
注意点としては以下です。
- GeoTIFFのデータの型やサイズによってそれなりに動作が重い。
- sourceに合わせてviewを設定しないといけない[1]ため、任意のresolutionsやcodeを設定することができない。よってcodeが異なる複数のシーンを同じmap上に表示するようなことはできない様子。
というわけで大変便利なのですが、すべてを解決する銀の弾丸というわけではなく、やりたいことによっては従来の方法が引き続き有効となります。
-
軽くコードを読んだ範囲では、sourceにsource.getView()以外のviewを渡して投影法を切り替える方法が見つかりませんでした(無理やり渡すと動かなくなる)。 ↩︎
Discussion