🗾

OpenLayersで地理院地図をベクトルタイルで地理院同様のスタイルで表示してみた

2025/04/01に公開

目的

  • OpenLayersを使用して、地理院地図をベクトルタイルレイヤで表示
  • 地理院地図と同じスタイリングで表示(標準地図)

結論

  • 地理院はOpenLayers用のスタイリングファイルを用意していない
  • mapbox用のstyle.jsonを地理院のGitHubからダウンロードできる
  • ol-mapbox-style を使用する事で、mapbox用style.jsonをOpenLayersでも使用できる

使用技術

  • Vue3
  • OpanLayers
  • 地理院地図

前提の説明(ベクトルタイルレイヤとは)

ご存知の方は読み飛ばしてください~
地図タイルの配信方法として、現在主に使われているのは

  • ベクトルタイル(Vector Tiles)
  • ラスタータイル(Raster Tiles)
    が存在します。※ほかにもあるが省略

✅ ベクトルタイルレイヤ(Vector Tile Layer)

特徴 説明
データ形式 ジオメトリ(点・線・面)と属性情報。通常はPBF(Protocol Buffer)形式で配信される。
描画方法 クライアントがスタイル情報に従って描画する。
拡大・縮小 スムーズで高解像度。どんなズームレベルでもシャープ。
スタイル変更 クライアント側で自由にスタイル変更可能(色・太さ・ラベルなど)。
ファイルサイズ 一般的に軽量(テキスト・数値データなので)

🖼️ ラスタータイルレイヤ(Raster Tile Layer)

特徴 説明
データ形式 画像(JPEG、PNG など)
描画方法 サーバー側で描画された画像をそのままクライアントに表示する。
拡大・縮小 拡大すると画像がぼやける。
スタイル変更 サーバー側でしかスタイル変更できない(再生成が必要)。
ファイルサイズ ベクトルより重め(画像なので)

🎯 用途別の使い分け

用途 向いているレイヤ
柔軟なスタイル変更や動的な表現 ベクトルタイルレイヤ
古いブラウザや単純な表示 ラスタータイルレイヤ
印刷や静的地図が必要なとき ラスタータイルレイヤ
高解像度ディスプレイやモバイル対応 ベクトルタイルレイヤ

📝 前提のまとめ

  • ベクトルタイルレイヤ は「データを配信して、クライアントで描く」→ インタラクティブで柔軟。
  • ラスタータイルレイヤ は「画像を配信して、そのまま表示」→ 簡単で確実。

今回の記事は、
「ベクトルタイルレイヤを用いて柔軟なスタイル変更をしたいが、地理院地図と同じスタイリングをベースに描画したい。」
というちょっとわがままな要望を叶える記事です。

セットアップ

$ npm i ol ol-ext ol-mapbox-style

まずは地図を表示してみた

OpenLayersを使用する際は、main.tsol/oll.css をインポートする

main.ts
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import "ol/ol.css";

createApp(App).use(router).mount("#app");

地理院地図のベクトルタイルレイヤを表示するコンポーネントを作成

地理院地図Vector提供実験(GitHub)

MapView.vue
<template>
  <h1>地理院地図をベクトルタイルレイヤで表示してみたい</h1>
  <div id="map"></div>
</template>

<script setup lang="ts">
import { nextTick, onMounted } from "vue";
import Map from "ol/Map";
import View from "ol/View";
import VectorTileLayer from "ol/layer/VectorTile";
import VectorTileSource from "ol/source/VectorTile";
import MVTFormat from "ol/format/MVT";
import { fromLonLat } from "ol/proj";

onMounted(async () => {
  await nextTick();
  new Map({
    target: "map",
    layers: [
      new VectorTileLayer({
        source: new VectorTileSource({
          format: new MVTFormat({}),
          url: "https://cyberjapandata.gsi.go.jp/xyz/experimental_bvmap/{z}/{x}/{y}.pbf",
        }),
      }),
    ],
    view: new View({
      center: fromLonLat([139.767, 35.681]),
      zoom: 11,
    }),
  });
});
</script>

<style scoped>
#map {
  height: 800px;
}
</style>

これで地理院地図をベクトルタイルレイヤで表示できました。
※Networkタブで数値.pbfが取得されているのがわかります。

スタイルを付けてみる

地理院地図のスタイルを見てみた

地理院地図Vector提供実験(GitHub)
ここで取得できる標準地図のstyle std.json

Style Specificationをベースにしたうえで、若干の拡張を施しています。

と記載があり、OpenLayersではそのまま使用することが出来ません。

MapBoxのスタイルを見つけた

Mapbox GL JSで地理院地図Vector風の地図を表示するサンプル(GitHub)
ここでは、MapBoxで動作するstyle.jsonを配布してくれています。

MapBox用につき、このままではOpenLayersで表示できませんが、今回はこちらを用いてOpenLayersで表示する実装を試します。

MapBoxスタイルをOpenLayersに適用する方法

ol-mapbox-stylestylefunctionを使用します。

今回は、先ほどのMapBox用スタイル(std.json)を使用してみます。
ここからダウンロードをし、Vueプロジェクト内に配置します。

レイヤーに対してstylefunctionを使用してスタイリングを行います。

↓完成形

MapView.vue
<template>
  <h1>地理院地図をベクトルタイルレイヤで表示してみたい</h1>
  <div id="map"></div>
</template>

<script setup lang="ts">
import { nextTick, onMounted } from "vue";
import Map from "ol/Map";
import View from "ol/View";
import VectorTileLayer from "ol/layer/VectorTile";
import VectorTileSource from "ol/source/VectorTile";
import MVTFormat from "ol/format/MVT";
import { fromLonLat } from "ol/proj";
import { stylefunction } from "ol-mapbox-style";
import style from "@/mapstyles/std.json";

onMounted(async () => {
  await nextTick();
  // レイヤーを先に作成しておく
  const vectorTileLayer = new VectorTileLayer({
    source: new VectorTileSource({
      format: new MVTFormat({}),
      url: "https://cyberjapandata.gsi.go.jp/xyz/experimental_bvmap/{z}/{x}/{y}.pbf",
    }),
  });

  new Map({
    target: "map",
    layers: [vectorTileLayer],
    view: new View({
      center: fromLonLat([139.767, 35.681]),
      zoom: 11,
    }),
  });

  // stylefunctionを使って、地理院地図の標準地図スタイルを適用する
  const layers = style.layers.map((layer) => layer.id);
  stylefunction(vectorTileLayer, style, layers);
});
</script>

<style scoped>
#map {
  height: 800px;
}
</style>

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

標準地図っぽくなりました!

まとめ

  • 地理院地図はすごい
  • OpenLayersもすごい
  • ol-maxbox-styleもすごい

おまけ:弊社では一緒に働く仲間を募集しています!

弊社では一緒に働く仲間を募集しています!
株式会社コードユニットは 「エンジニアが自由に挑戦し、成長できる環境を創る」(意訳) をビジョンに掲げる札幌のIT企業です。

社員募集.js
const ourBelief =
  'エンジニアが楽しく社内で研鑽出来る' === 'お客様へ最大の価値を提供できる' || true;

if (ourBelief) {
  console.log('そんな信念で動いている、とにかく楽しい会社です。是非応募してください。');
} else {
  throw new Error('https://codeunit.co.jp/recruit');
}
株式会社コードユニット

Discussion