LeafletでGeoPackageを読み込んで表示してみた

![](https://day-journal.com/memo/images/try-054_01.gif)

<br>

![](https://day-journal.com/memo/images/try-054_00.png)

<br>

この記事は、「[MIERUNE Advent Calendar 2020](https://qiita.com/advent-calendar/2020/mierune)」の17日目の記事です。

### LeafletでGeoPackageを読み込んで表示してみました :tada:  

QGISでよく利用するGeoPackageですが、実はLeafletで読み込んで表示することもできたりします :bulb: 

LeafletでGeoPackageを読み込んで表示する場合は、[GeoPackage JS](https://github.com/ngageoint/geopackage-js)を利用した[leaflet-geopackage](https://github.com/ngageoint/geopackage-js/tree/master/leaflet)で実現できます。

<br>

### 利用データ

今回は、[QGIS](https://qgis.org/ja/site/index.html)の[QuickOSM](https://plugins.qgis.org/plugins/QuickOSM)プラグインでOpenStreetMapのshopデータを5000件程度準備してGeoPackageで保存しました。

![](https://day-journal.com/memo/images/try-054_02.png)

<br>

## Leaflet
次に、Leafletで構築していきます。
leaflet-geopackageは、webpackに対応していないみたいなので今回はプレーンな構成で構築してみます。

<br>

全体構成

![画像](https://day-journal.com/memo/images/try-054_03.png)

#### index.html

```html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Leaflet Sample</title>
        <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
        <link href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" rel="stylesheet" />

        <script src="https://unpkg.com/@ngageoint/leaflet-geopackage@3.0.3/dist/leaflet-geopackage.min.js"></script>

        <link href="css/style.css" rel="stylesheet" />
    </head>
    <body>
        <div id="map"></div>
        <script src="js/app.js"></script>
    </body>
</html>
```

<br>

LeafletをCDNで読み込みます。

```html
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" rel="stylesheet" />
```

<br>

leaflet-geopackageをCDNで読み込みます。

```html
<script src="https://unpkg.com/@ngageoint/leaflet-geopackage@3.0.3/dist/leaflet-geopackage.min.js"></script>
```

<br>

/css

#### style.css

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

#map {
    z-index: 0;
    height: 100%;
}
```

<br>

/js

#### app.js

```javascript
// MIERUNE Streets読み込み
const m_streets = new L.tileLayer(
    'https://api.maptiler.com/maps/jp-mierune-streets/256/{z}/{x}/{y}.png?key=[APIキー]',
    {
        attribution:
            '<a href="https://maptiler.jp/" target="_blank">&copy; MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>',
    }
);

// MIERUNE Gray読み込み
const m_gray = new L.tileLayer(
    'https://api.maptiler.com/maps/jp-mierune-gray/256/{z}/{x}/{y}.png?key=[APIキー]',
    {
        attribution:
            '<a href="https://maptiler.jp/" target="_blank">&copy; MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>',
    }
);

// MAP読み込み
const map = L.map('map', {
    center: [43.3179, 142.6308],
    zoom: 8,
    zoomControl: true,
    layers: [m_streets],
});

//背景レイヤ
const Map_BaseLayer = {
    'MIERUNE Streets': m_streets,
    'MIERUNE Gray': m_gray,
};

//レイヤ設定
L.control.layers(Map_BaseLayer, null).addTo(map);

//スケール設定
L.control
    .scale({
        imperial: false,
        maxWidth: 300,
    })
    .addTo(map);

// GeoPackage読み込み
L.geoPackageFeatureLayer([], {
    // GeoPackageファイル指定
    geoPackageUrl: './data/shop.gpkg',
    // レイヤ名指定
    layerName: 'shop',
    pointToLayer: function (feature, layer) {
        return L.circleMarker(layer, {
            color: '#014c86',
            radius: 3,
            weight: 1,
            opacity: 0.7,
            fill: true,
            fillColor: '#014c86',
            fillOpacity: 0.7
        });
    },
    onEachFeature: function (feature, layer) {
        const field =
            `fid: ${feature.properties.fid} <br>
            full_id: ${feature.properties.full_id} <br>
            osm_id: ${feature.properties.osm_id} <br>
            name: ${feature.properties.name} <br>
            shop: ${feature.properties.shop}`;
        layer.bindPopup(field);
    }
}).addTo(map);
```

<br>

GeoPackageを読み込んで表示します。

```javascript
// GeoPackage読み込み
L.geoPackageFeatureLayer([], {
    // GeoPackageファイル指定
    geoPackageUrl: './data/shop.gpkg',
    // レイヤ名指定
    layerName: 'shop',
    pointToLayer: function (feature, layer) {
        return L.circleMarker(layer, {
            color: '#014c86',
            radius: 3,
            weight: 1,
            opacity: 0.7,
            fill: true,
            fillColor: '#014c86',
            fillOpacity: 0.7
        });
    },
    onEachFeature: function (feature, layer) {
        const field =
            `fid: ${feature.properties.fid} <br>
            full_id: ${feature.properties.full_id} <br>
            osm_id: ${feature.properties.osm_id} <br>
            name: ${feature.properties.name} <br>
            shop: ${feature.properties.shop}`;
        layer.bindPopup(field);
    }
}).addTo(map);
```

<br>
<br>

簡易ローカルサーバーで確認してみます。

```shell
python -m http.server 8000
```

<br>

表示されました :grinning: 

![画像](https://day-journal.com/memo/images/try-054_01.gif)  

<br>

#### LeafletでGeoPackageを読み込んで表示ができました :thumbsup: 

LeafletでもGeoPackageを手軽に読み込むことができます :bulb: 
Webアプリケーションでも読めたりするので、GeoPackage好きなかたはゼヒお試しください！

今後、webpackで構築できるようにしたり、OpenLayersやMapbox GL JSのプラグインを構築できたらおもしろいなと思ったりしました :grinning: 

ちなみに、以前の記事、「[色々なマップライブラリでポイント表示数の限界を探ってみた](https://qiita.com/dayjournal/items/86e1ca065e03ea88e0fb)」のように、GeoPackageでも5万件の表示を検証してみましたが、GeoJSONと表示の重さは変わらなかったのでLeaflet側の限界なのかなと思いました...

<br>

Leafletについて、他にも記事を書いています。よろしければぜひ :bow:
<a href="https://day-journal.com/memo/tags/Leaflet" target="_blank">tags - Leaflet</a>

やってみたシリーズ :grinning:
<a href="https://day-journal.com/memo/tags/Try" target="_blank">tags - Try</a>

<br>
<br>

<a href="https://dayjournal.booth.pm" target="_blank"><img src="https://day-journal.com/memo/images/etc/book.png" alt="book"></a>