React+leafletにおいてhtml/Canvasを使う
Google Map並(もしくはそれ以上)のことが無料でできるleafletというライブラリがある.Reactで使う場合にはwrapperのreact-leafletを使うと簡単に導入できる.
これは公開されている地図ラスタ画像をレンダリングするものだが,基本的にDOMベースのレンダリングなのでマーカーや図形をたくさん置くと重くなる.そこでそれらをcanvasでレンダリングすることで軽くしようという魂胆で書き換えを試みる.
地図をcanvasで表示
pure.jsでは動作することを確認したが,Reactでインポートする方法がわからない.
マーカーをcanvasで表示
leaflet@1.8.0では一部クラスが削除されたため使えない
追記
npmからインストールすればできました.
import { useMap } from 'react-leaflet'
import 'leaflet-canvas-marker'
const MyComponent = () => {
useEffect(() => {
const map = useMap()
const layer = L.canvasIconLayer().addTo(map)
})
}
leafletのissueでは機能改善とバグ修正しか受け付けておらず,サードパーティが対応するまで実装は無理っぽい.
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も対応が冷たい
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)
Typescriptへの対応
知識がないため付け焼刃にはなるが,types/leaflet.d.ts
で以下のように宣言することでエラーが消える.
import 'leaflet'
declare module 'leaflet' {
export let canvasIconLayer: Function
}
leaflet@1.8.0でエラーを吐かない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
}
↑このパッケージではマーカーに個別のイベントをつけられないことに気が付いたので,代替案を探索中.
This is a complete rewrite of Leaflet.Canvas-Markers by Eugene Voynov. Thank you for the inspiration.
改良版が作られていた.使い方は本家と同じ.
Typescriptはissueに定義があがっていた.
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;
}
react-leaflet v2に限ってはwrapperを作っている人がいた.