write ahead log

ロールフォワード用

React-Leafletで地図の代わりに画像を使う

さすがにそんな事できないだろと思って調べたらできるらしい。

座標系(CSR)にCRS.Simpleというのがあって、これを指定すると左下がx:0,y:0のシンプルな座標系になるっぽい。

あとはImageOverlayでレイヤーを足せばそれっぽくなる。

というか調べていたらVideoOverlayとかあるんだけど。何でもありだな。

Documentation - Leaflet - a JavaScript library for interactive maps

参考

先に参考資料を載せておく。

第1回 座標参照系(CRS)とは? | 航空・空間情報の朝日航洋株式会社

Leaflet で地図以外の画像を扱う #1 L.ImageOverlay | いきなり日曜大工

Leaflet.jsで画像を表示する – GUNMA GIS GEEK

ReactLeafletで画像を地図の代わりに使う方法 | 99 Blues

セットアップ

雑にサンプルアプリを作ってみる。

$ npx create-react-app leaflet-sample
$ cd leaflet-sample
$ npm install react-leaflet leaflet

サンプルコード

App.jsをそれっぽくしてみる。

画像ピッタリに表示領域を用意して、マーカーをいくつかおいてみた。

画像をドラッグで移動すると、画像サイズ以上は何もない領域になってしまうのでMapContainerのmaxBoundsで対処しとくといい感じになった。

import { CRS, LatLng, LatLngBounds } from 'leaflet';
import { MapContainer, ImageOverlay, Marker } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import L from 'leaflet';
L.Icon.Default.imagePath = 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/';

function App() {
  const imgWidth = 816;
  const imgHeight = 756;

  const translateX = (x) => x;
  const translateY = (y) => imgHeight - y;

  return (
    <div style={{margin: 150}}>
      <MapContainer
        center={new LatLng(imgHeight/2, imgWidth/2)}
        zoom={0}
        crs={CRS.Simple}
        style={{ width: imgWidth, height: imgHeight}}
        maxBounds={[[0, 0], [imgHeight, imgWidth]]}
      >
        <ImageOverlay
          url={'japan_map.png'}
          bounds={new LatLngBounds([[0, 0], [imgHeight, imgWidth]])}
        />
        <Marker position={[0, 0]} />
        <Marker position={[translateY(400), translateX(520)]} />
        <Marker position={[imgHeight/2, imgWidth/2]} />
        <Marker position={[imgHeight-20, imgWidth-20]} />
      </MapContainer>
    </div>
  );
}

export default App;

フリーの日本地図イラストを入れてみた。