Leaflet タイルの表示まわりを改善
地図タイルの気になるところ
今回は前からずっと気になっていたタイル表示まわりについてです。
タイルのヒビ
Leaflet を使っている方は気になりませんか、タイルのヒビ、もといスキマ。
Leaflet の GitHub でもこの件について繰り返し Issue(例えば #3575, #5551) に上がってはいるものの、Leaflet 側の問題ではないとか、webkit が(タイル)画像の端にアンチエイリアスをしているからだとかで、どうにかしたいなら現時点では自分で対策をする必要があるようです。
解決方法というか代替案として Leaflet.TileLayer.NoGap というタイルを Canvas に並べたレイヤーを使うものが用意されています。自分はまだこれを試したことはありませんが、地図作りが最後までいってもこの問題が解決しないようならこれを使うことを検討していました。
地図の背景色
気になっていることはもうひとつありました。地図コンテナの背景色が黒なので、地図をズームさせたり動かすとタイル読み込み待ちの間に見えちゃう黒の印象がきつく、せっかくの Leaflet のズームアニメーションがもったいない。
背景色を黒にしているのは地図全体の四辺が黒だからなんですが、タイル部分の背景をもう少し地図っぽい色味(ってなんだろう)にできたら印象が柔らかくなったり、ヒビも目立たなくなるのだろうか。
・・という感じでいつかは解決したいなと時々思い出しては試行錯誤していたんですが、先日この両方の悩みを解消できる(ごまかすともいう)対処方法を見出すことができました。
Google 先生に聞いてみた
ある日、そういえば Google 先生はタイルの背景をどうしているんだろうと思って Google Maps を見に行きました。地図をがーっと動かしてタイルの読み込みが追い付かない状況を作り出し、見える背景がどうなっているか観察してみます。すると格子模様らしきものが見えるので、ブラウザの開発ツールで調べてみるとこんな感じの透過 PNG のグリッドでした。
それまで背景色をどうにかすることばかり考えていたので画像を使う発想はありませんでした。画像を使うのがアリならずばり地図画像そのものを使って色の補完ができるのでは・・・?
その後地図の元画像から低解像度の画像を作り、ときに引き延ばしたりして背景に入れ込む方向でいろいろ試したところ、低解像度の地図画像をまるごと L.ImageOverlay でタイルの背景にいれるというやり方に辿り着きました。
低解像度の画像を背景に入れる
タイルの元画像を縮小して 5% サイズのサムネイルみたいな画像を作ります。
これをタイルレイヤーの後ろに、地図コンテナに指定している領域と同じ範囲になるように L.ImageOverlay ではりつけます。これ、L.Map の maxBounds に指定する L.LatLngBounds そのままではうまくいかないんですよね。ここで L.ImageOverlay の回 にやった画像配置の実験が役に立つとは。
// 背景に貼り込む用のペイン
map.createPane('background');
L.imageOverlay('images/hokusai217x150.jpg', L.latLngBounds([
// タイルレイヤーに重なるように配置
map.unproject([0, image_height], maxZoom),
map.unproject([image_width, 0], maxZoom)
]), {
pane: 'background'
}).addTo(map);
/* タイルレイヤーより後ろ */
.leaflet-background-pane {
z-index: 100;
}
これで貼り込んだミニ画像はタイルレイヤーと一緒にズームされ、拡大縮小されたものがタイルレイヤーの地図と同じスケールで後ろに来ていることになります。
引き伸ばした荒い画像でもスキマの色を補完するには十分なようで、ヒビは見えなくなりタイル読み込み中に見えてる部分もそんなに気にならなくなりました。
元の背景なしバージョンはこちら。
ミニ画像だけだとこんな感じです。もっと小さい画像でも大丈夫かも。
BotW 地図にもさっそく実装。いい感じです。
根本的解決ではなく見た目対策となりましたが今のところはこれで十分です。タイルのヒビ問題が Leaflet 側で解決されてもこの背景は入れたい。Google 先生にいいヒントをもらえました。
2019/9/6 BotW デモ地図の地名ラベルのフォントサイズがおかしかったのを修正しました。