Leaflet.PixiOverlay その１マーカーの表示


その１：[Leaflet.PixiOverlay その１マーカーの表示 - Qiita](https://qiita.com/sugasaki/items/cc50fe09a98fcd219719#demo---draw-a-marker)
その２：[Leaflet.PixiOverlay その２many-markers - Qiita](https://qiita.com/sugasaki/items/9b6eb6ca70613b3d47e3)

コードは以下に保存しました。
[sugasaki/Leaflet.PixiOverlay.Trial](https://github.com/sugasaki/Leaflet.PixiOverlay.Trial)


# はじめに

LeafletとWebGLのライブラリであるPixi.jsの橋渡しをするLeaflet.PixiOverlayを使って、マーカーの表示をやってみます。


[Leaflet.PixiOverlay](https://github.com/manubb/Leaflet.PixiOverlay)

Leaflet.PixiOverlayは[teralytics/Leaflet.D3SvgOverlay: Leaflet Plugin: D3 SVG Overlay](https://github.com/teralytics/Leaflet.D3SvgOverlay)からインスパイアされたプロジェクトのようです。

すごく沢山のマーカーを置いたり、ポリゴンを置いてもサクサク動作します。

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/8d27446f-d05a-4eb5-d5e8-06a82e678b53.png)
拡大するとこんな沢山のマーカーでした。
![image](https://qiita-image-store.s3.amazonaws.com/0/49910/a921bf66-6dbf-b434-a6d2-198b198ad9a1.png)


# 環境作成
以下で作成したプロジェクトファイルをベースにします。
[Leaflet はじめの一歩 - Qiita](https://qiita.com/sugasaki/items/3ff1662652305c657577)


## pixi-js インストール

webGLのレンダリングにPixiJSを使っているので、まずはpixi-js インストール

`> npm install pixi.js --save`

[PixiJS v4](http://www.pixijs.com/)
[pixijs/pixi.js: The HTML5 Creation Engine: Create beautiful digital content with the fastest, most flexible 2D WebGL renderer.](https://github.com/pixijs/pixi.js)

Index.htmlにスクリプトタグを追加

```html
<script src="./node_modules/pixi.js/dist/pixi.min.js"></script>
```

## leaflet-pixi-overlay インストール

leaflet-pixi-overlay インストール

`> npm install leaflet-pixi-overlay --save`

Index.htmlにスクリプトタグを追加

```html
<script src="./node_modules/leaflet-pixi-overlay/L.PixiOverlay.min.js"></script>
```

# Examples - Draw a marker

以下のGithubに書いてあるExamples→Draw a markerをやってみます。
[manubb/Leaflet.PixiOverlay: Bring Pixi.js power to Leaflet maps](https://github.com/manubb/Leaflet.PixiOverlay)


## index.html

index.htmlを以下の内容にしました。

```html:index.html
<html>
<head>
    <title>Leaflet</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="./node_modules/leaflet/dist/leaflet.css" />
</head>

<body style="height: 100%; margin: 0; overflow: hidden;">
    <div id="map" style="height: 100%; width: 100%;"></div>
</body>

<script src="./node_modules/leaflet/dist/leaflet.js"></script>
<script src="./node_modules/pixi.js/dist/pixi.min.js"></script>
<script src="./node_modules/leaflet-pixi-overlay/L.PixiOverlay.min.js"></script>
<script src="./js/index.js"></script>
</html>
```


## スクリプト用のJSファイルを追加

スクリプト用のJSファイル（index.js）を追加します。
ファイルにDraw a markerの内容を打ち込みます。

```js:index.js
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);

//Draw a marker
var loader = new PIXI.loaders.Loader();
loader.add('marker', 'img/marker-icon.png');
loader.load(function (loader, resources) {
    var markerTexture = resources.marker.texture;
    var markerLatLng = [51.5, -0.09];
    var marker = new PIXI.Sprite(markerTexture);
    marker.anchor.set(0.5, 1);

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

    var firstDraw = true;
    var prevZoom;

    var pixiOverlay = L.pixiOverlay(function (utils) {
        var zoom = utils.getMap().getZoom();
        var container = utils.getContainer();
        var renderer = utils.getRenderer();
        var project = utils.latLngToLayerPoint;
        var scale = utils.getScale();

        if (firstDraw) {
            var markerCoords = project(markerLatLng);
            marker.x = markerCoords.x;
            marker.y = markerCoords.y;
        }

        if (firstDraw || prevZoom !== zoom) {
            marker.scale.set(1 / scale);
        }

        firstDraw = false;
        prevZoom = zoom;
        renderer.render(container);
    }, pixiContainer);
    
    pixiOverlay.addTo(map);
});
```

## 結果

マーカーが表示されました。

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/2108ddc4-59f3-b3fb-84d5-825b24a8dc59.png)

Leafletのマーカー機能よりもだいぶコード量が増えてますが、WebGLで描画するためにやむなしといったところでしょうか。


## コード解説

### loader

> var loader = new PIXI.loaders.Loader();
> loader.add('marker', 'img/marker-icon.png');
> loader.load(function (loader, resources) { 

loaderはコードみればだいたい分かりますが、img/marker-icon.png　の読み込みが完了したら処理を行うという感じ

[公式ヘルプ#loaders](http://pixijs.download/dev/docs/PIXI.loaders.html)

> This namespace contains APIs which extends the resource-loader module for loading assets, data, and other resources dynamically.
> この名前空間（PIXI.loaders）は、assets、data、その他のリソースを動的にロードするための、resource-loaderモジュールを拡張するAPIが含まれています。


### texture
> var markerTexture = resources.marker.texture;
> var markerLatLng = [51.5, -0.09];
> var marker = new PIXI.Sprite(markerTexture);

markerTextureへ代入、緯度経度を設定、Spriteを作成する。

### anchor

> marker.anchor.set(0.5, 1);

anchorは[公式ヘルプ#anchor](http://pixijs.download/dev/docs/PIXI.Sprite.html#anchor)を見ると原点の場所のようです。

> The anchor sets the origin point of the texture. The default is 0,0 this means the texture's origin is the top left Setting the anchor to 0.5,0.5 means the texture's origin is centered Setting the anchor to 1,1 would mean the texture's origin point will be the bottom right corner
> anchorはテクスチャの原点を設定します。 デフォルトは0,0です。これは、テクスチャの原点が左上であることを意味します。
> アンカーを0.5, 0.5に設定すると、テクスチャの原点がセンタリングされることを意味します。アンカーを1,1に設定すると、テクスチャの原点が右下になります。

という事で、marker.anchor.set(0.5, 1) の場合には原点が、X:中央 Y:下　であり、マーカー<img src='https://qiita-image-store.s3.amazonaws.com/0/49910/2a332711-280f-710d-dbe8-b1198239b183.png' height='20x'> の尖ったところを原点として設定しているということになります。

### Container

[公式ヘルプ#Container](http://pixijs.download/dev/docs/PIXI.Container.html)

> A Container represents a collection of display objects. It is the base class of all display objects that act as a container for other objects.
> コンテナは、表示オブジェクトのコレクションを表します。 これは他のオブジェクトのコンテナとして機能するすべての表示オブジェクトの基本クラスです。

コンテナを作って、表示したいオブジェクトをコンテナに突っ込めば表示してくれるようです。


### フラグ類

```js
    var firstDraw = true;
    var prevZoom;
```

### L.pixiOverlay

以下の構文でoverlayレイヤーを作成します。

```js
    //第1引数に処理関数を、第２引数にPIXIのコンテナを指定します。
    var pixiOverlay = L.pixiOverlay(function(utils) {
        // your drawing code here
    }, new PIXI.Container());
```

第1引数に渡した処理関数は、Leafletでズームやパンを行う度にコールされます。
ドラッグ中はコールされないです。
よって、


１回目の処理（初回処理）では、latLngToLayerPointでオーバーレイ座標系の位置を算出し、スケールをセットしている。

マーカーのサイズを常に倍率１にする為に、
Leafletのズーム率が変われば、markerスケールをセットしなおしている。以下の部分。

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

最後にフラグを変更し、ズーム率を保存している。

render()でオーバーレイ上にあるオブジェクトの再描画を行っている。
`renderer.render(container);`
再描画を行わない場合、パンした場合に座標が追従しない。（オーバーレイ座標系の位置が変わらない）


#### latLngToLayerPoint(latLng, zoom?) 
> returns L.Point projected from L.LatLng in the coordinate system of the overlay.
Leaflet座標系LatLngからオーバーレイの座標系に投影されたL.Pointを返します。

var markerCoords = project(markerLatLng); の場合、
markerLatLng = [51.5, -0.09] → markerCoords[ x: 65503.232, y: 43589.11367487424]



### pixiOverlay.addTo(map);

pixiOverlayの機能でLeaflet Mapに追加します。
map.addLayer(this);をラップしています。

[manubb/Leaflet\.PixiOverlay: Bring Pixi\.js power to Leaflet maps](https://github.com/manubb/Leaflet.PixiOverlay)



# おわりに
コード解説は以上です。
コードは以下に保存しました。
[sugasaki/Leaflet.PixiOverlay.Trial](https://github.com/sugasaki/Leaflet.PixiOverlay.Trial)


このやり方がベスト解というわけではなく、Pixiを使って他にもやり方がありそうです。

冒頭の沢山のマーカーを表示するサンプル[many-markers.html](https://github.com/manubb/Leaflet.PixiOverlay/blob/master/docs/many-markers.html)ではまた違ったやり方がなされています。

次回はmany-markers.htmlについて掘り下げていきます。

その２：[Leaflet.PixiOverlay その２many-markers - Qiita](https://qiita.com/sugasaki/items/9b6eb6ca70613b3d47e3)