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?

【初心者向け】ZENRIN Maps APIでウィジェットの表示順序(z-index)の変更方法

Last updated at Posted at 2025-11-06

はじめに

本記事では、ZENRIN Maps API のウィジェットや図形を表示する際の「表示順序(z-index)」の制御方法について解説します。
地図上に複数の図形やウィジェット(例: 配達可能エリアのポリゴン、配達ルートのポリライン、配送先のマーカー、注文情報のポップアップ)を配置した場合、重要な情報を手前に表示するために z-index の設定が重要になります。

この記事でできること

  • ZENRIN Maps APIで地図を描画
    複数ウィジェットの重なり順序の制御
  • Polygon(ポリゴン)、Polyline(ポリライン)、Marker(マーカー)、Popup(ポップアップ)の z-index 設定
  • z-index を動的に変更できる UI の作成

APIキーの取得手順

ZENRIN Maps API を利用するには、事前に APIキーの取得が必要です。

現在、ZENRIN Maps API は 2か月間の無料トライアルが用意されており、期間中は主要な機能を実際にお試しいただけます。開発や評価の初期段階でも安心してご利用いただけます。

APIキーの取得方法については、以下の記事で詳しく解説されています。
初めての方は、まずこちらをご覧いただき、APIキーの発行と設定を行ってください。

ZENRIN Maps APIの始め方

公式リファレンス

実装イメージ(例: 配達サービスの動線管理)

今回は例として「配達サービス」を想定し、以下の情報を地図上に配置して表示順序を制御します。

  • 🏪 配達可能エリア(Polygon)
  • 🛣️ 配達ルート(Polyline)
  • 🏠 配送先(Marker)
  • 📋 注文情報(Popup)

⚠️ 注意
図形クラス(Polygon / Polyline)とウィジェットクラス(Marker / Popup)間では、z-index の重なり順序は保証されません。
そのため同一クラス間での制御を前提としてください。

ファイル構成

project/
├── index.html          # メインHTML
├── css/
   └── zma_zindex.css  # スタイルシート
└── js/
    └── zma_zindex.js   # JavaScript

サンプルコード

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <title>配達サービス動線管理のz-index制御デモ</title>
 <script src="https://test-js.zmaps-api.com/zma_loader.js?key=[APIキー]&auth=referer"></script>
 <link rel="stylesheet" href="css/zma_zindex.css">
</head>
<body>
 <div id="ZMap">
   <div class="control-panel">
     <h3>🚚 配達サービス動線管理</h3>
     <div class="scenario-info">
       <strong>シナリオ:</strong> 飲食店の配達可能エリア、配達ルート、配送先、注文情報の表示順序を制御<br>
       <strong>目的:</strong> 重要な情報ほど手前に表示し、効率的な配達管理を実現<br>
       <strong>注意:</strong> 図形クラス(Polygon/Polyline)とウィジェットクラス(Marker/Popup)間では、z-indexの重なり順序は保証されません
     </div>
     
     <div class="widget-control area" data-widget="polygon">
       <label>🏪 配達可能エリア (Polygon)</label>
       <div class="z-index-buttons">
         <button onclick="setPolygonZIndex(99)">99</button>
         <button onclick="setPolygonZIndex(100)" class="active">100</button>
         <button onclick="setPolygonZIndex(101)">101</button>
         <button onclick="setPolygonZIndex(102)">102</button>
         <button onclick="setPolygonZIndex(103)">103</button>
       </div>
       <div class="info-text">現在: 100 (背景情報)</div>
     </div>
     
     <div class="widget-control route" data-widget="polyline">
       <label>🛣️ 配達ルート (Polyline)</label>
       <div class="z-index-buttons">
         <button onclick="setPolylineZIndex(99)">99</button>
         <button onclick="setPolylineZIndex(100)">100</button>
         <button onclick="setPolylineZIndex(101)" class="active">101</button>
         <button onclick="setPolylineZIndex(102)">102</button>
         <button onclick="setPolylineZIndex(103)">103</button>
       </div>
       <div class="info-text">現在: 101 (ルート情報)</div>
     </div>
     
     <div class="widget-control destination" data-widget="marker">
       <label>🏠 配送先 (Marker)</label>
       <div class="z-index-buttons">
         <button onclick="setMarkerZIndex(99)">99</button>
         <button onclick="setMarkerZIndex(100)">100</button>
         <button onclick="setMarkerZIndex(101)">101</button>
         <button onclick="setMarkerZIndex(102)" class="active">102</button>
         <button onclick="setMarkerZIndex(103)">103</button>
       </div>
       <div class="info-text">現在: 102 (配送先)</div>
     </div>
     
     <div class="widget-control info" data-widget="popup">
       <label>📋 注文情報 (Popup)</label>
       <div class="z-index-buttons">
         <button onclick="setPopupZIndex(99)">99</button>
         <button onclick="setPopupZIndex(100)">100</button>
         <button onclick="setPopupZIndex(101)">101</button>
         <button onclick="setPopupZIndex(102)">102</button>
         <button onclick="setPopupZIndex(103)" class="active">103</button>
       </div>
       <div class="info-text">現在: 103 (注文詳細)</div>
     </div>
   </div>
 </div>

 <script src="js/zma_zindex.js"></script>
</body>
</html>
zma_zindex.css
body { margin: 0; padding: 0; font-family: Arial, sans-serif; }
#ZMap { 
 position: relative; 
 width: 100vw; 
 height: 100vh; 
 border: none; 
}

.control-panel {
 position: absolute;
 top: 10px;
 left: 10px;
 background: rgba(255, 255, 255, 0.95);
 padding: 15px;
 border-radius: 8px;
 box-shadow: 0 2px 10px rgba(0,0,0,0.3);
 z-index: 1000;
 max-width: 350px;
}

.control-panel h3 {
 margin: 0 0 10px 0;
 font-size: 16px;
 color: #2e7d32;
}

.widget-control {
 margin-bottom: 10px;
 padding: 8px;
 background: #f5f5f5;
 border-radius: 4px;
 border-left: 4px solid #ccc;
}

.widget-control.area {
 border-left-color: #4caf50;
 background: #e8f5e8;
}

.widget-control.route {
 border-left-color: #2196f3;
 background: #e3f2fd;
}

.widget-control.destination {
 border-left-color: #ff9800;
 background: #fff3e0;
}

.widget-control.info {
 border-left-color: #9c27b0;
 background: #f3e5f5;
}

.widget-control label {
 display: block;
 font-weight: bold;
 margin-bottom: 5px;
 font-size: 12px;
}

.z-index-buttons {
 display: flex;
 gap: 5px;
 flex-wrap: wrap;
}

.z-index-buttons button {
 padding: 4px 8px;
 font-size: 11px;
 border: 1px solid #ccc;
 background: white;
 cursor: pointer;
 border-radius: 3px;
}

.z-index-buttons button:hover {
 background: #e0e0e0;
}

.z-index-buttons button.active {
 background: #007bff;
 color: white;
 border-color: #007bff;
}

.info-text {
 font-size: 11px;
 color: #666;
 margin-top: 5px;
}

.scenario-info {
 font-size: 11px;
 color: #444;
 margin: 8px 0 12px 0;
 line-height: 1.5;
 background: #e8f5e8;
 padding: 8px;
 border-radius: 4px;
 border: 1px solid #4caf50;
}
zma_zindex.js
var map, polygon, polygonBase, polyline, polylineBase, markers = [], popups = [];

// 中心点の緯度経度(東京駅周辺)
const lat = 35.681406, lng = 139.749132;

ZMALoader.setOnLoad(function (mapOptions, error) {
 if (error) {
   console.error(error);
   return;
 }

 // マップオプションを設定
 mapOptions.center = new ZDC.LatLng(lat, lng);
 mapOptions.zoom = 14;

 // 地図を生成
 map = new ZDC.Map(
   document.getElementById('ZMap'),
   mapOptions,
   function() {
     // Success callback
     createDeliveryInfo();
   },
   function() {
     console.error('Map creation failed');
   }
 );
});

function createDeliveryInfo() {
 // 配達可能エリア (Polygon) - 飲食店の配達エリア
 var deliveryArea = [];
 deliveryArea.push(new ZDC.LatLng(35.6607694489887, 139.7419563985648));
 deliveryArea.push(new ZDC.LatLng(35.6845229143682, 139.7286721190967));
 deliveryArea.push(new ZDC.LatLng(35.7057395047171, 139.7473525622848));
 deliveryArea.push(new ZDC.LatLng(35.7032096194981, 139.7793172849411));
 deliveryArea.push(new ZDC.LatLng(35.6794617174330, 139.7926015644093));
 deliveryArea.push(new ZDC.LatLng(35.6582381374606, 139.7739211212211));
 deliveryArea.push(new ZDC.LatLng(35.6607694489887, 139.7419563985648));
 
 // 配達エリアのベース(緑)
 polygonBase = new ZDC.Polygon(deliveryArea, {
   fill: '#4caf50',
   strokeWidth: 1,
   opacity: 0.3
 });
 map.addWidget(polygonBase);
 polygonBase.setZIndex(99);

 // 配達エリアのメイン(緑)
 polygon = new ZDC.Polygon(deliveryArea, {
   fill: '#4caf50',
   strokeWidth: 2,
   opacity: 0.6
 });
 map.addWidget(polygon);
 polygon.setZIndex(100);

 // 配達ルート (Polyline) - 最適な配達経路(polygon内に配置)
 var deliveryRoutes = [];
 deliveryRoutes.push(new ZDC.LatLng(35.67, 139.75));  // polygon内の点1
 deliveryRoutes.push(new ZDC.LatLng(35.68, 139.77));  // polygon内の点2
 deliveryRoutes.push(new ZDC.LatLng(35.69, 139.76));  // polygon内の点3
 deliveryRoutes.push(new ZDC.LatLng(35.70, 139.75));  // polygon内の点4
 deliveryRoutes.push(new ZDC.LatLng(35.67, 139.75));  // 始点に戻る
 
 // 配達ルートのベース(青)
 polylineBase = new ZDC.Polyline(deliveryRoutes, {
   color: '#2196f3',
   width: 6
 });
 map.addWidget(polylineBase);
 polylineBase.setZIndex(100);

 // 配達ルートのメイン(青)
 polyline = new ZDC.Polyline(deliveryRoutes, {
   color: '#2196f3',
   width: 4
 });
 map.addWidget(polyline);
 polyline.setZIndex(101);

 // 配送先 (Marker) - polylineの各接続点に表示
 var markerPositions = [
   new ZDC.LatLng(35.67, 139.75),  // 点1
   new ZDC.LatLng(35.68, 139.77),  // 点2
   new ZDC.LatLng(35.70, 139.75)   // 点3
 ];
 
 // 各接続点にマーカーを作成
 for (var i = 0; i < markerPositions.length; i++) {
   var marker = new ZDC.Marker(markerPositions[i]);
   map.addWidget(marker);
   marker.setZIndex(102);
   markers.push(marker);  // 配列に追加
 }

 // 注文情報 (Popup) - 各接続点に表示(始点は除く)
 var popupPositions = [
   new ZDC.LatLng(35.68, 139.77),  // 点2
   new ZDC.LatLng(35.69, 139.76),  // 点3
 ];
 
 var popupContents = [
   '<div style="padding: 8px; background: #f3e5f5; border: 2px solid #9c27b0; border-radius: 6px; color: #4a148c; font-size: 11px; min-width: 120px;"><strong>📋 注文1</strong><br>🍕 ピザ マルゲリータ<br>⏰ 18:30</div>',
   '<div style="padding: 8px; background: #f3e5f5; border: 2px solid #9c27b0; border-radius: 6px; color: #4a148c; font-size: 11px; min-width: 120px;"><strong>📋 注文2</strong><br>🍜 ラーメン 醤油<br>⏰ 18:45</div>',
 ];
 
 // 各接続点にポップアップを作成
 var popupOffsets = [
   new ZDC.Point(0, -20),   // 点2のオフセット(上に20px)
   new ZDC.Point(-90, 280),  // 点3のオフセット(左に30px、上に20px)
 ];
 
 for (var i = 0; i < popupPositions.length; i++) {
   var popup = new ZDC.Popup(
     popupPositions[i],
     {
       htmlSource: popupContents[i],
       offset: popupOffsets[i],
       propagation: true
     }
   );
   map.addWidget(popup);
   popup.setZIndex(103);
   popups.push(popup);  // 配列に追加
 }
}

// z-index変更関数
function setPolygonZIndex(zIndex) {
 polygon.setZIndex(zIndex);
 updateButtonStates('polygon', zIndex);
}

function setPolylineZIndex(zIndex) {
 polyline.setZIndex(zIndex);
 updateButtonStates('polyline', zIndex);
}

function setMarkerZIndex(zIndex) {
 // 全てのマーカーのz-indexを変更
 for (var i = 0; i < markers.length; i++) {
   markers[i].setZIndex(zIndex);
 }
 updateButtonStates('marker', zIndex);
}

function setPopupZIndex(zIndex) {
 // 全てのポップアップのz-indexを変更
 for (var i = 0; i < popups.length; i++) {
   popups[i].setZIndex(zIndex);
 }
 updateButtonStates('popup', zIndex);
}

function updateButtonStates(widgetType, activeZIndex) {
 // 指定されたウィジェットのコントロールのみを更新
 const control = document.querySelector(`.widget-control[data-widget="${widgetType}"]`);
 if (!control) return;
 
 const buttons = control.querySelectorAll('.z-index-buttons button');
 const infoText = control.querySelector('.info-text');
 
 buttons.forEach(button => {
   button.classList.remove('active');
   if (parseInt(button.textContent) === activeZIndex) {
     button.classList.add('active');
   }
 });
 
 if (infoText) {
   infoText.textContent = `現在: ${activeZIndex}`;
 }
}

コードを実行した結果です。
※図形クラスのポリライン(Polyline)とウィジェットクラスの(Popup)が最上位
zindex_default.png

図形クラスのポリゴン(Polygon)とウィジェットクラスのマーカー(Marker)を最上位に変更
zindex_update.png

ステップ毎の解説

Step 1:HTML の基本構造と ZENRIN Maps API の読み込み

<script src="https://test-js.zmaps-api.com/zma_loader.js?key=YOUR_API_KEY&auth=referer"></script>
<link rel="stylesheet" href="css/zma_zindex.css" />
<script src="js/zma_zindex.js" defer></script>
  • zma_loader.js で ZENRIN Maps API を読み込む。
  • css/zma_zindex.css でマップとコントロールパネルのスタイルを設定。
  • js/zma_zindex.js でマップ描画と z-index 制御のロジックを記述。
  • defer を付けることで DOM が読み込まれてからスクリプトを実行。

Step 2:地図描画用の HTML 要素とコントロールパネル

<div id="ZMap">
  <div class="control-panel">
    <h3>🚚 配達サービス動線管理</h3>
    <div class="scenario-info">...</div>
    <div class="widget-control area" data-widget="polygon">...</div>
    <div class="widget-control route" data-widget="polyline">...</div>
    <div class="widget-control destination" data-widget="marker">...</div>
    <div class="widget-control info" data-widget="popup">...</div>
  </div>
</div>
  • #ZMap が地図描画領域。
  • .control-panel 内に、各ウィジェット(Polygon/Polyline/Marker/Popup)の z-index を変更するボタンと情報表示を配置。
  • data-widget 属性で種類を判別。

Step 3:CSS でのスタイル設定

#ZMap {
  position: relative;
  width: 100vw;
  height: 100vh;
}
.control-panel {
  position: absolute;
  top: 10px;
  left: 10px;
  background: rgba(255, 255, 255, 0.95);
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.3);
  z-index: 1000;
  max-width: 350px;
}
.widget-control.area { border-left-color: #4caf50; background: #e8f5e8; }
.widget-control.route { border-left-color: #2196f3; background: #e3f2fd; }
  • マップは画面全体表示。
  • コントロールパネルは地図上に重ねる形で固定。
  • .widget-control ごとに色分けして視覚的に識別。
  • ボタンには .active で現在の z-index を強調。

Step 4:JavaScript:地図の初期化

const lat = 35.681406, lng = 139.767132;

ZMALoader.setOnLoad(function(mapOptions, error) {
  if (error) {
    console.error(error);
    return;
  }

  mapOptions.center = new ZDC.LatLng(lat, lng);
  mapOptions.zoom = 14;

  map = new ZDC.Map(document.getElementById('ZMap'), mapOptions, function () {
    createDeliveryInfo();
  });
});
  • 東京駅付近を地図の中心に設定。
  • ズームレベル 14 で初期表示。
  • createDeliveryInfo() を呼んで Polygon, Polyline, Marker, Popup を作成。

Step 5:配達可能エリア(Polygon)の追加

var deliveryArea = [
  deliveryArea.push(new ZDC.LatLng(35.6607694489887, 139.7419563985648));
  ...
];

polygonBase = new ZDC.Polygon(deliveryArea, { fill: '#4caf50', strokeWidth: 1, opacity: 0.3 });
map.addWidget(polygonBase);
polygonBase.setZIndex(99);

polygon = new ZDC.Polygon(deliveryArea, { fill: '#4caf50', strokeWidth: 2, opacity: 0.6 });
map.addWidget(polygon);
polygon.setZIndex(100);
  • 背景情報として polygonBase(薄い色、Z=99)。
  • 手前に表示する主要 Polygon polygon(濃い色、Z=100)。
  • setZIndex() で重なり順序を制御。

Step 6:配達ルート(Polyline)の追加

var deliveryRoutes = [
  deliveryRoutes.push(new ZDC.LatLng(35.67, 139.75));  // polygon内の点1
  ...
];

polylineBase = new ZDC.Polyline(deliveryRoutes, { color: '#2196f3', width: 6 });
map.addWidget(polylineBase);
polylineBase.setZIndex(100);

polyline = new ZDC.Polyline(deliveryRoutes, { color: '#2196f3', width: 4 });
map.addWidget(polyline);
polyline.setZIndex(101);
  • 太線 Polyline を下に敷き、細線 Polyline を上に表示。
  • ルートの視認性と前後関係を z-index で調整。

Step 7:配送先(Marker)の追加

var markerPositions = [
    new ZDC.LatLng(35.67, 139.75),  // 点1
  ...
];

for (var i = 0; i < markerPositions.length; i++) {
    var marker = new ZDC.Marker(markerPositions[i]);
    map.addWidget(marker);
    marker.setZIndex(102);
    markers.push(marker);  // 配列に追加
  }
  • 配送先を地図上にマーカーで表示。
  • Polygon/Polyline より前面に表示するため Z=102。

Step 8:注文情報(Popup)の追加

var popupPositions = [
   new ZDC.LatLng(35.68, 139.77),  // 点2
   new ZDC.LatLng(35.69, 139.76),  // 点3
 ];

  var popupContents = [
    '<div style="padding: 8px; background: #f3e5f5; border: 2px solid #9c27b0; border-radius: 6px; color: #4a148c; font-size: 11px; min-width: 120px;"><strong>📋 注文1</strong><br>🍕 ピザ マルゲリータ<br>⏰ 18:30</div>',
    '<div style="padding: 8px; background: #f3e5f5; border: 2px solid #9c27b0; border-radius: 6px; color: #4a148c; font-size: 11px; min-width: 120px;"><strong>📋 注文2</strong><br>🍜 ラーメン 醤油<br>⏰ 18:45</div>',
  ];
  
  // 各接続点にポップアップを作成
  var popupOffsets = [
    new ZDC.Point(0, -20),   // 点2のオフセット(上に20px)
    new ZDC.Point(-90, 280),  // 点3のオフセット(左に30px、上に20px)
  ];
  
  for (var i = 0; i < popupPositions.length; i++) {
    var popup = new ZDC.Popup(
      popupPositions[i],
      {
        htmlSource: popupContents[i],
        offset: popupOffsets[i],
        propagation: true
      }
    );
    map.addWidget(popup);
    popup.setZIndex(103);
    popups.push(popup);  // 配列に追加
  }
  • 注文情報は Popup で表示。
  • 最前面に配置(Z=103)。
  • 配置位置やオフセットも調整可能。

Step 9:z-index を変更する関数

function setPolygonZIndex(zIndex) { polygon.setZIndex(zIndex); updateButtonStates('polygon', zIndex); }
function setPolylineZIndex(zIndex) { polyline.setZIndex(zIndex); updateButtonStates('polyline', zIndex); }
function setMarkerZIndex(zIndex) { marker.setZIndex(zIndex); updateButtonStates('marker', zIndex); }
function setPopupZIndex(zIndex) { popups.forEach(p => p.setZIndex(zIndex)); updateButtonStates('popup', zIndex); }
  • 各ウィジェットの z-index を変更。
  • ボタンのアクティブ状態も同時に更新。

Step 10:ボタン状態の更新

function updateButtonStates(widgetType, activeZIndex) {
  const control = document.querySelector(`.widget-control[data-widget="${widgetType}"]`);
  const buttons = control.querySelectorAll('.z-index-buttons button');
  const infoText = control.querySelector('.info-text');

  buttons.forEach(button => {
    button.classList.remove('active');
    if (parseInt(button.textContent) === activeZIndex) button.classList.add('active');
  });

  if (infoText) infoText.textContent = `現在: ${activeZIndex}`;
}
  • ボタン UI を操作して、どの z-index が選択されているかを反映。
  • ユーザーに現在の表示順序をわかりやすく提示。

おわりに

今回のサンプルでは、Polygon(ポリゴン)、Polyline(ポリライン)、Marker(マーカー)、Popup(ポップアップ) という複数の地図ウィジェットを z-index で重なり順を制御 する方法を紹介しました。
ポイントは以下の通りです:

  • 情報の重要度に応じて表示順序を整理
  • コントロールパネルのボタン操作で即座に変更可能
  • 背景情報と前面情報を視覚的に区別して管理

この手法は、配達管理だけでなく、災害対応マップやイベント会場マップなど、多層情報を扱う地図アプリ でも応用できます。
特に、複数の情報レイヤーをユーザーが自由に入れ替えて確認できる UI を作る場合に便利です。

地図上の情報を より直感的で効率的に見せる工夫 の第一歩として、今回の z-index 制御の考え方を参考にしてみてください。

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?