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でやってみます。

今回はマーカーの表示までやってみます。

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/4236d06a-9773-d2eb-1910-dac6cd4d0084.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

reactの雛形を作成

```
create-react-app leaflet-pixioverlay-trial-react
```

## ライブラリインストール

以下のライブラリを入れます
* leaflet
* leaflet-pixi-overlay 
* pixi.js

```shell-session
npm i leaflet leaflet-pixi-overlay pixi.js --save
```

## Leafletの表示

まずはLeafletを表示させます。

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

```react:drawMarker.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'

export default class DrawMarker extends Component {
    state = {
    }

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

    leafletInit() {
        var map = L.map('map').setView([51.505, -0.09], 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);
    }
    
    render() {
        return <div id="mapUI">
            <div id='map'></div>
        </div>;
    }
}    
```

### App.jsの編集

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

class App extends Component {
  componentDidMount() {
  }

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

export default App;
```


### index.css

```css
html, body {
    margin: 10px;
    padding: 0;
    height: 100%;
    width: 100%;
}

#root {
    width: inherit;
    height: inherit;
}


.leaflet-container {
    width: 600px;
    height: 300px;
    margin: 10px;
}
```

### imgフォルダの作成

public/imgフォルダを作成
img配下にmarker-icon.pngを配置します。
marker-icon.pngは以下にあります。
[Leaflet.PixiOverlay/docs/img at master · manubb/Leaflet.PixiOverlay](https://github.com/manubb/Leaflet.PixiOverlay/tree/master/docs/img)

配置後は以下のようになります。
![image](https://qiita-image-store.s3.amazonaws.com/0/49910/ed1077dd-7ebf-18f2-fd07-7b6a230a0a91.png)


### 実行

`yarn start` で実行します。

leafletが表示されれば成功

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/ebc8d266-36c7-2d84-df92-9f105fdb75ff.png)


## pixiOverlayでマーカーを表示

### pixiOverlayの処理を追加
src/components/drawMarker.jsにpixiOverlayの処理を追加します。

```react:drawMarker.js
export default class DrawMarker extends Component {
    state = {
        mapLayer: null
    }

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

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

    leafletInit() {
        var map = L.map('map').setView([51.505, -0.09], 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) {
        //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 markerTexture = resources.marker.texture;
            var markerLatLng = [51.5, -0.09];
            var marker = new PIXI.Sprite(markerTexture);
            marker.anchor.set(0.5, 1); //原点をX:中央 Y:下　に設定

            var pixiContainer = new PIXI.Container();
            pixiContainer.addChild(marker);

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

                if (firstDraw) {
                    var markerCoords = project(markerLatLng); //Leaflet座標系LatLngからオーバーレイの座標系に投影されたL.Pointを返す。
                    marker.x = markerCoords.x; //ex. markerLatLng[0] 51.5 → 65503.232
                    marker.y = markerCoords.y; //ex. markerLatLng[1] -0.09 → 43589.11367487424
                }

                if (firstDraw || prevZoom !== zoom) { //Leafletのズーム率  ex. 0～18
                    marker.scale.set(1 / scale); //マーカーのサイズを常に倍率１にする。
                }

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

            pixiOverlay.addTo(mapLayer);
        });
    }

    render() {
        return <div id="mapUI">
            <div id='map'></div>
        </div>;
    }
}
```


### 実行

`yarn start` で実行します。

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

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/4236d06a-9773-d2eb-1910-dac6cd4d0084.png)