Open8

React+leafletにおいてhtml/Canvasを使う

kage1020kage1020

Google Map並(もしくはそれ以上)のことが無料でできるleafletというライブラリがある.Reactで使う場合にはwrapperのreact-leafletを使うと簡単に導入できる.

これは公開されている地図ラスタ画像をレンダリングするものだが,基本的にDOMベースのレンダリングなのでマーカーや図形をたくさん置くと重くなる.そこでそれらをcanvasでレンダリングすることで軽くしようという魂胆で書き換えを試みる.

kage1020kage1020

マーカーをcanvasで表示

https://github.com/eJuke/Leaflet.Canvas-Markers

leaflet@1.8.0では一部クラスが削除されたため使えない


追記
npmからインストールすればできました.

https://www.npmjs.com/package/leaflet-canvas-marker

import { useMap } from 'react-leaflet'
import 'leaflet-canvas-marker'

const MyComponent = () => {
  useEffect(() => {
    const map = useMap()
    const layer = L.canvasIconLayer().addTo(map)
  })
}

leafletのissueでは機能改善とバグ修正しか受け付けておらず,サードパーティが対応するまで実装は無理っぽい.

https://github.com/Leaflet/Leaflet/issues/7321

Hi, great to hear that you find Leaflet useful!
However, this issue tracker is used for reporting bugs and discussing new features. For questions on using Leaflet, please use gis.stackexchange.com or stackoverflow.

こんにちは!Leafletを使ってくれて嬉しいぜ!
だけどここはバグを報告したり,新機能について議論したりする場所だからLeafletについての質問は stackexchange.com か stackoverflow を使ってくれよな!

対応が冷たい

react-leafletも対応が冷たい

https://github.com/PaulLeCam/react-leaflet/issues/869

Hi,
Please only use GitHub issues to report possible bugs in the library.
You can use the react-leaflet tag in StackOverflow for questions related to using it.

こんにちは,
ここはバグを報告するところだ.
使い方については StackOverflow で調べてくれ.

上記のコードをいろいろいじってみたが,技術力不足で画像がcanvasでレンダリングされず実装を断念.

代替案としてL.CircleMarkerを使えばcanvasで書ける.つまり,canvasに直接図形を書くだけ.

const marker = new L.CircleMarker([0, 0], { renderer: L.canvas() });
marker.addTo(map)
kage1020kage1020

Typescriptへの対応

知識がないため付け焼刃にはなるが,types/leaflet.d.tsで以下のように宣言することでエラーが消える.

import 'leaflet'

declare module 'leaflet' {
  export let canvasIconLayer: Function
}
kage1020kage1020

leaflet@1.8.0でエラーを吐かないleaflet.d.tsをとりあえず定義した.

leaflet.d.ts
import 'leaflet'
import * as geojson from 'geojson'

declare module 'leaflet' {
  export interface BBox {
    minX: number
    minY: number
    maxX: number
    maxY: number
    data: Marker<geojson.GeoJsonProperties>
  }

  export class CanvasIconLayer extends Layer {
    initialize(options: any): any
    setOptions(options: any): Function
    redraw(): void
    addMarkers(markers: Marker<geojson.GeoJsonProperties>[]): void
    addMarker(marker: Marker<geojson.GeoJsonProperties>): void
    addLayer(layer: Layer): void
    addLayers(layers: Layer[]): void
    removeLayer(layer: Layer): void
    removeMarker(marker: Marker<geojson.GeoJsonProperties>, redraw: boolean): void
    onAdd(map: Map): void
    onRemove(map: Map): void
    addTo(map: Map): this
    clearLayers(): void
    _addMarker(marker: Marker<geojson.GeoJsonProperties>, latlng: LatLngExpression, isDisplaying: boolean): BBox[]
    _drawMarker(marker: Marker<geojson.GeoJsonProperties>, pointPos: Point): void
    _drawImage(marker: Marker<geojson.GeoJsonProperties>, pointPos: Point): void
    _reset(): void
    _redraw(clear: boolean): void
    _initCanvas(): void
    addOnClickListener(listener: any): void
    addOnHoverListener(listener: any): void
    _executeListeners(event: any): void
  }

  export function canvasIconLayer(): CanvasIconLayer
}

kage1020kage1020

https://github.com/francoisromain/leaflet-markers-canvas

This is a complete rewrite of Leaflet.Canvas-Markers by Eugene Voynov. Thank you for the inspiration.

改良版が作られていた.使い方は本家と同じ.
Typescriptはissueに定義があがっていた.

https://github.com/francoisromain/leaflet-markers-canvas/issues/2

import 'leaflet';

declare module 'leaflet' {
  export class MarkersCanvas extends Layer {
    addTo(map:Map|LayerGroup):this;
    addMarker(marker:Marker):void;
    addMarkers(markers:Array<Marker>):void;
    getBounds():LatLngBounds;
    redraw():void;
    clear():void;
    removeMarker(marker:Marker):void;
  }
  function markersCanvas(): MarkersCanvas;
}