記事内に広告が含まれています

【ワレコのプログラミング】ASP.NET CoreでOpenStreetMapを表示してみる【Mapboxのクラスター機能実験】

この記事は約17分で読めます。
スポンサーリンク

ワレコ

超久しぶりに地図プログラミングを試してみた。

具体的にはOpenStreetMapを表示してみた。

Visual Studio 2022にあるASP.NET CoreのModel View Controllerテンプレートを使って無料のOpenStreetMapの表示に無事に成功した。

またMapboxにあるクラスター表示機能も試してみたが、簡単にクラスター機能を使う事も出来た。

では本題に入ろう。

スポンサーリンク
スポンサーリンク

地図サイトの作成がWEBプログラミングのスタートだった

元々ワテがWEBプログラミングを始めた切っ掛けは、2015年頃にGoogle Maps APIのサンプルHTMLファイルを見付けて、そのHTMLやJavaScriptコードをいろいろ試して地図プログラミングを始めた事から始まる。

Google Maps APIのサンプルはこちら↴

Overview  |  Maps JavaScript API  |  Google for Developers
Get started with the Google Maps JavaScript API. View a simple example, learn the concepts, and create custom maps for y...

その後のワテは幾つかの地図サイトを作ったり、あるいは、データーベースプログラミングも独学で習得して、各種のヘンテコなWEBサイトを作るなどして、WEBプログラミングを独学で習得したのだ。

ワテがGoogle Maps APIを使って作った地図サイトは今も公開しているが、Google Maps APIの利用が有料になった数年前からは、API使用のリクエスト数を制限して毎月200ドルまでの無料範囲に収まるようにしている。

その結果、ワテ自作の地図サイトは利用者も少なく、閑古鳥が鳴いている状態である。

なので、地図サイトを閉鎖する事も検討しているのだが、決断しないままズルズルと数年経ってしまった。

この際、Google Maps APIの利用は完全に中止して、無料のOpenStreetMapを使って地図サイトをリニューアルしてみようかな!?などと考えたのだが、実際にやるかどうかは未だ決めていない。

そこで取り敢えずOpenStreetMapを試してみる事にしたのだ。

OpenStreetMapとは何か?

オープンストリートマップのWikipediaから引用させて頂くと、以下の通り。

オープンストリートマップ(英語: OpenStreetMap、OSM)は自由に利用でき、なおかつ編集機能のある世界地図を作る共同作業プロジェクトである。

引用元 https://ja.wikipedia.org/wiki/オープンストリートマップ

まあ要するにみんなで無料の世界地図を作ろうと言うプロジェクトだ。具体的にどうやって地図を作っているのかなどはワテは良く知らない。

Google Mapsの場合ならストリートビューの撮影自動車が世界中の景色を撮影しているようだが、OpenStreetMapの場合には地図だけでありストリートビューの機能は無いので、自動車で撮影するなどの作業はやっていないと思う。

Mapboxとは何か?

実は、Mapboxと言うのは今日初めて知った。

Mapbox公式サイトはこちら↴

Mapbox | Maps, Navigation, Search, and Data
APIs and SDKs for AI-powered maps, location search, turn-by-turn navigation, and geospatial data in mobile or web apps. ...

日本のMapboxサイトはこちら↴

Mapbox - デジタル地図の開発プラットフォーム
Mapboxは、デジタル地図の開発プラットフォームです。高度なデザイン性とカスタマイズ性を持ち、各種データとレイヤーを柔軟に組み合わせ、顧客独自の地図情報サービスを簡単に開発できるのが特徴です。また、各種データを常に最新の状態に保ち、データ...

MapboxのWikipediaから引用させて頂くと以下の通り。

Mapboxとはウェブサイト、アプリケーション向けオンラインカスタムマップ(英語版)の大規模プロバイダで、 主にFoursquare、ロンリープラネット、Evernote、フィナンシャル・タイムズ、ウェザーチャンネル(英語版)、Snapchatで採用されている[2]。2010年の創業以降、Googleマップなど選択肢が限られている業界においてカスタムマップのニッチ需要で急速に拡大している[2]。並びにMapboxはMBTilesや、TileMillという地図作成IDE、LeafletというJavaScriptライブラリ、CartoCSSという地図スタイル言語およびパーサーといったオープンソースの地図ライブラリやアプリケーションを開発もしくは主要作成者である[要出典]。

引用元 https://ja.wikipedia.org/wiki/Mapbox

なんのこっちゃサッパリ分からん。

Mapboxはアメリカの民間企業のようだ。

日本のMapboxサイトには以下の説明がある。

Mapboxは開発者向けの地図開発プラットフォームです。

社内外の様々なデータを自由に組み合わせ、ユースケースに最適な地図を
構築することで企業のロケーションデータ活用を促進します。

引用元 https://www.mapbox.jp/

Mapboxに付いて少し調べた限りでは、Mapboxを使えばゼンリン地図、国土地理院地図、OpenStreetMapなどの色んな地図を表示出来て、かつ、地図アプリを作る上で役立つ色んな機能が提供されているようだ。無料で使える物や有料のサービスもある。

今回はMapboxにあるクラスター(Cluster)表示機能を試してみた。

クラスター(Cluster)表示機能とはどんな機能かは、この後に登場する実際にワテが作ってみた地図サイトで解説したい。

Leafletとは何か?

Leafletは以前に少し試した事がある。

LeafletのWikipediaから引用させて頂くと以下の通り。

Leafletは広く使われているWeb地図のためのJavaScriptライブラリである。 2011年に最初にリリースされた[3]。 モバイルとデスクトップのプラットフォームのほとんどに対応し、HTML5とCSS3に対応している。 OpenLayersやGoogle Maps API(英語版)とともに最も人気のあるJavaScript地図ライブラリの一つであり、FourSquare、Pinterest、Flickrなどの有名なサイトで使われている。

Leafletを使うと、GISの知識のない開発者でも容易にタイルベースのWeb地図を表示できる。またGeoJSONから地物データを読み込んでスタイリングしたり、インタラクティブなレイヤーを作ることができる(クリックするとポップアップが表示されるマーカーなど)。

引用元 https://ja.wikipedia.org/wiki/Leaflet

まあ要するにLeafletとは地図サイトを作る為のJavaScriptライブラリだ。Google Maps APIに相当するものだ。

先ほど紹介したMapbox社のWikipediaにはLeafletの開発をやっているのもMapboxと記載されている。

と言う訳で、OpenStreetMapを表示するにはMapboxあるいはLeafletを使えば良さそうだ。

MapboxのClusterサンプルをASP.NET Coreサイトに表示成功

さて、Visual Studio 2022が2021年11月頃に発表されたので、ワテのWindows10パソコンにもインストールしている。

そのVS2022にあるASP.NET CoreのModel View Controllerテンプレートを使ってWEBサイトを作ってみる。

そのWEBサイトに、OpenStreetMapを表示して、かつクラスター機能を動かしてみた。

参考にしたのはMapboxのサイトで見付けたクラスター表示のサンプルコードだ。

サンプル | Mapbox GL JS
Mapbox GL JSのコード例。

このサンプルHTMLをASP.NET Coreで作ったWEBサイトのIndex.cshtmlファイルに貼り付けたら無事にOpenStreetMapを表示する事が出来た。

そのWEBサイトをワテが契約しているレンタルサーバー(ABLENET社のWindows VPS)に発行した。

そのWEBサイトを下に示す。

上に表示しているのがOpenStreetMapだ。丸い円形は、その地域で発生した地震の震源地の位置と数を示している。

大画面で表示したい人はこちら↴

 https://www.wareko.net/AhoBakaMaps

マウスホイールを回すと地図を拡大・縮小表示出来るが、それに連動してクラスターの大きさも数も変わる。

クラスターの円をクリックすると、地図が拡大すると同時にクラスターが細分化されて細かい情報が分かる。

このように地図上に何らかのデータの分布を表示して、その数を自動的に集計してくれる機能の事を地図アプリ業界ではクラスター機能と呼んでいる。Google Maps APIにもクラスター表示機能がある。

このHTMLは以下の通り。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>クラスターの作成と設定</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>

<script>
	mapboxgl.accessToken = 'pk.eyJ1IjoiYWhvYmFrYSIsImEiOiJja3hrZHZjenYzMmhrMnd0aGR0dm9rYmxmIn0.fhxpJTjBvoJpSqX4tkea6A';
    const map = new mapboxgl.Map({
        container: 'map',
        style: 'mapbox://styles/mapbox/dark-v10',
        center: [-103.5917, 40.6699],
        zoom: 3
    });

    map.on('load', () => {
        // Add a new source from our GeoJSON data and
        // set the 'cluster' option to true. GL-JS will
        // add the point_count property to your source data.
        map.addSource('earthquakes', {
            type: 'geojson',
            // Point to GeoJSON data. This example visualizes all M1.0+ earthquakes
            // from 12/22/15 to 1/21/16 as logged by USGS' Earthquake hazards program.
            data: 'https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson',
            cluster: true,
            clusterMaxZoom: 14, // Max zoom to cluster points on
            clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)
        });

        map.addLayer({
            id: 'clusters',
            type: 'circle',
            source: 'earthquakes',
            filter: ['has', 'point_count'],
            paint: {
                // Use step expressions (https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-step)
                // with three steps to implement three types of circles:
                //   * Blue, 20px circles when point count is less than 100
                //   * Yellow, 30px circles when point count is between 100 and 750
                //   * Pink, 40px circles when point count is greater than or equal to 750
                'circle-color': [
                    'step',
                    ['get', 'point_count'],
                    '#51bbd6',
                    100,
                    '#f1f075',
                    750,
                    '#f28cb1'
                ],
                'circle-radius': [
                    'step',
                    ['get', 'point_count'],
                    20,
                    100,
                    30,
                    750,
                    40
                ]
            }
        });

        map.addLayer({
            id: 'cluster-count',
            type: 'symbol',
            source: 'earthquakes',
            filter: ['has', 'point_count'],
            layout: {
                'text-field': '{point_count_abbreviated}',
                'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
                'text-size': 12
            }
        });

        map.addLayer({
            id: 'unclustered-point',
            type: 'circle',
            source: 'earthquakes',
            filter: ['!', ['has', 'point_count']],
            paint: {
                'circle-color': '#11b4da',
                'circle-radius': 4,
                'circle-stroke-width': 1,
                'circle-stroke-color': '#fff'
            }
        });

        // inspect a cluster on click
        map.on('click', 'clusters', (e) => {
            const features = map.queryRenderedFeatures(e.point, {
                layers: ['clusters']
            });
            const clusterId = features[0].properties.cluster_id;
            map.getSource('earthquakes').getClusterExpansionZoom(
                clusterId,
                (err, zoom) => {
                    if (err) return;

                    map.easeTo({
                        center: features[0].geometry.coordinates,
                        zoom: zoom
                    });
                }
            );
        });

        // When a click event occurs on a feature in
        // the unclustered-point layer, open a popup at
        // the location of the feature, with
        // description HTML from its properties.
        map.on('click', 'unclustered-point', (e) => {
            const coordinates = e.features[0].geometry.coordinates.slice();
            const mag = e.features[0].properties.mag;
            const tsunami =
                e.features[0].properties.tsunami === 1 ? 'yes' : 'no';

            // Ensure that if the map is zoomed out such that
            // multiple copies of the feature are visible, the
            // popup appears over the copy being pointed to.
            while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
                coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
            }

            new mapboxgl.Popup()
                .setLngLat(coordinates)
                .setHTML(
                    `magnitude: ${mag}<br>Was there a tsunami?: ${tsunami}`
                )
                .addTo(map);
        });

        map.on('mouseenter', 'clusters', () => {
            map.getCanvas().style.cursor = 'pointer';
        });
        map.on('mouseleave', 'clusters', () => {
            map.getCanvas().style.cursor = '';
        });
    });
</script>

</body>
</html>

コード OpenStreetMapでクラスター表示のサンプル

引用元 https://docs.mapbox.com/jp/mapbox-gl-js/example/cluster/

と言う訳で、Mapboxのクラスター表示のサンプルプログラムをそのまま流用してASP.NET Coreのページに埋め込んだだけであるが、無事にOpenStreetMapの表示やクラスター表示に成功した。

まとめ

ワレコ

超久しぶりに地図プログラミングをやってみた。

やっぱり時々はプログラムを書かないと、脳みそが劣化すると思う。

当記事ではVisual Studio 2022にあるASP.NET CoreのModel View Controllerテンプレートを使って作成したWEBサイトにOpenStreetMapのサンプルを表示する実験を紹介した。

Mapboxを使うとクラスター表示も簡単に出来た。これはたぶんLeafletにクラスター表示機能が実装されていて、Mapboxから呼び出しているのだと思う。

なぜなら、OpenStreetMapでクラスター表示をするサンプルをネットで検索してみると、Mapboxを使わずにLeafletの機能のみでクラスター表示をやっている例もあるので。

と言う訳で、OpenStreetMapを使って地図サイトを作成する第一歩を踏み出す事が出来た。

今後はLeafletやMapboxの使い方を勉強すると同時に、データベース機能(Entity Frameworkを使う予定)やSNSログイン機能を組み込みたいと思っている。

そうすると、いろんな地図アプリの開発に応用できるからだ。

スポンサーリンク
コメント募集

この記事に関して何か質問とか補足など有りましたら、このページ下部にあるコメント欄からお知らせ下さい。

ASP.NET Core自作ソフト
スポンサーリンク
シェアする
warekoをフォローする
スポンサーリンク

コメント