6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ランニングコースAPI比較:Google vs. ZENRIN、開発者が選ぶべきはどっち?

Posted at

要約

本記事では、GoogleMaps APIとZENRINMaps APIを使用してランニングコースを検索し、その結果を比較しました。両APIにはランニング専用モードは存在しませんが、歩行者ルートをカスタマイズすることで実用的なランニングルートを作成できることがわかりました。GoogleMaps APIではwaypointsの活用が重要であり、ZENRINMaps APIでは各種パラメータのカスタマイズが可能です。実装方法、結果の違い、それぞれのAPIの長所と短所を解説し、開発者がプロジェクトに最適なAPIを選択する際の参考となる情報を提供しています。

はじめに

ランニングコース検索は、健康志向のランナーや効率的なトレーニングを求めるアスリートなど、様々なニーズを持つ人々にとって非常に重要です。

本記事では、ZENRIN Maps APIとGoogle Maps APIを用いて、このランニングコース検索を実装し、それぞれのAPIの特性と実装方法を比較検討します。

対象読者

  • ランニングアプリの開発に興味がある方
  • 経路探索APIの選定に悩んでいる方
  • ZENRIN Maps APIとGoogle Maps APIの違いを詳しく知りたい方

ZENRINMaps APIでのランニングコース実装

実装概要

ZENRINMaps APIを利用して、特定の出発地点から目的地点までのランニングコースを検索し、地図上に表示する機能を実装しました。APIのパラメータをカスタマイズすることで、ランニングに適したルートを生成しています。 ZENRIN Maps APIを使用するためには検証用IDとPW取得が必要です。
お試しIDは下記から簡単に発行できました。
ZENRIN Maps API 無料お試しID お申込みフォーム(2か月無料でお試しできます)

詳細手順はこちらを参照しました。

実装コード

var map;
// ルート情報(所要時間、距離、消費カロリー)を表示する関数
function showRouteInfo(rawDuration, rawDistance, rawCalorie) {
    convertTime(rawDuration);
    convertDtn(rawDistance);
    convertCalorie(rawCalorie);
}

// 所要時間を適切な形式で表示する関数
function convertTime(rawDuration) {
    const timeInfoArea = document.getElementById('time');
    if (timeInfoArea) {
        const minutes = Math.round(rawDuration / 60); // 秒 → 分に変換
        timeInfoArea.textContent = `${minutes} 分`;
    } else {
        console.error("所要時間の表示エリアが見つかりません。");
    }
}

// 距離をキロメートル単位で表示する関数
function convertDtn(rawDistance) {
    const distInfoArea = document.getElementById('dist');
    if (rawDistance && distInfoArea) {
        const distanceInKm = (rawDistance / 1000).toFixed(1); // メートル → キロメートルに変換
        distInfoArea.textContent = `${distanceInKm} km`;
    } else {
        console.error("距離の表示エリアが見つかりません。");
    }
}

// 消費カロリーを表示する関数
function convertCalorie(rawCalorie) {
    const calorieInfoArea = document.getElementById('calorie');
    if (rawCalorie && calorieInfoArea) {
        calorieInfoArea.textContent = `${rawCalorie.toFixed(1)} kcal`;
    } else {
        console.error("消費カロリーの表示エリアが見つかりません。");
    }
}

// ルート検索を実行する関数
function performRouteSearch(origin, destination) {
    const startPoint = `${origin.lng},${origin.lat}`;
    const goalPoint = `${destination.lng},${destination.lat}`;

    const api = "/route/route_mbn/walk";
    const params = {
        search_type: 5,
        from: startPoint,
        to: goalPoint,
        llunit: 'dec',
        datum: 'JGD',
        eta: true,
        speed: 200,
        weight: 70,
        stride: 100,
        step_count: true,
        calorie: true,
        avoid: '1,2'
    };

    try {
        map.requestAPI(api, params, function (response) {
            if (response.ret && response.ret.status === 'OK') {
                const route = response.ret.message.result.item[0].route;

                // 座標データを取得
                const coordinates = route.section.flatMap(section =>
                    section.link.flatMap(link =>
                        link.line.coordinates.map(coord => new ZDC.LatLng(coord[1], coord[0]))
                    )
                );

                // 座標データが存在するか確認
                if (coordinates.length === 0) {
                    console.warn("座標データが存在しません。");
                    return;
                }

                // 地図の範囲を調整
                if (coordinates.length > 0) {
                    // 最初の座標を中心にする
                    const firstCoord = coordinates[0];
                    map.setCenter(new ZDC.LatLng(firstCoord.lat, firstCoord.lng));
                    map.setZoom(15); // 適切なズームレベルを設定
                }

                // ルート情報を取得して表示
                const rawDuration = route.time; // 所要時間
                const rawDistance = route.distance; // 距離
                const rawCalorie = route.calorie; // 消費カロリー
                showRouteInfo(rawDuration, rawDistance, rawCalorie);

                // ポリラインでルートを地図上に描画
                try {
                    const polyline = new ZDC.Polyline(coordinates, {
                        color: '#008dcb',
                        width: 5,
                        opacity: 0.7,
                    });
                    map.addWidget(polyline);
                } catch (error) {
                    console.error("ZDC.Polylineの作成に失敗しました:", error);
                }
            } else {
                console.error("ルート検索に失敗しました。");
            }
        });
    } catch (error) {
        console.error("ルート検索中にエラーが発生しました:", error);
    }
}

// ポリラインの範囲を計算する関数
function calculatePolylineBounds(polylineCoordinates) {
    if (!polylineCoordinates || polylineCoordinates.length === 0) {
        console.warn('ポリラインの座標が無効です。');
        return null;
    }

    let minLat = Number.POSITIVE_INFINITY;
    let maxLat = Number.NEGATIVE_INFINITY;
    let minLng = Number.POSITIVE_INFINITY;
    let maxLng = Number.NEGATIVE_INFINITY;

    try {
        polylineCoordinates.forEach(point => {
            if (point.lat < minLat) minLat = point.lat;
            if (point.lat > maxLat) maxLat = point.lat;
            if (point.lng < minLng) minLng = point.lng;
            if (point.lng > maxLng) maxLng = point.lng;
        });
    } catch (error) {
        console.error("calculatePolylineBounds関数でエラーが発生しました:", error);
        return null;
    }

    const southWest = new ZDC.LatLng(minLat, minLng);
    const northEast = new ZDC.LatLng(maxLat, maxLng);
    return new ZDC.LatLngBounds(southWest, northEast);
}

// ZMALoaderの初期化
ZMALoader.setOnLoad(function (mapOptions, error) {
    if (error) {
        console.error(error);
        return;
    }

    mapOptions.zoom = 17;
    mapOptions.centerZoom = false;

    map = new ZDC.Map(
        document.getElementById('ZMap'),
        mapOptions,
        function () {
            // スタート地点と終点を設定
            const origin = new ZDC.LatLng(35.669, 139.700);
            const destination = new ZDC.LatLng(35.671, 139.714);

            console.log("map:", map);

            performRouteSearch(origin, destination);

            // 地図コントロールを追加
            map.addControl(new ZDC.ZoomButton('bottom-left'));
            map.addControl(new ZDC.Compass('top-right'));
            map.addControl(new ZDC.ScaleBar('bottom-left'));
        },
        function () {
            console.error("地図の生成に失敗しました");
        }
    );
});


実装結果と課題

  • 結果: 結果: ZENRINMaps APIを使用することで、ランニングに適したルートを地図上に表示できました。速度、体重、歩幅などのパラメータを設定することで、消費カロリーの計算や階段・急な坂を避けるルートの生成が可能となりました。
    ZENRINMaps APIで、以下のパラメータ指定によって、ランニングの条件を追加しています
const params = {
    // 既存のパラメータに加えて
    eta: true,        // 到着予定時刻の計算を有効にする
    speed: 200,       // 移動速度を200m/分(12km/h)に設定(ジョギング程度の速度)
    weight: 70,       // ランナーの体重を70kgと仮定
    stride: 100,      // 歩幅を100cmと設定
    step_count: true, // 歩数(ステップ数)の計算を有効にする
    calorie: true,    // 消費カロリーの計算を有効にする
    avoid: '1,2'      // 1: 階段、2: 急な坂を避ける
};

上記のようにパラメータを追加することでランニングコース検索用にカスタマイズしています。

  • ランニングに適した速度でのルート計算が可能になります

  • ランナーの体重と歩幅を考慮した、より正確な消費カロリーと歩数の計算ができます

  • 階段や急な坂を避けることで、ランニングに適したルートを優先的に選択できます

  • 到着予定時刻の計算により、ランニングの所要時間を正確に把握できます

  • 課題: ランニング専用モードがないため、歩行者モードをベースにしたカスタマイズが必要です。また、パラメータの最適な設定値には個人差があることが考えられます。

GoogleMaps APIでのランニングコース実装

実装概要

GoogleMaps APIを使用して、出発地点から目的地点までのランニングコースを検索し、地図上に表示する機能を実装しました。WALKINGモードを使用し、waypointsを活用して公園内を通るルートを緯度経度で指定しています。

実装コード

    <script>
        function initMap() {
            const map = new google.maps.Map(document.getElementById("map"), {
                center: { lat: 35.465833, lng: 139.622778 },
                zoom: 15,
            });

            const directionsService = new google.maps.DirectionsService();
            const directionsRenderer = new google.maps.DirectionsRenderer();
            directionsRenderer.setMap(map);

            const request = {
                origin: new google.maps.LatLng(35.669, 139.700), // 渋谷駅付近
                destination: new google.maps.LatLng(35.671, 139.714), // 代々木公園付近
                travelMode: google.maps.TravelMode.WALKING,
                waypoints: [
                    { location: new google.maps.LatLng(35.6705, 139.7055), stopover: false }, // 公園入口
                    { location: new google.maps.LatLng(35.6712, 139.7100), stopover: false }, // 公園中央
                    { location: new google.maps.LatLng(35.6700, 139.7120), stopover: false }  // ランニングコース途中
                ],
                optimizeWaypoints: true, // 最適なルートを計算
            };

            directionsService.route(request, (result, status) => {
                if (status === 'OK') {
                    directionsRenderer.setDirections(result);
                    const route = result.routes[0].legs[0];

                    document.getElementById('distance').textContent = '総距離: ' + route.distance.text;
                    document.getElementById('duration').textContent = '所要時間: ' + route.duration.text;

                    const steps = route.steps;
                    const routeSteps = document.getElementById('route-steps');
                    routeSteps.innerHTML = "";
                    steps.forEach(step => {
                        const li = document.createElement('li');
                        li.innerHTML = step.instructions + ' (' + step.distance.text + ')';
                        routeSteps.appendChild(li);
                    });
                } else {
                    console.error("ルート検索に失敗しました: " + status);
                }
            });
        }
    </script>

実装結果と課題

  • 結果:GoogleMaps APIを使用して、基本的な歩行者ルートを地図上に表示し、距離や所要時間などの情報を提供できました。waypointsを活用することで、公園内を通るランニングコースを作成することができました。

  • 課題:GoogleMaps APIはランニングに特化したオプションを提供していないため、ランナーが求める細かい条件を完全に満たすルート作成は難しい場合があります。

地図表示

  • ZENRIN Maps API
    zma_Running.png

  • Google Maps API
    gma_Running.png

API比較

  • ランニング対応: ZENRINMaps APIは、パラメータのカスタマイズによりランニングに適したルート生成が可能です。GoogleMaps APIは、waypointsを活用することで公園内のルートなどを指定できますが、ランニング特有の条件設定は限定的です。

  • 情報提供: ZENRINMaps APIは消費カロリーなどのランナー向け情報を直接提供できます。GoogleMaps APIは基本的な距離と時間情報を提供しますが、ランナー特有の情報は別途計算が必要です。

  • カスタマイズ性: GoogleMaps APIは豊富なドキュメントと広範なコミュニティサポートがあり、カスタマイズの幅が広いです。ZENRINMaps APIは日本国内に特化した詳細な地図情報を提供しており、日本のランナー向けに最適化しやすい可能性があります。

  • 使いやすさ: GoogleMaps APIは世界中で広く使われており、導入しやすいです。ZENRINMaps APIは日本国内での利用に特化しており、日本語のサポートが充実しています。

まとめ

本記事では、Google Maps APIとZENRIN Maps APIを使用してランニングコースを検索し、その結果を比較しました。両APIともランニング専用モードは存在しませんが、それぞれ異なるアプローチでランニングに適したルートを作成できることがわかりました。Google Maps APIではwaypointsによるルートのカスタマイズが、ZENRIN Maps APIでは詳細なパラメータ設定によるカスタマイズが可能です。それぞれのAPIの特徴を理解し、プロジェクトの要件や利用シーンに応じて適切なAPIを選択することで、より魅力的なランニングアプリを開発できるでしょう。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?