Leaflet.PixiOverlayをReactで使ってみる その２


[Leaflet.PixiOverlayをReactで使ってみる その１ - Qiita](https://qiita.com/sugasaki/items/19e77872dc7474570593)
[Leaflet.PixiOverlayをReactで使ってみる その２ - Qiita](https://qiita.com/sugasaki/items/1974eb2716116f0defe2)

# はじめに 

LeafletとWebGLのライブラリであるPixi.jsの橋渡しをする「Leaflet.PixiOverlay」をReactでやってみます。


今回はマーカー1,000,000個の表示をやってみます。


![image](https://qiita-image-store.s3.amazonaws.com/0/49910/c3c71b22-c6f3-1984-d538-070bf1da2363.png)

拡大するとこんな沢山のマーカー。
![image](https://qiita-image-store.s3.amazonaws.com/0/49910/6871733d-09bc-ebc0-00a0-95f1007f6f4f.png)


## Git
今回作成した成果物は以下に置いてます。

[sugasaki/leaflet-pixioverlay-trial-react](https://github.com/sugasaki/leaflet-pixioverlay-trial-react)

デモは以下です。
[leaflet-pixioverlay-trial-react](https://sugasaki.github.io/leaflet-pixioverlay-trial-react/)


### JS版の説明
過去に書いたJS版は以下です。以下で説明した内容をReactに置き換えています。
その１：[Leaflet.PixiOverlay その１マーカーの表示 - Qiita](https://qiita.com/sugasaki/items/cc50fe09a98fcd219719#demo---draw-a-marker)
その２：[Leaflet.PixiOverlay その２many-markers - Qiita](https://qiita.com/sugasaki/items/9b6eb6ca70613b3d47e3)


## create-react-app

[Leaflet.PixiOverlayをReactで使ってみる その１ - Qiita](https://qiita.com/sugasaki/items/19e77872dc7474570593)で作ったプロジェクトに付け足していきます。


## many-markers

Leaflet.PixiOverlayのExample - many-markersをコンポーネントにしていきます。

[Leaflet.PixiOverlay/many-markers.html at master · manubb/Leaflet.PixiOverlay](https://github.com/manubb/Leaflet.PixiOverlay/blob/master/docs/many-markers.html)

### MarkerContainer.js

ParticleContainerの拡張用JSであるMarkerContainer.jsを以下から取得し、src/components/配下にコピーします。

[Leaflet.PixiOverlay/MarkerContainer.js at master · manubb/Leaflet.PixiOverlay](https://github.com/manubb/Leaflet.PixiOverlay/blob/master/docs/js/MarkerContainer.js)


### drawMarkerコンポーネントを作成
src/components/manyMarkers.js

```react:manyMarkers.js
import React, { Component } from 'react'

//leaflet
import 'leaflet/dist/leaflet.css';
import L from 'leaflet'

//pixi-overlay
import * as PIXI from "pixi.js";
import 'leaflet-pixi-overlay'

//ParticleContainerの拡張用JSをロードする
import './MarkerContainer'

export default class ManyMarker extends Component {
    state = {
        mapLayer: null
    }

    componentDidMount() {//ComponentがDOMツリーに追加された状態で呼ばれます。
        this.leafletInit();
    }

    componentDidUpdate() { //Componentが更新された後に呼ばれます。
        this.pixiOverlayInit(this.state.mapLayer);
    }


    getRandom(min, max) {
        return min + Math.random() * (max - min);
    }

    leafletInit() {
        var map = L.map('map-many-marker').setView([48.838565, 2.449264526367], 13);
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        }).addTo(map);

        //pixiOverlayでmapオブジェクトを参照できるようにstateにセット
        this.setState({ mapLayer: map });
    }


    pixiOverlayInit(mapLayer) {
        //マーカー最大個数
        var markersLength = 1000000;
        var getRandom = this.getRandom; //pixiOverlayからgetRandom関数にアクセスできるようにポインタ保存

        //Draw a marker
        var loader = new PIXI.loaders.Loader();
        loader.add('marker', './img/marker-icon.png'); //リソースにmarkerという名で'img/marker-icon.png'を登録
        loader.load(function (loader, resources) {  //リソース(marker)をロードする
            var texture = resources.marker.texture;

            var pixiContainer = new PIXI.Container();
            var innerContainer = new PIXI.particles.ParticleContainer(markersLength, { vertices: true });
            innerContainer.texture = texture;
            innerContainer.baseTexture = texture.baseTexture;
            innerContainer.anchor = { x: 0.5, y: 1 };
            pixiContainer.addChild(innerContainer);

            var firstDraw = true;
            var prevZoom;
            var initialScale;

            var pixiOverlay = L.pixiOverlay(function (utils) { //Leafletでズームやパンを行う度にコールされます。ドラッグ中はコールされない
                var zoom = utils.getMap().getZoom(); //Leafletのズーム率  ex. 0～18
                var container = utils.getContainer();
                var renderer = utils.getRenderer();
                var project = utils.latLngToLayerPoint; //Leaflet座標系LatLngからオーバーレイの座標系に投影されたL.Pointを返す。
                var scale = utils.getScale();
                var invScale = 1 / scale;

                if (firstDraw) {
                    var origin = project([(48.7 + 49) / 2, (2.2 + 2.8) / 2]);
                    innerContainer.x = origin.x;
                    innerContainer.y = origin.y;
                    initialScale = invScale / 8;
                    innerContainer.localScale = initialScale;
                    for (var i = 0; i < markersLength; i++) {
                        var x = getRandom(48.7, 49);
                        var y = getRandom(2.2, 2.8);
                        var coords = project([x, y]);
                        // our patched particleContainer accepts simple {x: ..., y: ...} objects as children:
                        innerContainer.addChild({
                            x: coords.x - origin.x,
                            y: coords.y - origin.y
                        });
                    }
                }

                if (firstDraw || prevZoom !== zoom) {
                    innerContainer.localScale = zoom < 8 ? 0.1 : initialScale;// 1 / scale;
                }

                firstDraw = false;
                prevZoom = zoom;
                renderer.render(container); //オーバーレイ上にあるオブジェクトの再描画する。
            }, pixiContainer);

            pixiOverlay.addTo(mapLayer);
        });
    }


    render() {
        return <div>
            <div id='map-many-marker'></div>
        </div>;
    }
}
```

### App.jsの編集

```react:App.js
import React, { Component } from 'react';
import './App.css';
import DrawMarker from './components/drawMarker';
import ManyMarker from './components/manyMarkers';

class App extends Component {
  componentDidMount() {
  }

  render() {
    return (
      <div className="App">
        <DrawMarker />
        <ManyMarker />
      </div>
    );
  }
}

export default App;
```



### 実行

`yarn start` で実行します。

leafletにマーカーが表示されれば成功


![image](https://qiita-image-store.s3.amazonaws.com/0/49910/c3c71b22-c6f3-1984-d538-070bf1da2363.png)

拡大するとこんな沢山のマーカー。
![image](https://qiita-image-store.s3.amazonaws.com/0/49910/6871733d-09bc-ebc0-00a0-95f1007f6f4f.png)