O-map風ウェブ地図にOpenStreetMapと筆ポリゴンを重ねあわせる

↓の続きです。

できあがったものを先に貼っておきます。「Run Pen」をクリックして、あちこち移動して縮小したり拡大してみたりしてください。ズームレベルを保ったまま表示範囲を広げたい場合は「0.5x」、「0.25x」をクリック。

今回やったこと

  • OpenStreetMapから森林・草地・公園などのレイヤを重ね合わせ

  • 背景を立ち入り禁止の緑色にする

  • 湿地をパターン塗りつぶしする (これが一番たいへんだった)

  • 筆ポリゴンのベクトルタイルを重ねて耕作地をパターン塗りつぶしする

  • 標高タイルのソースを変更

上に貼ったデモではこれらの変更内容の地物を含むエリアを初期座標に設定しました。

OpenStreetMapのレイヤを重ねる

対象の選択

OpenOrienteering Mapperの OSM-ISOM 2017-2.crt にOpenStreetMapのタグとISOM2017-2の対応がまとまっているので参考にしました。例として一部抜粋↓

418    natural = bush
403    natural = grassland
403    natural = heath
408    natural = scrub
417    natural = tree
406    natural = wood
408    natural = wood AND (wood:age = young OR wood:age = very_young)
404    natural = wood AND wood:density = sparse
408    natural = wood AND wood:density = dense

OpenStreetMapの記号の定義はOpenStreetMap Wikiを見れば書いてあります。わりと楽しく読めます。

今回ピックアップするタグをとりあえず次のように決めました。

  • wood,forest,park→「405 森」

  • scrub→「406 走行困難」

  • grass, meadow→「401 開けた土地」

    • golf_courseタグが同時に付けられている場合は除外。

  • grassland, heath, logging →「403 開けた荒れ地」

  • parking, pitch, track→「501 舗装区域」

    • pitch(競技場。公園の中の野球場とかにこのタグがついている)は「OSM-ISOM 2017-2.crt」で「401 開けた土地」に分類されているけれど、地面硬いから舗装区域では?と思ってこっちに分類。それで正しいかは未確認。

建物・道・水系は国土地理院ベクトルタイルのほうが信頼性が高いと考えてOpenStreetMapからは拾っていません。

他に、独立樹や水飲み場などの点状特徴物のOpenStreetMapのタグもあったりして、それらを全部反映させていくのも楽しそうではありますが、優先順位的に今回は拾わないことにします。

MapTilerでAPIキー取得

OpenMapTilesというサービスでOpenStreetMapのデータがベクトルタイルで配信しています。それを使うためにMapTilerのアカウントが必要なので、登録してAPIキーを取得します。
非商用利用の場合、1カ月あたり10万件までのリクエスト数であれば無料で利用が可能です。

OpenMapTilesを地図に追加する

今回、すでに国土地理院ベクトルタイルがMapLibre GL JS上に乗っているので、そこに追加していきます。

まず、「sources」に地図の配信元(ソース)を追加します。↓の内容で追加したらAttributionへの出典表記も自動でやってくれました。

"openmaptiles": {
  "type": "vector",
  "url": "https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key=xxxxx"
},

上でSourcesに書いた設定でベクトルタイルを受信するようになったので、そこからフィルタで必要な地物を絞り込み、色を指定して塗ります。

        {
          "id": "401-開けた土地-osm",
          "type": "fill",
          "source": "openmaptiles",
          "source-layer": "landcover",
          "filter": [
            "all", 
            ["in", "class", "grass", "meadow"],
            ["!=", "subclass", "park"],
            ["!=", "subclass", "golf_course"]
          ],
          "paint": {
            "fill-color": "#ffba35"
          }
        },

背景を立ち入り禁止で塗りつぶす

背景を立禁色で塗りました。森や公園、水系、草地などで塗られていないところすべてを思い切って立禁にしています。実際には立ち入っていいところも立禁になってしまったりしますが、O-mapっぽい見た目であることを選びました。

      "layers": [{
          "id": "background",
          "type": "background",
          "paint": {
            "background-color": "#9eba1d"
          }
        },

湿地をパターン塗りつぶしする

MapLibre GL JSではパターンの塗りつぶしは数字では指定できず、パターンのもとになる画像を貼ってそれを敷き詰めるような書き方になります。今回、テキストだけでやりたかったので、同じファイル内にテキストでsvgを書いてそれを画像として読み込ませるようにしました。もっときれいな書き方あると思いますが↓のようになりました。

      const marshSVG =
        `
        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="3.0px" height="3.0px" viewBox="0 0 3.0 3.0">
          <rect x="0" y="0" width="100%" height="3.0" fill="#ffffff"></rect>
          <rect x="0" y="0" width="100%" height="1.5" fill="#00ffff"></rect>
        </svg>
      `;

      const marshImage = new Image();
      marshImage.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(marshSVG);
      marshImage.onload = () => {
        map.addImage('marshPattern', marshImage);
      };
        {
          "id": "307-湿地-gsivt",
          "type": "fill",
          "source": "gsivt",
          "source-layer": "landforma",
          "filter": ["any", ["==", "ftCode", 7401]],
          "paint": {
            "fill-pattern": "marshPattern"
          }
        },

筆ポリゴンのレイヤを重ねる

筆ポリゴンは、農林水産省が出している全国の農地の区画情報のGISデータです。

基盤地図情報などのように出典記載で利用できます。

今回、その筆ポリゴンをベクトルタイル化されたものがあったので地図に重ねてみることにします。

耕作地も湿地と同様にパターン塗りつぶしです。こんな感じになりました。

  const cultivatedLandSVG =
    `
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="3.0px" height="3.0px" viewBox="0 0 4.8 4.8">
      <style type="text/css">
        .st1 {
          fill: #000000;
        }
      </style>
      <rect fill="#ffba35" width="4.8" height="4.8"/>
      <circle class="st1" cx="2.4" cy="2.4" r="1.0"/>
    </svg>
  `;

  const cultivatedLandImage = new Image();
  cultivatedLandImage.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(cultivatedLandSVG);
  cultivatedLandImage.onload = () => {
    map.addImage('cultivatedLandPattern', cultivatedLandImage);
  };
        "fude-polygon": {
          "attribution": "<a href='https://github.com/optgeo/ag?tab=readme-ov-file#%E5%87%BA%E5%85%B8'>筆ポリゴンデータ(農林水産省)のベクトルタイル化</a>",              "maxzoom": 13,
          "tiles": [
            "https://optgeo.github.io/ag-tiles/zxy/{z}/{x}/{y}.pbf"
          ],
          "type": "vector"
        },
        {
          "id": "412-耕作地-pattern-fude",
          "paint": {
            "fill-pattern": "cultivatedLandPattern"
          },
          "source": "fude-polygon",
          "source-layer": "farmland",
          "type": "fill"
        },

標高タイルのソースを変更

この記事のもとになる記事を書いた2024/5/22の一週間後に「国立研究開発法人 産業技術総合研究所」から出た標高タイルの変換サービスが出ていたのでこれを使うことにします。

こんな感じになりました。

        "contour-source": {
          "type": "vector",
          "attribution": "<a href='https://maps.gsi.go.jp/development/ichiran.html#dem' target='_blank'>標高タイル</a>",
          tiles: [
            demSource.contourProtocolUrl({
              thresholds: {
                // zoom: [minor, major]
                11: [5, 25],
                12: [5, 25],
                14: [5, 25],
                15: [5, 25],
              },
              contourLayer: "contours",
              elevationKey: "ele",
              levelKey: "level",
              extent: 4096,
              buffer: 1,
            }),
          ],
        {
          "id": "101-等高線",
          "type": "line",
          "source": "contour-source",
          "source-layer": "contours",
          "paint": {
            "line-color": "#d15c00",
            // level = highest index in thresholds array the elevation is a multiple of
            "line-width": ["match", ["get", "level"], 1, 1, 0.56],
          },
        },

他に試したいことメモ

  • 画像/PDFのエクスポート。これはプラグインを追加するだけ。

  • 縮尺を数値で指定して変えられるようにしたい。緯度によってズームレベルと縮尺の対応が変わるので難しそう。

  • GPSログをアップロードして表示できるようにする。QuickRoute的な色分けはけっこう大変そう。

  • IOF XMLからコースをインポート。意外と簡単にできそう。

  • 道の太さをズームレベルに合わせて変更するようにしたい。国土地理院の出しているstd.jsonあたりの設定値を参考にする。道の重なり順とかも道路中心線のデータに含まれていて表現可能だけど、個人的にそこはあまり興味ない。

  • レイヤのオンオフをスウィッチャーで切り替える。

    • 標高タイルの等高線をオフにして国土地理院ベクトルタイルの等高線を使うように切り替えるようにできれば表示の遅延を抑えられたりとか。

    • 林野庁の樹種ポリゴンとか。

    • たとえばデザインはO-mapだけど地名とかも表示されて普段づかいできる地図とか。

  • 3D表示。

  • ジオリファレンス済み画像の重ね合わせ。

    • ジオリファレンスできるプラグインとかは無さそう。

この記事が気に入ったらサポートをしてみませんか?