18
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Google Maps APIの課金が気になるので、日本全国の地図をPMTiles+MapLibreで自前配信できるようにした

18
Last updated at Posted at 2026-08-05

Webサイトに地図を載せる場合、Google Maps Platformは有力な選択肢です。

一方で、Google Maps Platformは基本的に従量課金方式です。無料利用枠はありますが、アクセス数が増えた場合の費用、APIキーの管理、請求先アカウントの設定などを気にする必要があります。

そこで、次のような用途で使える日本全国の地図データを公開しました。
地図データは全てオープンデータ。商用も含めて、ご自由にお使いください。

  • Webサイトに背景地図を表示したい
  • 地図上にマーカーやGeoJSON(図形)を重ねたい
  • APIキーを発行せずに使いたい
  • 地図APIの呼び出し回数による課金を避けたい
  • 地図データを自分のWebサーバーから配信したい
  • 過去のOpenStreetMapと現在の状態を比較したい

公開ページはこちら。

自分のサーバーで日本地図を表示する|Japan PMTiles

どのようなものか

OpenStreetMapをもとに作成した日本全国のベクトル地図を、PMTiles形式で配布しています。

地図表示にはMapLibre GL JSを使用します。

必要なファイルは、基本的に次の3つです。

index.html
japan-20260101.json
japan-20260101.pmtiles

この3ファイルを同じフォルダーに置いてWebサーバーで公開すると、日本全国の地図を表示できます。

専用のタイルサーバーやデータベースは必要ありません。

PMTilesとは

一般的なWeb地図(ラスタ形式など)では、ズームレベルや位置ごとに分割された大量のタイルファイルを使用します。

例えば、次のようなURLです。

/{z}/{x}/{y}.pbf

PMTilesは、これらのタイルを1つのファイルにまとめるための形式です。

japan-20260101.pmtiles

ブラウザは、この大きなファイルを毎回すべてダウンロードするわけではありません。HTTP Range Requestを使い、表示に必要な部分だけを取得します。

そのため、次のような構成を作れます。

ブラウザ
  ↓ 必要な範囲だけ取得
Webサーバー
  └─ japan-20260101.pmtiles

大量のタイルファイルを展開せず、1ファイルのまま配信できることがPMTilesの大きな利点です。

Google Mapsをすべて置き換えるものではない

今回配布しているものは、主にGoogle Maps JavaScript APIなどで行っていた「背景地図の表示」を自前配信へ移すためのものです。

Google Maps Platformのすべての機能を、そのまま置き換えるものではありません。

機能 この構成での対応
背景地図の表示 対応
地図の拡大・縮小・回転・傾斜 対応
マーカーの表示 MapLibreで対応
ポップアップの表示 MapLibreで対応
GeoJSONの重ね合わせ MapLibreで対応
地図の色や表示内容の変更 style.jsonで対応
表示中の店舗や施設の取得 PMTiles内の属性から取得可能
住所検索 Nominatimなどが別途必要
日本全国を対象にした店舗検索 検索APIまたは索引が別途必要
ルート検索 OSRMやGraphHopperなどが別途必要
Street View 含まれない(Mapillaryを活用)
口コミ、写真、混雑状況 含まれない
航空写真 別のタイルが必要

単純な背景地図、マーカー、図形表示が中心のサイトであれば、置き換えを検討しやすい構成です。また、少し頑張れば、UIデザインも含めて、かなり自由度と柔軟性の高い地図を提供出来るかと思います。

最小構成のHTML

次のHTMLで地図を表示できます。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>日本地図</title>

  <link
    rel="stylesheet"
    href="https://unpkg.com/maplibre-gl@5.24.0/dist/maplibre-gl.css"
  >

  <style>
    html,
    body,
    #map {
      width: 100%;
      height: 100%;
      margin: 0;
    }
  </style>
</head>

<body>
  <div id="map"></div>

  <script src="https://unpkg.com/maplibre-gl@5.24.0/dist/maplibre-gl.js"></script>
  <script src="https://unpkg.com/pmtiles@4.4.1/dist/pmtiles.js"></script>

  <script>
    const protocol = new pmtiles.Protocol();
    maplibregl.addProtocol("pmtiles", protocol.tile);

    const map = new maplibregl.Map({
      container: "map",
      center: [138, 37],
      zoom: 4,
      style: "./japan-20260101.json",
      localIdeographFontFamily: "sans-serif"
    });
  </script>
</body>
</html>

PMTilesのURLはstyle.json側に記述されています。

概念的には、次のような設定です。

{
  "sources": {
    "japan": {
      "type": "vector",
      "url": "pmtiles://./japan-20260101.pmtiles"
    }
  }
}

MapLibreへPMTiles用のプロトコルを登録することで、pmtiles://から始まるURLを読み込めるようになります。

const protocol = new pmtiles.Protocol();
maplibregl.addProtocol("pmtiles", protocol.tile);

マーカーを追加する

MapLibreの標準機能でマーカーを追加できます。

new maplibregl.Marker()
  .setLngLat([135.5023, 34.6937])
  .addTo(map);

大阪市付近にマーカーが表示されます。

ポップアップを追加する

マーカーに説明を付けることもできます。

const popup = new maplibregl.Popup({
  offset: 25
}).setHTML(`
  <strong>大阪市</strong><br>
  サンプル地点です。
`);

new maplibregl.Marker()
  .setLngLat([135.5023, 34.6937])
  .setPopup(popup)
  .addTo(map);

GeoJSONを重ねる

独自の地点、線、区域などはGeoJSONとして追加できます。

map.on("load", () => {
  map.addSource("sample-points", {
    type: "geojson",
    data: {
      type: "FeatureCollection",
      features: [
        {
          type: "Feature",
          properties: {
            name: "大阪市"
          },
          geometry: {
            type: "Point",
            coordinates: [135.5023, 34.6937]
          }
        },
        {
          type: "Feature",
          properties: {
            name: "京都市"
          },
          geometry: {
            type: "Point",
            coordinates: [135.7681, 35.0116]
          }
        }
      ]
    }
  });

  map.addLayer({
    id: "sample-points",
    type: "circle",
    source: "sample-points",
    paint: {
      "circle-radius": 8,
      "circle-stroke-width": 2,
      "circle-stroke-color": "#ffffff"
    }
  });
});

このように、背景地図はPMTilesから読み込み、その上に自分のデータを重ねられます。

PMTiles内の店舗や施設は検索できるのか

PMTilesに店舗名や施設名などの属性が収録されていれば、MapLibreから取得できます。

例えば、読み込まれているベクトルタイルをquerySourceFeatures()で調べられます。

function searchLoadedPois(keyword) {
  const normalizedKeyword = keyword.trim().toLowerCase();

  const features = map.querySourceFeatures("japan", {
    sourceLayer: "pois"
  });

  return features.filter((feature) => {
    const name = String(feature.properties?.name ?? "").toLowerCase();
    return name.includes(normalizedKeyword);
  });
}

ただし、これは原則としてMapLibreが現在読み込んでいるタイル(≒画面に表示している範囲)が対象です。

日本全国に存在するすべての店舗を、PMTilesファイル内から一括検索する機能ではありません。

用途によって、次のように使い分けます。

表示中の範囲を検索する場合

PMTilesとMapLibreだけで実装できます。

  • 表示中の店舗を取得する
  • 店舗名で絞り込む
  • 店舗をクリックして属性を表示する
  • コンビニや飲食店などの種類で絞り込む

日本全国を横断検索する場合

別途、検索用の仕組みを用意します。

  • Overpass API(サーバー選択と負荷が課題)
  • Nominatim(世界全体を検索してしまう)
  • SQLiteなどで作成した検索インデックス(ちょっとだけ手間)
  • 店舗名と座標をまとめたJSON(決まっているならオススメ)

検索結果として緯度・経度を取得し、その地点へMapLibreを移動させる構成になります。

地図デザインはstyle.jsonで変更できる

道路、水域、建物、文字、背景色などの表示設定は、MapLibre Style Specificationに従ったJSONで定義されています。

japan-20260101.json

style.jsonを編集すれば、例えば次のような変更ができます。

  • 道路の色や太さを変える
  • 建物を非表示にする
  • 店舗アイコンの表示条件を変える
  • 地名の文字サイズを変える
  • ダークモード風にする
  • 特定の種類の地物だけを強調する

JSONを直接編集するほか、Maputnikを使うと、ブラウザ上で地図を見ながら編集できます。

過去の日本地図も公開

2010年から2026年まで、12点の日本全国データを用意しています。
※2025年10月13日(大阪・関西万博の閉幕日も作ったので1件多い)

同じ場所を異なる時点で表示することで、OpenStreetMap上の変化を確認できます。

例えば、次のような用途が考えられます。

  • 新しい道路が追加された時期を調べる
  • 建物や施設の変化を見る
  • OpenStreetMapのデータ充実度を比較する
  • 地域のマッピング活動を振り返る
  • 過去時点の地図を教材や展示に使う

これは実際の過去の景観や行政上の状態を保証するものではなく、各時点でOpenStreetMapに登録されていた内容を表示するものです。

少し昔の地図を見てみよう」と言うサイトで実際に当時の地図を見ることが出来ます。

Webサーバー側の条件

PMTilesを配信するWebサーバーは、HTTP Range Requestに対応している必要があります。

多くの一般的なWebサーバーは対応していますが、利用するホスティングサービスによっては確認が必要です。
※少なくとも、さくらインターネットのレンタルサーバー(スタンダード)は対応済み。

HTMLとPMTilesを別のドメインに置きたい場合

CORSの設定も必要です。
例として、Apacheでは環境に応じて次のようなヘッダーを設定します。

<FilesMatch "\.pmtiles$">
  Header set Access-Control-Allow-Origin "*"
  Header set Accept-Ranges "bytes"
</FilesMatch>

Access-Control-Allow-Origin: *が適切かどうかは、利用目的に応じて判断してください。特定サイトだけに許可する場合は、そのオリジンを指定します。

まぁ、別ドメインにしなければ問題無いので、同じサーバーに置くなら対応不要です。

「無料」ではなく「地図APIの回数課金がない」

今回の構成では、Google Maps Platformなどの地図APIを呼び出さないため、地図APIの表示回数に応じた課金はありません。ただし、費用が完全にゼロになるとは限りません。

Webサーバーの利用料(性能、ストレージ、通信量)、サーバーの管理費(人件費など)は無料になりません。
アクセス数が非常に増えた場合は、自前配信側の通信量や同時接続数、CDNの必要性を確認する必要があります。

一般的には、アクセス数が増えてもPMTilesの自前配信は地図APIより低コストになりやすい構成ですが、配信の安定性や運用負担も含めて、地図APIと比較する必要があります。

逆に、小規模なサイト、学校内のシステム、自治体や地域団体のサイト、期間限定のイベントマップなどでは、費用を予測しやすい構成なので、かなり使えると思います。

OpenStreetMapの帰属表示について

配布データはOpenStreetMapをもとにしています。

地図を表示する際は、OpenStreetMapへの帰属表示を削除しないでください。

© OpenStreetMap contributors

OpenStreetMapのデータはOpen Database Licenseのもとで提供されています。

詳しくは、次のページを確認してください。

向いている用途

この構成は、特に次のような用途に向いています。

  • 店舗や施設の案内地図
  • イベント会場マップ
  • オープンデータの可視化
  • ハザード情報の重ね合わせ
  • 学校や授業で使う地図
  • 研究用の地図
  • 地域活動のWebマップ
  • 過去のOpenStreetMap比較
  • 外部APIへ依存しにくい地図システム
  • マーカーとポップアップが中心の小規模サイト

一方、次の機能が中心の場合は、Google Maps Platformなどの既存サービスを利用する方が簡単な場合があります。

  • 高度な住所検索
  • 店舗の口コミや営業時間
  • リアルタイムの交通情報
  • 経路案内
  • Street View
  • 商用施設データ

まとめ

PMTilesとMapLibreを使うと、日本全国のベクトル地図を静的ファイルとして自分のWebサーバーから配信できます。

今回公開したデータには、次の特徴があります。

  • APIキーが不要
  • 地図APIの表示回数による課金がない
  • 専用のタイルサーバーが不要
  • PMTilesを1ファイルのまま配信できる
  • MapLibreでマーカーやGeoJSONを追加できる
  • style.jsonで地図デザインを変更できる
  • 2010年から2026年までの過去データを比較できる

Google Maps Platformの全機能を置き換えるものではありませんが、「背景地図を表示し、その上に自分の情報を載せる」という用途では、選択肢の一つになると考えています。

配布ページには、PMTiles、style.json、サンプルHTML、カスタマイズ方法をまとめています。

自分のサーバーで日本地図を表示する|Japan PMTiles

参考サイト

18
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?