ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
English
MapLibre GL JS でカスタムマーカーがズーム時にずれる問題と GeoJSON レイヤーによる解決

MapLibre GL JS でカスタムマーカーがズーム時にずれる問題と GeoJSON レイヤーによる解決

はじめに MapLibre GL JS で地図上にカスタムマーカーを配置する際、maplibregl.Marker に独自の DOM 要素を渡す方法がよく使われる。件数バッジ付きの丸いマーカーなど、CSS で自由にスタイリングできる利点がある。 しかし、この方法にはズーム・パン操作時にマーカーが地図の動きに遅れて追従するという問題がある。特にマーカー数が多い場合やモバイルデバイスでは顕著になり、ズームアウトすると本来陸上にあるべきマーカーが海上に表示されるような視覚的な不整合も起きる。 本記事では、この問題の原因と、GeoJSON ソース + レイヤーを使った根本的な解決方法を解説する。 問題の再現 DOM マーカーによる実装(問題あり) for (const point of dataPoints) { const el = document.createElement('div') Object.assign(el.style, { width: '32px', height: '32px', borderRadius: '50%', backgroundColor: point.color, border: '3px solid white', boxShadow: '0 2px 6px rgba(0,0,0,0.3)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', }) // 件数バッジ if (point.count > 1) { const badge = document.createElement('span') badge.style.color = 'white' badge.style.fontSize = '11px' badge.style.fontWeight = 'bold' badge.textContent = String(point.count) el.appendChild(badge) } new maplibregl.Marker({ element: el }) .setLngLat([point.lng, point.lat]) .addTo(map) } この実装では以下の問題が発生する。 症状 ズーム・パン時の遅延: マーカーが地図の動きに 1〜2 フレーム遅れて追従する ズームアウト時の位置ずれ: 沿岸都市のマーカーが海上に表示される パフォーマンス低下: マーカー数が増えると DOM の再配置コストが増大する 原因 maplibregl.Marker は DOM 要素を CSS transform で配置する仕組みになっている。地図がズーム・パンされるたびに、各マーカーの CSS transform を再計算して更新する必要があり、これが WebGL キャンバスの描画と非同期で行われるため、視覚的なずれが生じる。 ...

IIIF Georeference to XYZ Tiles

IIIF Georeference to XYZ Tiles

IIIF Georeference Extension JSONからXYZタイルを生成し、MapLibre GL JSで表示するツール。 リポジトリ : https://github.com/nakamura196/iiif-georef-tiles GitHub Pages : https://nakamura196.github.io/iiif-georef-tiles/ 必要環境 Python 3.x GDAL (gdal_translate, gdalwarp, gdal2tiles.py) GDALのインストール # macOS (Homebrew) brew install gdal # Ubuntu/Debian sudo apt install gdal-bin python3-gdal 使用方法 python3 scripts/iiif_georef_to_tiles.py <IIIF_GEOREF_JSON_URL> 例 python3 scripts/iiif_georef_to_tiles.py https://nakamura196.github.io/iiif_geo/canvas.json オプション オプション デフォルト 説明 --scale 0.25 画像の縮小率 --zoom 14-18 タイルのズームレベル範囲 --output-dir docs 出力ディレクトリ --name tiles タイルフォルダ名 --work-dir work 作業用ディレクトリ --keep-work - 作業用ファイルを削除しない 処理の流れ IIIF Georeference JSON │ ▼ ┌───────────────────────┐ │ 1. JSONを取得 │ │ (URLからfetch) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 2. 画像をダウンロード │ │ (IIIF Image API) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 3. GCPを埋め込み │ │ (gdal_translate) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 4. 座標変換 │ │ (gdalwarp) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 5. タイル生成 │ │ (gdal2tiles.py) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 6. HTMLビューア生成 │ │ (MapLibre GL JS) │ └───────────────────────┘ 変換結果 元画像 地理参照後 出力ファイル docs/ ├── index.html # MapLibre GL JSビューア ├── source.json # 元のIIIF Georeference JSON └── tiles/ # XYZタイル ├── 14/ ├── 15/ ├── 16/ ├── 17/ └── 18/ ローカルで確認 cd docs && python3 -m http.server 8000 # http://localhost:8000/ を開く IIIF Georeference Extension IIIF Georeference Extensionは、IIIF画像に地理参照情報を付与するための拡張仕様です。 ...

IIIF Georeference ViewerのMapLibre GL移行と機能改善

IIIF Georeference ViewerのMapLibre GL移行と機能改善

本記事はAIが作成し、人間が追記しました。 概要 IIIF Georeference ViewerにおけるマップコンポーネントをLeafletからMapLibre GLへ移行し、複数の機能改善を実施しました。本記事では、実装した主要な機能とその技術的詳細について説明します。 https://nakamura196.github.io/iiif_geo/ 主要な改善点 1. 画像の自動回転機能 IIIF画像を地図上に正しい向きで表示するため、コントロールポイント(対応点)から自動的に回転角度を計算する機能を実装しました。 機能概要 画像座標と地理座標の対応点から、画像を北が上になるように回転させる角度を自動計算 2点間または3点以上の分布パターンから最適な回転角度を決定 URLパラメータによる回転角度の保存と復元 実装のポイント // utils/calculateImageRotation.ts export function calculateImageRotation(features: Feature[]): RotationCalculationResult | null { // 最も離れた2点を見つける(より正確な角度計算のため) const validFeatures = features.filter((f) => f.properties?.resourceCoords && f.geometry?.coordinates ); // 画像座標系でのベクトルと地理座標系でのベクトルから回転角度を計算 const imgVector = { x: img2.x - img1.x, y: img2.y - img1.y }; const geoVector = { x: geo2.lng - geo1.lng, y: geo2.lat - geo1.lat }; // 北を基準とした角度の差を計算 const rotationDeg = geoAngleFromNorthDeg - imgAngleDeg; return normalizeAngle(rotationDeg); } UI実装 自動回転ボタン(🔧アイコン)をOSDビューアーに配置 rotationパラメータが未指定の場合は自動的に回転角度を計算 手動での角度調整用スライダーも提供 2. LeafletからMapLibre GLへの移行 移行の背景 パフォーマンス向上 : MapLibre GLはWebGLベースのレンダリングにより、大量のマーカー表示時のパフォーマンスが向上 スムーズなアニメーション : 地図の移動やズーム時のアニメーションがより滑らかに ベクタータイルのサポート : ラスタータイルに加えてベクタータイルの表示が可能 実装のポイント import { Map, NavigationControl, Marker, Popup } from "maplibre-gl"; import "maplibre-gl/dist/maplibre-gl.css"; const mapInstance = ref<Map | null>(null); // MapLibre GL初期化 mapInstance.value = new Map({ container: mapContainer.value!, style: mapStyles.value[0].style, center: initialCenter, zoom: zoom_.value, attributionControl: false }); 3. 現在地表示機能 ブラウザのGeolocation APIを使用して、ユーザーの現在地を地図上に表示する機能を実装しました。 ...

「れきちず x Next.js」サイトにルートの登録機能を追加しました。

「れきちず x Next.js」サイトにルートの登録機能を追加しました。

概要 「れきちず x Next.js」サイトにルートの登録機能を追加しました。以下が表示例です。 参考 「れきちず x Next.js」サイトについては、以下で紹介しています。 この「れきちず」を使ってルートを表示する先行事例として、以下が挙げられます。 https://codh.rois.ac.jp/edomi/route/ 今回は上記の事例を参考に、ルートを作成する機能を追加しました。 使い方 サイトにアクセスします。 https://rekichizu-next.vercel.app/ja/ 「マイルートを管理」をクリックします。 ログインが求められますので、画面右上のボタンからログインします。 「新しいルートを作成」から、ルートを作成します。 以下が編集画面です。 編集アイコンをクリックすると、ルートのタイトルおよび説明を編集できます。 モードを「追加」に設定すると、地図上でクリックした箇所にピンが立ちます。ドラッグ&ドロップで移動させることも可能です。 マーカーはドラッグ&ドロップで順序変更することができます。 インポートとエクスポート エクスポート ルートの一覧画面と編集画面にダウンロードボタンを設置しています。以下のようなJSONファイルがダウンロードされます。 { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "id": "1744639551563", "text": "湯島天神", "where": "神社", "type": "point" }, "geometry": { "type": "Point", "coordinates": [ 139.76809921470056, 35.707702013817155 ] } }, { "type": "Feature", "properties": { "id": "1744639379903", "text": "不忍池", "where": "池", "type": "point" }, "geometry": { "type": "Point", "coordinates": [ 139.77050681034103, 35.71210499496915 ] } }, { "type": "Feature", "properties": { "id": "1744639551563-1744639379903", "path": "[1744639551563] -> [1744639379903]", "type": "line" }, "geometry": { "type": "LineString", "coordinates": [ [ 139.76809921470056, 35.707702013817155 ], [ 139.77050681034103, 35.71210499496915 ] ] } } ] } これをgeojson.ioに貼り付けると、以下のように表示されます。 ...

れきちずをNext.jsで使用する

れきちずをNext.jsで使用する

概要 れきちずをNext.jsで使用する方法を調べてみましたので、備忘録です。 背景 以下の記事で、「れきちず」の使い方を紹介しました。 そして、2025年4月4日に「全国版が公開」されたことを知りました。 https://rekichizu.jp/ そこでNext.jsを用いて作成したアプリケーションへの導入にあたり、その使い方を調べてみました。 デモアプリ 以下のようなアプリケーションを試作しました。 https://rekichizu-next.vercel.app/ja/ 使用方法の調査にあたり、公式サイトで提供されている地図の切り替えや重ね合わせ機能、および検索機能などを再現することを目的としました。この実装にあたり、以下のReactライブラリを使用しました。 https://visgl.github.io/react-maplibre/ 開発メモ 検索機能 検索機能には、GeoLODのAPIを利用させていただきました。なお、「れきちず」の公式サイトでは、専用の検索APIが用いられているようでした。 https://geolod.ex.nii.ac.jp/doc/api/ react-maplibre 本ライブラリを使用して、やりたいことの多くを実現できました。一方、TerrainControlではTerrainのON/OFFと合わせてピッチを変更することが難しい?、useMapではaddLayer/removeLayerが難しい?など、いくつか苦労した点もありました。 まとめ 「れきちず」およびNext.jsを用いたアプリケーション開発にあたり、参考になりましたら幸いです。 「れきちず」の開発に関わる方々に深く感謝いたします。