1
1

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 で住所検索機能を実装する

Last updated at Posted at 2025-11-20

はじめに

このサンプルでは、ZENRIN Maps API の住所検索機能を利用して、入力した住所から地図上に配送先を表示する方法を紹介します。
住所を検索すると、候補リストが表示され、選択した住所の位置やエリアをマップ上で確認できます。
配送先の確認や、顧客情報の位置管理など、業務システムやWebアプリに住所検索を組み込みたい場合の参考になります。

この記事でできること

  • 住所入力フォームから住所検索を実行
  • 検索結果リストを画面に表示
  • 検索結果をクリックして地図上にピンやポリゴンを描画
  • 階層(都道府県・市区町村・大字など)に応じたエリア表示
  • 該当住所の郵便番号・住所コード・緯度経度を表示

APIキー取得手順

ZENRIN Maps API を利用するには、事前に APIキーの取得が必要です。
現在、ZENRIN Maps API は2か月間の無料トライアルが用意されており、期間中は主要な機能を実際にお試しいただけます。
開発や評価の初期段階でも安心してご利用いただけます。
APIキーの取得方法については、以下の記事で詳しく解説されています。
初めての方は、まずこちらをご覧いただき、APIキーの発行と設定を行ってください。
ZENRIN Maps APIの始め方

公式リファレンス

ファイル構成

project/
├─ zma_address_search.html
├─ css/
   └─ zma_address_search.css
└─ js/
    └─ zma_address_search.js

サンプルコード

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ZENRIN Maps API - 住所検索サンプル</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
    <link rel="stylesheet" href="css/zma_address_search.css">
</head>

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

    <div class="search-panel">
        <div class="panel-header">
            <h2><i class="fas fa-map-marked-alt"></i> 配送先住所検索</h2>
            <p>住所を入力して配送先の位置を確認できます</p>
        </div>
        <div class="panel-body">
            <div class="search-box">
                <input type="text" class="search-input" id="addressInput" placeholder="例: 東京都千代田区丸の内1丁目">
                <button class="search-button" id="searchButton">
                    <i class="fas fa-search"></i>
                </button>
            </div>

            <div class="search-info" id="searchInfo">
                <i class="fas fa-info-circle"></i>
                <span id="searchInfoText"></span>
            </div>

            <div class="error-message" id="errorMessage">
                <i class="fas fa-exclamation-triangle"></i>
                <span id="errorMessageText"></span>
            </div>

            <div class="loading" id="loading">
                <div class="spinner"></div>
                <p>検索中...</p>
            </div>

            <div class="selected-info" id="selectedInfo">
                <div class="selected-info-title">
                    <i class="fas fa-check-circle"></i>
                    選択された配送先
                </div>
                <div class="selected-info-content" id="selectedInfoContent"></div>
            </div>

            <div class="results-container" id="resultsContainer">
                <div class="results-header" id="resultsHeader"></div>
                <div id="resultsList"></div>
            </div>
        </div>
    </div>

    <script src="https://test-js.zmaps-api.com/zma_loader.js?key=YOUR_API_KEY&auth=referer"></script>
    <script src="js/zma_address_search.js"></script>
</body>
</html>
CSS(クリックで展開)
zma_address_search.css
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    height: 100vh;
    overflow: hidden;
}

/* Map container */
#ZMap {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
}

/* Search panel */
.search-panel {
    position: absolute;
    top: 20px;
    left: 20px;
    width: 400px;
    max-height: calc(100vh - 40px);
    background: white;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    z-index: 1000;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.panel-header {
    padding: 20px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
}

.panel-header h2 {
    font-size: 18px;
    margin-bottom: 5px;
}

.panel-header p {
    font-size: 12px;
    opacity: 0.9;
}

.panel-body {
    padding: 20px;
    overflow-y: auto;
    flex: 1;
}

/* Search input */
.search-box {
    position: relative;
    margin-bottom: 15px;
}

.search-input {
    width: 100%;
    padding: 12px 45px 12px 15px;
    border: 2px solid #e0e0e0;
    border-radius: 8px;
    font-size: 14px;
    transition: all 0.3s;
}

.search-input:focus {
    outline: none;
    border-color: #667eea;
    box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

.search-button {
    position: absolute;
    right: 5px;
    top: 50%;
    transform: translateY(-50%);
    background: #667eea;
    border: none;
    border-radius: 6px;
    padding: 8px 15px;
    color: white;
    cursor: pointer;
    transition: background 0.3s;
}

.search-button:hover {
    background: #5568d3;
}

.search-button:active {
    transform: translateY(-50%) scale(0.95);
}

/* Search info */
.search-info {
    background: #f8f9fa;
    padding: 12px;
    border-radius: 8px;
    margin-bottom: 15px;
    font-size: 13px;
    color: #666;
    display: none;
}

.search-info.show {
    display: block;
}

.search-info i {
    margin-right: 8px;
    color: #667eea;
}

/* Results list */
.results-container {
    display: none;
}

.results-container.show {
    display: block;
}

.results-header {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 12px;
    color: #333;
}

.result-item {
    background: #f8f9fa;
    padding: 15px;
    border-radius: 8px;
    margin-bottom: 10px;
    cursor: pointer;
    transition: all 0.3s;
    border: 2px solid transparent;
}

.result-item:hover {
    background: #e9ecef;
    border-color: #667eea;
    transform: translateX(5px);
}

.result-item.selected {
    background: #e7f3ff;
    border-color: #667eea;
}

.result-address {
    font-size: 14px;
    font-weight: 600;
    color: #333;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
}

.result-address i {
    margin-right: 8px;
    color: #667eea;
}

.result-details {
    font-size: 12px;
    color: #666;
    line-height: 1.6;
}

.result-detail-row {
    display: flex;
    margin-bottom: 4px;
}

.result-detail-label {
    min-width: 80px;
    font-weight: 600;
    color: #555;
}

.result-detail-value {
    color: #666;
}

/* Selected address info */
.selected-info {
    display: none;
    background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%);
    padding: 15px;
    border-radius: 8px;
    margin-bottom: 15px;
}

.selected-info.show {
    display: block;
}

.selected-info-title {
    font-size: 13px;
    font-weight: 600;
    color: #667eea;
    margin-bottom: 10px;
    display: flex;
    align-items: center;
}

.selected-info-title i {
    margin-right: 8px;
}

.selected-info-content {
    font-size: 13px;
    color: #333;
    line-height: 1.8;
}

/* Loading spinner */
.loading {
    display: none;
    text-align: center;
    padding: 20px;
}

.loading.show {
    display: block;
}

.spinner {
    border: 3px solid #f3f3f3;
    border-top: 3px solid #667eea;
    border-radius: 50%;
    width: 40px;
    height: 40px;
    animation: spin 1s linear infinite;
    margin: 0 auto 10px;
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(360deg);
    }
}

/* Error message */
.error-message {
    display: none;
    background: #fee;
    color: #c33;
    padding: 12px;
    border-radius: 8px;
    margin-bottom: 15px;
    font-size: 13px;
}

.error-message.show {
    display: block;
}

.error-message i {
    margin-right: 8px;
}

/* Responsive */
@media (max-width: 768px) {
    .search-panel {
        width: calc(100% - 40px);
    }
}

/* Info badge */
.info-badge {
    display: inline-block;
    background: #667eea;
    color: white;
    font-size: 11px;
    padding: 3px 8px;
    border-radius: 12px;
    margin-left: 8px;
}
zma_address_search.js
// マップ変数
let map;
let currentMarker = null;
let currentPolygon = null;

// DOM要素
const addressInput = document.getElementById('addressInput');
const searchButton = document.getElementById('searchButton');
const searchInfo = document.getElementById('searchInfo');
const searchInfoText = document.getElementById('searchInfoText');
const errorMessage = document.getElementById('errorMessage');
const errorMessageText = document.getElementById('errorMessageText');
const loading = document.getElementById('loading');
const resultsContainer = document.getElementById('resultsContainer');
const resultsHeader = document.getElementById('resultsHeader');
const resultsList = document.getElementById('resultsList');
const selectedInfo = document.getElementById('selectedInfo');
const selectedInfoContent = document.getElementById('selectedInfoContent');

// 地図の初期化
ZMALoader.setOnLoad(function (mapOptions, error) {
    if (error) {
        console.error('Map Loader Error:', error);
        showError('地図の読み込みに失敗しました');
        return;
    }

    // 東京駅を中心に設定
    const lat = 35.681406;
    const lng = 139.767132;
    mapOptions.center = new ZDC.LatLng(lat, lng);
    mapOptions.zoom = 15;
    mapOptions.mouseWheelReverseZoom = true;
    mapOptions.zipsMapType = 'kP8KjZdn';

    const mapElement = document.getElementById('ZMap');

    map = new ZDC.Map(
        mapElement,
        mapOptions,
        function () {
            // 成功時のコールバック
            map.addControl(new ZDC.ZoomButton('bottom-right', new ZDC.Point(-20, -35)));
            map.addControl(new ZDC.Compass('top-right'));
            map.addControl(new ZDC.ScaleBar('bottom-left'));
        },
        function () {
            // 失敗時のコールバック
            showError('地図の初期化に失敗しました');
        }
    );
});

// 検索ボタンのイベントリスナー
searchButton.addEventListener('click', searchAddress);

// Enterキーでも検索
addressInput.addEventListener('keypress', function (e) {
    if (e.key === 'Enter') {
        searchAddress();
    }
});

// 住所検索の実行
async function searchAddress() {
    const query = addressInput.value.trim();

    // 入力チェック
    if (query.length < 2) {
        showError('2文字以上の住所を入力してください');
        return;
    }

    // UIのリセット
    hideError();
    hideInfo();
    hideResults();
    hideSelectedInfo();
    showLoading();

    try {
        // ZENRIN Maps API 住所検索APIを直接呼び出す
        const params = new URLSearchParams({
            word: query,
            word_match_type: '3',
            limit: '0,10',
            address_polygon: 'true'  // 行政界ポリゴンを取得
        });

        const url = `https://test-web.zmaps-api.com/search/address?${params.toString()}`;

        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'x-api-key': 'YOUR_API_KEY',
                'Authorization': 'referer'
            }
        });

        hideLoading();

        if (!response.ok) {
            throw new Error(`HTTP Error: ${response.status}`);
        }

        const data = await response.json();

        // 結果の処理
        if (data.status === 'OK' && data.result && data.result.info && data.result.info.hit > 0) {
            const items = data.result.item;
            displayResults(items, query);
        } else if (data.status === 'OK' && data.result && data.result.info && data.result.info.hit === 0) {
            showError('該当する住所が見つかりませんでした');
        } else if (data.status === 'ERROR') {
            showError('検索中にエラーが発生しました: ' + (data.message || '不明なエラー'));
        } else {
            console.error('予期しないレスポンス形式:', data);
            showError('検索中にエラーが発生しました。コンソールを確認してください。');
        }

    } catch (error) {
        hideLoading();
        console.error('検索エラー:', error);
        showError('検索中にエラーが発生しました。サーバーが起動しているか確認してください。');
    }
}

// 検索結果の表示
function displayResults(items, query) {
    const hitCount = items.length;
    resultsHeader.innerHTML = `<i class="fas fa-list"></i> 検索結果 <span class="info-badge">${hitCount}件</span>`;

    resultsList.innerHTML = '';

    items.forEach((item, index) => {
        const resultItem = createResultItem(item, index);
        resultsList.appendChild(resultItem);
    });

    resultsContainer.classList.add('show');
    showInfo(`「${query}」の検索結果が${hitCount}件見つかりました`);
}

// 結果アイテムの作成
function createResultItem(item, index) {
    const div = document.createElement('div');
    div.className = 'result-item';
    div.dataset.index = index;

    // 住所の組み立て
    const fullAddress = item.address || '';
    const addressCode = item.address_code || '';
    const postCode = item.post_code || '';

    // 緯度経度の取得
    let lat = null;
    let lng = null;
    if (item.position && item.position.length === 2) {
        lng = item.position[0];
        lat = item.position[1];
    }

    div.innerHTML = `
        <div class="result-address">
            <i class="fas fa-map-marker-alt"></i>
            ${fullAddress}
        </div>
        <div class="result-details">
            ${postCode ? `<div class="result-detail-row">
                <span class="result-detail-label">郵便番号:</span>
                <span class="result-detail-value">${postCode}</span>
            </div>` : ''}
            ${addressCode ? `<div class="result-detail-row">
                <span class="result-detail-label">住所コード:</span>
                <span class="result-detail-value">${addressCode}</span>
            </div>` : ''}
            ${lat && lng ? `<div class="result-detail-row">
                <span class="result-detail-label">座標:</span>
                <span class="result-detail-value">緯度 ${lat.toFixed(6)}, 経度 ${lng.toFixed(6)}</span>
            </div>` : ''}
        </div>
    `;

    // クリックイベント
    div.addEventListener('click', function () {
        selectAddress(item, div);
    });

    return div;
}

// 住所の選択
function selectAddress(item, element) {
    // 他の選択を解除
    document.querySelectorAll('.result-item').forEach(el => {
        el.classList.remove('selected');
    });

    // 選択状態を設定
    element.classList.add('selected');

    // 選択された住所情報を表示
    displaySelectedInfo(item);

    // 住所階層に応じた地図表示
    if (item.position && item.position.length === 2) {
        const lng = item.position[0];
        const lat = item.position[1];
        const addressLevel = item.address_level;

        // TBN(地番・戸番)レベルの場合のみピンマーカーを表示
        if (addressLevel === 'TBN') {
            addMarkerToMap(lat, lng, item.address, item);
        } else if (item.address_polygon) {
            // ポリゴンを表示
            addPolygonToMap(item.address_polygon, item.address, lat, lng, item);
        }
    }
}

// 選択された住所情報の表示
function displaySelectedInfo(item) {
    const fullAddress = item.address || '';
    const postCode = item.post_code || '';
    const addressCode = item.address_code || '';
    const addressLevel = item.address_level || '';
    const childLevelFlag = item.child_level_flag;

    // 住所階層の日本語表示
    const addressLevelMap = {
        'TOD': '都道府県',
        'SHK': '市区町村',
        'OAZ': '大字',
        'AZC': '字丁目',
        'GIK': '街区',
        'TBN': '地番・戸番'
    };

    let infoHTML = `
        <div style="margin-bottom: 8px;">
            <strong style="color: #667eea;">住所:</strong><br>
            ${fullAddress}
        </div>
    `;

    // 住所階層の表示と注意メッセージ
    if (addressLevel) {
        const levelName = addressLevelMap[addressLevel] || addressLevel;
        infoHTML += `
            <div style="margin-bottom: 8px;">
                <strong style="color: #667eea;">住所階層:</strong> ${levelName}
            </div>
        `;

        // TBN以外の場合は注意メッセージを表示
        if (addressLevel !== 'TBN') {
            infoHTML += `
                <div style="margin-bottom: 8px; padding: 10px; background: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px;">
                    <strong style="color: #856404;">⚠️ 注意</strong><br>
                    <span style="color: #856404; font-size: 12px;">
                        ${levelName}レベルの住所のため、おおよそのエリアを表示しています。<br>
                        ${childLevelFlag === 1 ? 'より詳細な住所を入力すると、正確な位置を表示できます。' : ''}
                    </span>
                </div>
            `;
        }
    }

    if (postCode) {
        infoHTML += `
            <div style="margin-bottom: 8px;">
                <strong style="color: #667eea;">郵便番号:</strong> ${postCode}
            </div>
        `;
    }

    if (addressCode) {
        infoHTML += `
            <div style="margin-bottom: 8px;">
                <strong style="color: #667eea;">住所コード:</strong> ${addressCode}
            </div>
        `;
    }

    if (item.position && item.position.length === 2) {
        infoHTML += `
            <div>
                <strong style="color: #667eea;">中心座標:</strong><br>
                緯度: ${item.position[1].toFixed(6)}<br>
                経度: ${item.position[0].toFixed(6)}
            </div>
        `;
    }

    selectedInfoContent.innerHTML = infoHTML;
    selectedInfo.classList.add('show');
}

// 既存の表示をクリア
function clearMapDisplay() {
    if (currentMarker) {
        map.removeWidget(currentMarker);
        currentMarker = null;
    }
    if (currentPolygon) {
        map.removeWidget(currentPolygon);
        currentPolygon = null;
    }
}

// 地図にマーカーを追加(TBNレベルのみ)
function addMarkerToMap(lat, lng, address, item) {
    clearMapDisplay();

    const latLng = new ZDC.LatLng(lat, lng);

    currentMarker = new ZDC.Marker(latLng, {
        styleId: ZDC.MARKER_COLOR_ID_RED_L
    });

    map.addWidget(currentMarker);
    map.setCenter(latLng);
    map.setZoom(18);
}

// 地図にポリゴンを追加
function addPolygonToMap(polygonGeoJSON, address, lat, lng, item) {
    clearMapDisplay();

    try {
        // GeoJSON文字列をパース
        const geoJSON = typeof polygonGeoJSON === 'string' ? JSON.parse(polygonGeoJSON) : polygonGeoJSON;
        
        let outerRing = null;

        // PolygonとMultiPolygonの両方に対応
        if (geoJSON && geoJSON.coordinates && geoJSON.coordinates.length > 0) {
            if (geoJSON.type === 'Polygon') {
                // Polygon: coordinates[0] が外側のリング
                outerRing = geoJSON.coordinates[0];
            } else if (geoJSON.type === 'MultiPolygon') {
                // MultiPolygon: coordinates[0][0] が最初のポリゴンの外側のリング
                outerRing = geoJSON.coordinates[0][0];
            }
        }

        if (outerRing && Array.isArray(outerRing) && outerRing.length > 0) {
            // 座標リングを ZDC.LatLng の配列に変換
            const coordinates = outerRing.map(coord => {
                // coord = [経度, 緯度] の配列
                return new ZDC.LatLng(coord[1], coord[0]); // LatLng(緯度, 経度)
            });

            // ポリゴンを作成
            currentPolygon = new ZDC.Polygon(coordinates, {
                stroke: '#667eea',      // 枠線色
                strokeWidth: 3,          // 枠線太さ
                fill: '#667eea',         // 塗りつぶし色
                fillPattern: 'solid',    // 塗りつぶしパターン
                opacity: 0.5             // 不透明度
            });

            map.addWidget(currentPolygon);

            // ポリゴンの中心に移動
            const latLng = new ZDC.LatLng(lat, lng);
            map.setCenter(latLng);
            map.setZoom(14);
        } else {
            throw new Error('無効なGeoJSON形式です');
        }
    } catch (error) {
        console.error('ポリゴンの追加に失敗:', error);
    }
}

// ローディング表示
function showLoading() {
    loading.classList.add('show');
}

function hideLoading() {
    loading.classList.remove('show');
}

// エラーメッセージ表示
function showError(message) {
    errorMessageText.textContent = message;
    errorMessage.classList.add('show');
}

function hideError() {
    errorMessage.classList.remove('show');
}

// 情報メッセージ表示
function showInfo(message) {
    searchInfoText.textContent = message;
    searchInfo.classList.add('show');
}

function hideInfo() {
    searchInfo.classList.remove('show');
}

// 結果非表示
function hideResults() {
    resultsContainer.classList.remove('show');
}

// 選択情報非表示
function hideSelectedInfo() {
    selectedInfo.classList.remove('show');
}

コードを実行した結果は、以下になります。
address_search.png

検索住所が地番・戸番(TBN)以外はポリゴンで表示する
address_search_polygon.png

検索住所が地番・戸番(TBN)の場合は、マーカーを表示する
address_search_pin.png

ステップ解説

Step 1:地図の基本表示

まず、地図を初期化します。
ZMALoader を利用してロードが完了したタイミングで ZDC.Map を生成します。

ZMALoader.setOnLoad(function (mapOptions, error) {
    if (error) {
        console.error('Map Loader Error:', error);
        return;
    }

    // 東京駅を中心に表示
    const lat = 35.681406;
    const lng = 139.767132;
    mapOptions.center = new ZDC.LatLng(lat, lng);
    mapOptions.zoom = 15;
    mapOptions.mouseWheelReverseZoom = true;
    mapOptions.zipsMapType = 'kP8KjZdn';

    const mapElement = document.getElementById('ZMap');
    map = new ZDC.Map(
        mapElement,
        mapOptions,
        function () {
            // 成功時の処理
            map.addControl(new ZDC.ZoomButton('bottom-right', new ZDC.Point(-20, -35)));
            map.addControl(new ZDC.Compass('top-right'));
            map.addControl(new ZDC.ScaleBar('bottom-left'));
        },
        function () {
            // 失敗時の処理
            alert('地図の初期化に失敗しました');
        }
    );
});
  • 中心座標:東京駅(緯度35.681406, 経度139.767132)
  • ズームレベル:15
  • マウスホイールのズーム方向の反転:true 反転する
  • マップタイプ:kP8KjZdn スタンダード地図デザイン
  • マップコントロール:Zoomボタン、コンパス、スケールバーを追加

Step 2:住所検索APIの呼び出し

検索ボタンまたは Enterキーを押下すると、searchAddress() 関数が実行されます。
住所入力をチェックした後、ZENRIN Maps APIの住所検索エンドポイントを呼び出します。

async function searchAddress() {
    const query = addressInput.value.trim();

    if (query.length < 2) {
        showError('2文字以上の住所を入力してください');
        return;
    }

    showLoading();

    try {
        const params = new URLSearchParams({
            word: query,
            word_match_type: '3',
            limit: '0,10',
            address_polygon: 'true'
        });

        const url = `https://test-web.zmaps-api.com/search/address?${params.toString()}`;
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'x-api-key': YOUR_API_KEY,
                'Authorization': 'referer'
            }
        });

        const data = await response.json();
        hideLoading();

        if (data.status === 'OK' && data.result.info.hit > 0) {
            displayResults(data.result.item, query);
        } else {
            showError('該当する住所が見つかりませんでした');
        }
    } catch (error) {
        hideLoading();
        showError('検索中にエラーが発生しました');
        console.error(error);
    }
}

ポイント:

  • word:検索キーワード(住所)
  • word_match_type=3:部分一致検索
  • limit=0,10:10件まで取得
  • address_polygon=true:行政界ポリゴン情報を含める

Step 3:検索結果の表示

検索結果はリスト形式で画面に表示されます。
各結果には「住所」「郵便番号」「住所コード」「座標」が含まれます。

function displayResults(items, query) {
    const hitCount = items.length;
    resultsHeader.innerHTML = `検索結果 (${hitCount}件)`;

    resultsList.innerHTML = '';

    items.forEach((item, index) => {
        const div = document.createElement('div');
        div.className = 'result-item';
        div.innerHTML = `
            <div class="result-address">${item.address}</div>
            <div class="result-details">
                郵便番号: ${item.post_code || '-'}<br>
                住所コード: ${item.address_code || '-'}
            </div>
        `;
        div.addEventListener('click', function () {
            selectAddress(item, div);
        });
        resultsList.appendChild(div);
    });

    resultsContainer.classList.add('show');
}

Step 4:住所の選択と地図への描画

検索結果をクリックすると、地図上に該当住所のエリアやマーカーを表示します。
住所の階層(都道府県、市区町村、大字など)によって表示内容が異なります。

function selectAddress(item, element) {
    // 他の選択を解除
    document.querySelectorAll('.result-item').forEach(el => el.classList.remove('selected'));
    element.classList.add('selected');

    // 情報表示
    displaySelectedInfo(item);

    if (item.position && item.position.length === 2) {
        const [lng, lat] = item.position;
        if (item.address_level === 'TBN') {
            addMarkerToMap(lat, lng, item.address);
        } else if (item.address_polygon) {
            addPolygonToMap(item.address_polygon, item.address);
        }
    }
}
  • TBN(地番・戸番) → ピンマーカーを表示
  • 行政界(都道府県・市区町村など) → ポリゴンを描画

Step 5:行政界ポリゴンの描画

住所検索APIのレスポンスには、GeoJSON形式のポリゴン情報が含まれます。
Polygonの外周リングを抽出して表示します。

function addPolygonToMap(polygonGeoJSON, address) {
    clearMapDisplay();

    const geoJSON = typeof polygonGeoJSON === 'string' ? JSON.parse(polygonGeoJSON) : polygonGeoJSON;
    let outerRing = null;

    if (geoJSON.type === 'Polygon') {
        outerRing = geoJSON.coordinates[0];
    } else if (geoJSON.type === 'MultiPolygon') {
        outerRing = geoJSON.coordinates[0][0];
    }

    if (outerRing) {
        const latLngs = outerRing.map(coord => new ZDC.LatLng(coord[1], coord[0]));
        currentPolygon = new ZDC.Polygon(latLngs, { color: '#667eea', opacity: 0.5 });
        map.addWidget(currentPolygon);
        map.setCenter(latLngs[0]);
        map.setZoom(14);
    }
}

Step 6:選択した住所情報の表示

選択した住所の詳細をパネルに表示します。
住所階層に応じて注意メッセージも表示します。

function displaySelectedInfo(item) {
    const levelMap = {
        'TOD': '都道府県',
        'SHK': '市区町村',
        'OAZ': '大字',
        'AZC': '字丁目',
        'GIK': '街区',
        'TBN': '地番・戸番'
    };
    const levelName = levelMap[item.address_level] || item.address_level;

    let html = `
        <strong>住所:</strong> ${item.address}<br>
        <strong>階層:</strong> ${levelName}<br>
        <strong>郵便番号:</strong> ${item.post_code}<br>
        <strong>住所コード:</strong> ${item.address_code}
    `;
    selectedInfoContent.innerHTML = html;
    selectedInfo.classList.add('show');
}

おわりに

このサンプルでは、住所検索APIを使って住所情報とその位置を取得し、地図上にマーカーやポリゴンとして表示する方法を学びました。
都道府県、市区町村、大字・丁目といった住所階層ごとに地図の表示範囲が変わるため、配送エリアの確認営業エリアの可視化など、さまざまな用途に活用できます。
次のステップとして、検索結果から施設や道路情報を組み合わせることで、より実践的な住所管理システムへ発展させることも可能です。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?