leafletのタイルURLをAsyncで設定したい
TileLayerのURLとして指定できる値は基本的にカーリーブラケットでタイル位置を表現できる形式のURLのみなので、IndexedDBにBlobをつっこんで非同期に値を設定することができない。ファイルが一個だけなら取得後にTileLayerを作ることでなんとでもなるが、タイル画像だとルールに基づいた下記のようなURLを渡す必要がある。
https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
Leaflet.functionaltilelayerみたいなものはあるが現行のleafletではうまくうごかなかった。そんなにコード量もないので、leafletのGridLayerをextendして
L.GridLayer.Functional = L.GridLayer.extend({
_tileFunction: null,
initialize: function (func, opts) {
this._tileFunction = func
L.GridLayer.prototype.initialize.call(this, null, opts)
},
createTile: function (tilePoint, done) {
const img = L.DomUtil.create('img', 'leaflet-tile')
const map = this._map
const crs = map.options.crs
const tileSize = this.options.tileSize
const zoom = tilePoint.z
const nwPoint = tilePoint.multiplyBy(tileSize)
const sePoint = nwPoint.add(new L.Point(tileSize, tileSize))
const nw = crs.project(map.unproject(nwPoint, zoom))
const se = crs.project(map.unproject(sePoint, zoom))
const view = {
bbox: [nw.x, se.y, se.x, nw.y].join(','),
width: tileSize,
height: tileSize,
zoom: zoom,
tile: {
row: this.options.tms ? this._tileNumBounds.max.y - tilePoint.y : tilePoint.y,
column: tilePoint.x
}
}
this._tileFunction(view)
.then(url => {
img.src = url
done(null, img)
})
return img
}
})
L.gridLayer.functional = function (gridFunction, options) {
return new L.GridLayer.Functional(gridFunction, options)
}
というものを作って適当にimportすれば
L.gridLayer.functional(async view => {
const url = 'http://example.com/tiles/{z}/{y}/{x}.jpg'.replace('{z}/{y}/{x}', `${view.zoom}/${view.tile.row}/${view.tile.column}`)
return await this.someGoodFunction(url)
}).addTo(this.map)
という感じで呼び出すことができる。