0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MapLibreとdeck.glの連携構成を解説 — 地図表示とデータ表示

Posted at

はじめに

前回の記事「deck.glで地理座標を可視化する」では、
deck.gl単体で緯度・経度データを地図上に描画する方法を紹介しました。

deck.glはWebGLベースの高性能なデータ可視化ライブラリであり、
数十万点を超えるデータをブラウザ上で滑らかに描画できるのが特徴です。
ScatterplotLayerGeoJsonLayer などのレイヤを使うことで、
地理座標を含むデータを簡潔に可視化できます。

ただし、deck.glは地図を描画するライブラリではないので
地名ラベルや道路表示、地図スタイルの変更といった“地図としての表現”を担う機能は備えていません。

そのため、背景地図を扱う場合には
TileLayerBitmapLayer を使って外部の地図タイル画像を重ねる必要があります。
この構成でも緯度経度のデータを描画することはできますが、
背景はあくまで「画像」であり、地図的な機能は持ちません。

本記事では、MapLibre GL JS と組み合わせた地図表現を紹介します。
deck.gl単体では扱えなかった背景スタイルやズーム同期を、MapLibre連携でどのように実現できるかを解説します。

deck.gl単体構成の限界

deck.gl自身は地図エンジンを持たないため、背景地図はあくまで静的な画像であり、
地図のズームやスタイル、注記(地名ラベル)などを制御することはできません。

deck.gl単体には、次のような制限があります。

  • 背景の地図タイルとdeck.glのカメラ位置(viewState)を手動で同期させる必要がある
  • 背景と可視化レイヤが別々に動くため、ズームや回転の操作感が不自然になる
  • ラベルや注記はタイル画像に含まれ、フォントや言語を変更できない
  • 背景のスタイルを切り替える場合、タイルURLを差し替えるしかない

これらの制限により、deck.gl単体では「データの可視化」はできても、
「地図としての表現や操作性」は限定的になります。

MapLibreとdeck.glの役割の違い

deck.glは高性能なデータ可視化ライブラリですが、地図そのものを描画するための機能は備えていません。
一方、MapLibreは地図を描くためのエンジンです。
両者は目的が明確に異なり、互いを補完する関係にあります。

項目 deck.gl MapLibre GL JS
主な役割 データ可視化エンジン 地図描画エンジン
扱う対象 点・線・ポリゴンなどのデータ 道路・建物・注記などの地理オブジェクト
管理する要素 WebGLレイヤ構造(ScatterplotLayer など) カメラ・ズーム・回転・スタイル・注記
背景地図 静的なタイル画像 ベクトルスタイル(動的な描画)
主な出力 データビジュアライゼーション 地図そのもの

deck.glは「WebGLでデータを描く」ことに特化しており、
MapLibreは「地図としての表現や操作を担う」役割を持ちます。

この2つを組み合わせることで、次のような構成が実現します。

  • MapLibre が地図背景(道路・建物・ラベル)とカメラ制御を担当
  • deck.gl が地図上のデータ可視化(点群・領域・経路など)を担当

つまり、MapLibreが「地図の土台」を提供し、
その上にdeck.glが「データの表現」を重ねる構成になります。

この構成で、

  • ズーム・回転・傾斜の操作に対してdeck.glレイヤが追随
  • 背景スタイル(ライト/ダーク)を切り替えてもdeck.glレイヤを維持
  • 地名や注記がベクトルスタイルで動的に再描画

といった地図として自然な可視化を実現できます。

MapLibreとdeck.glを連携させる構成

要点は以下の3つです。

  • maplibregl.Map() でMapLibreの地図インスタンスを生成する
  • deck.glのレイヤを MapboxOverlay 経由でMapLibreに統合する
  • 両者が同一のWebGLコンテキストを共有し、カメラ操作を同期する

これにより、ズームや回転などの操作に合わせてdeck.glレイヤも自然に再描画されます。

サンプル:最小構成のHTML

以下は、MapLibreとdeck.glを連携させるための最小サンプルです。
背景にはCartoの「Positron」スタイルを使用しています(APIキー不要)。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8" />
  <title>MapLibre × deck.gl 最小構成サンプル</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link href="https://unpkg.com/maplibre-gl@3.6.1/dist/maplibre-gl.css" rel="stylesheet" />
  <script src="https://unpkg.com/maplibre-gl@3.6.1/dist/maplibre-gl.js"></script>
  <script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
  <style>
    body { margin: 0; overflow: hidden; }
    #map { position: absolute; top: 0; bottom: 0; width: 100%; }
  </style>
</head>
<body>
  <div id="map"></div>
  <script>
    // MapLibre地図の初期化
    const map = new maplibregl.Map({
      container: 'map',
      style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json', // Cartoスタイル(キー不要)
      center: [139.7671, 35.6812], // 東京駅
      zoom: 12,
      pitch: 0
    });

    // deck.glのレイヤを作成
    const scatterLayer = new deck.ScatterplotLayer({
      id: 'scatter-layer',
      data: [
        { position: [139.7671, 35.6812], color: [255, 0, 0], radius: 100 },
        { position: [139.75, 35.68], color: [0, 128, 255], radius: 80 }
      ],
      getPosition: d => d.position,
      getRadius: d => d.radius,
      getFillColor: d => d.color,
      radiusUnits: 'meters',
      opacity: 0.8
    });

    // MapLibre上にdeck.glレイヤを統合
    const overlay = new deck.MapboxOverlay({
      interleaved: true,
      layers: [scatterLayer]
    });
    map.addControl(overlay);

    // 背景スタイルを切り替える例
    // map.setStyle('https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json');
  </script>
</body>
</html>

確認ポイント

このサンプルを実行すると、次のような動作が確認できます。

  • 背景地図はMapLibreのベクトルスタイルで描画される
  • deck.glの散布図レイヤ(赤と青の点)が地図上に重ねて表示される
  • ズーム・回転・傾斜操作に対して、deck.glレイヤが自動で同期する
  • 背景スタイルを切り替えてもdeck.glレイヤは保持される

背景スタイルを切り替える例

MapLibreはスタイルをJSON単位で管理しており、
map.setStyle() を使うことで簡単に地図テーマを変更できます。

// 地図のスタイルをダークテーマに切り替える
map.setStyle('https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json');

このように、MapLibreを組み合わせることでdeck.glの描画性能を活かしつつ、柔軟な地図表現を実現できます。

MapLibreを利用する利点

MapLibreを組み合わせることで、
deck.gl単体では実現できなかった“地図らしい操作性と表現力”を得ることができます。
ここでは、実際の利用シーンで効果が大きい5つの利点を整理します。

カメラ同期による一体的な操作感

MapLibreはカメラパラメータを共有し、deck.glレイヤが自動で追随する。
ズームや傾斜操作を行っても、背景と可視化が滑らかに同期して再描画されます。

map.setPitch(45) のようにカメラを傾けても、
deck.gl側のレイヤは同じ視点で再投影されます。
これにより、背景とデータが一体となった操作体験が実現します。

ベクトルスタイルによる柔軟な背景制御

MapLibreはベクトルスタイルを採用しており、背景デザインを柔軟に制御できる。
色・フォント・道路幅などをスタイルJSONで定義でき、
map.setStyle() を使えばライトモードやダークモードなどの切り替えも簡単です。

deck.gl側はWebGLコンテキストを共有しているため、
背景スタイルを切り替えてもレイヤが再初期化されることはありません。

ラベルや注記との自然な共存

ベクトルタイルの注記は独立レイヤとして描画され、データとの前後関係を制御できる。
deck.gl単体では、ラベルが背景タイル画像に焼き込まれるため、
データと重なると読みづらくなる問題があります。
MapLibreでは地名や道路名が動的に再描画され、
データと注記の両立が自然な状態で保たれます。

地図UIとの統合

MapLibre標準のUIコントロールをそのまま利用できる。
ズームボタン、スケールバー、ロケーションコントロールなどが提供されており、
deck.glレイヤと同じWebGLキャンバス上で動作します。
そのため、地図アプリのようなUIを簡単に構成できます。

例:
map.addControl(new maplibregl.NavigationControl());
map.addControl(new maplibregl.ScaleControl());

統合WebGLによる高パフォーマンス

両者は同一のWebGLコンテキストを共有し、1枚のキャンバスで統合描画される。
背景と可視化レイヤを同時描画できるため、余計なコンポジット処理を回避できます。

この構成は、複数レイヤ(道路・建物・Scatterplot・Polygonなど)を同時に重ねる場合でも
高いパフォーマンスを発揮します。

これらの利点により、MapLibre × deck.glの組み合わせは
単なる可視化ではなく、地図としての体験を伴う可視化を実現します。

deck.gl単体構成との比較

ここでは、deck.gl単体構成とMapLibre × deck.gl構成を並べて比較し、
両者の違いを具体的に整理します。

機能面での比較

観点 deck.gl単体構成 MapLibre × deck.gl構成
背景 静的タイル(画像) ベクトルスタイル(道路・建物・注記を含む)
カメラ制御 viewState を手動管理 MapLibreのカメラと自動同期
スタイル変更 タイルURLを変更 map.setStyle() で即時切替
注記・ラベル タイル画像に埋め込み ベクトルレイヤとして描画(制御可能)
UI操作 独自実装が必要 MapLibre標準UIを利用可能
パフォーマンス 背景と別Canvasで描画 同一WebGLコンテキストで統合描画

deck.gl単体構成では、データ可視化そのものは高性能ですが、
背景地図との一体感や操作性の面で制約がありました。
MapLibreを組み合わせることで、
可視化レイヤがズームや回転と自然に同期し、背景の表現力も高まります。


deck.gl単体構成(静的タイル使用)

// 背景タイル(静的画像)
new deck.TileLayer({
  data: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
  renderSubLayers: props => new deck.BitmapLayer(props, {
    image: props.data,
    bounds: props.tile.bbox
  })
})

// 散布図レイヤ
new deck.ScatterplotLayer({
  data: [
    { position: [139.7671, 35.6812], color: [255, 0, 0], radius: 100 },
    { position: [139.75, 35.68], color: [0, 128, 255], radius: 80 }
  ],
  getPosition: d => d.position,
  getRadius: d => d.radius,
  getFillColor: d => d.color,
  radiusUnits: 'meters'
})

MapLibre × deck.gl構成(統合描画)

// MapLibreの初期化
const map = new maplibregl.Map({
  container: 'map',
  style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
  center: [139.7671, 35.6812],
  zoom: 12
});

// deck.glレイヤをMapLibreに統合
const overlay = new deck.MapboxOverlay({
  layers: [
    new deck.ScatterplotLayer({
      data: [
        { position: [139.7671, 35.6812], color: [255, 0, 0], radius: 100 },
        { position: [139.75, 35.68], color: [0, 128, 255], radius: 80 }
      ]
    })
  ]
});
map.addControl(overlay);

両者を比較すると、MapLibre構成では MapboxOverlay を介して
MapLibreの描画コンテキストにdeck.glレイヤを統合している点が大きな違いです。

この構成により、地図背景とデータが同一のWebGLパイプライン上で扱われ、
ズーム・傾斜・スタイル変更などの操作にも滑らかに追随します。

さらに活用するには

MapLibre × deck.glの連携構成を理解したら、
次は地図アプリとしての応用に広げてみましょう。
deck.glの柔軟なレイヤ表現とMapLibreのスタイル制御を組み合わせることで、
高度な可視化やインタラクションを容易に実現できます。

データ種別を拡張する

ScatterplotLayer のほかにも、deck.glには多様なレイヤが用意されています。

  • GeoJsonLayer:行政界・道路・建物などのポリゴン描画
  • ArcLayer:都市間の移動や接続関係を曲線で表現
  • HeatmapLayer:密度分布を色のグラデーションで可視化
  • PathLayer:経路・軌跡・ルート表示

これらをMapLibre上に重ねれば、背景と統一感のある地理可視化が可能です。

// GeoJSONデータを読み込み、ポリゴンを描画
const geojsonLayer = new deck.GeoJsonLayer({
  id: 'geojson-layer',
  data: 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json',
  filled: true,
  stroked: true,
  getFillColor: [255, 200, 0, 120],
  getLineColor: [80, 80, 80],
  lineWidthMinPixels: 1,
  pickable: true,
  onHover: info => {
    const { object } = info;
    if (object) {
      console.log(`Hovered: ${object.properties.name || '(no name)'}`);
    }
  }
});

// MapLibre上のoverlayに追加
overlay.setProps({ layers: [geojsonLayer] });

上記geojsonデータは deck.gl 公式提供の
vancouver-blocks.json(バンクーバー市の街区ポリゴン) です。
中心座標はおおよそ 経度 -123.1207、緯度 49.2827 で、
この付近に GeoJSON の街区データが配置されています。

d231a2790cdb3797bc9d-1.png

スタイル切り替えでテーマを変更する

MapLibreでは map.setStyle() により、
OSMベースのスタイルをダーク/ライトなどへ動的に切り替えできます。

// 地図をダークテーマに切り替える
map.setStyle('https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json');

// deck.glレイヤ側の色調も変更して統一
overlay.setProps({
  layers: [
    new deck.ScatterplotLayer({
      id: 'scatter-layer-dark',
      data: [
        { position: [139.7671, 35.6812], color: [255, 160, 0], radius: 100 },
        { position: [139.75, 35.68], color: [0, 200, 255], radius: 80 }
      ],
      getPosition: d => d.position,
      getRadius: d => d.radius,
      getFillColor: d => d.color,
      opacity: 0.9
    })
  ]
});

レイヤ側の色調(例:getFillColor)を合わせて変更すれば、
UI全体のトーンを統一できます。

UIコントロールを追加する

MapLibreのナビゲーションやスケールバーはそのまま利用可能です。

// ナビゲーションコントロール(ズーム・回転ボタン)
map.addControl(new maplibregl.NavigationControl());

// スケールバー(距離スケール表示)
map.addControl(new maplibregl.ScaleControl({ maxWidth: 150 }));

// 現在地ボタン(ユーザー位置を追跡)
map.addControl(new maplibregl.GeolocateControl({
  positionOptions: { enableHighAccuracy: true },
  trackUserLocation: true
}));

地図の基本的な操作機能を追加できます。

まとめ

本記事では、deck.gl単体での地理可視化から一歩進めて、
MapLibreと組み合わせた統合的な地図表現を解説しました。

主なポイントを整理すると次のとおりです。

  • deck.glは単体でも緯度経度を扱い、地理座標を可視化できる
  • しかし、背景地図やラベル、スタイルなど「地図らしさ」を再現するにはMapLibreとの連携が効果的
  • MapboxOverlayを介して統合することで、同一WebGLコンテキスト上で描画が可能
  • ベクトルスタイルの地図とdeck.glレイヤが同期して動くため、自然な地図操作が可能
  • スタイル変更やUIコントロール、GeoJSON連携など、拡張の自由度が高い

この構成を理解すれば、単なるデータプロットからだけでなく、
地図アプリケーションとして可視化することができるようになります。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?