ガイド変更履歴HERE SDK API references
ガイド

交通情報を更新する

最新の交通状況に基づいて、ルートを最新の状態に保ちます。このセクションでは、既存のルートの交通データを更新する方法と、交通状況が変化した際により適した代替ルートを見つけるために、ナビゲーション中に動的ルーティングを活用する方法について説明します。

ルート上の交通状況を更新する

ルートの交通情報は、calculateTrafficOnRoute()またはrefreshRoute()を呼び出すことで更新できます。

  • refreshRoute()メソッドは、出発地またはルートメタデータの更新が必要な場合に使用できます。
  • 交通情報のみを更新する必要があるシナリオでは、calculateTrafficOnRoute()メソッドを使用してTrafficOnRouteオブジェクトを提供できます。現在の交通流と交通障害に関する詳細情報がTrafficOnSectionごとに記載されています。TrafficOnSectionには、TrafficOnSpanオブジェクトのリストとして、スパンごとの詳細な交通情報が記載されています。

どちらのメソッドでも、ルート距離とジオメトリーは変更されません。

注 (Navigateにのみ適用)

または、DynamicRoutingEngineを使用してナビゲーション中によりよいルートを検索することもできます。これらのルートは現在の交通流に基づいて最適化されます。その結果、交通量の多い道路を迂回するための新しいルートジオメトリーも含まれる場合があります。DynamicRoutingEngineの詳細については、「ナビゲーション」セクションを参照してください。

TrafficOnRouteを使用してルートプレビュー中に交通状況を更新する

routingEngine.calculateTrafficOnRoute(..)メソッドは、作成後に特定のセクションまたはルート全体の交通状況を更新します。ナビゲーション中またはルートプレビューコンテキストでこれを計算できます。

インデックスと最後にアクセスした位置からのオフセット (メートル単位) を使用して、最後に移動したルートセクションからの交通状況を再計算することで、これを行います。ルートプレビューコンテキストでは、ルート全体の交通情報を更新するために、lastTraveledSectionIndex traveledDistanceOnLastSectionInMetersを0に設定できます。

このメソッドは、主にルートプレビュー用に設計された画面で次のように利用できます。

func updateTrafficOnRoute(route: Route?) {
    // Since traffic is being calculated for the entire route, lastTraveledSectionIndex and traveledDistanceOnLastSectionInMeters are set to 0.
    let lastTraveledSectionIndex = 0
    let traveledDistanceOnLastSectionInMeters = 0

    // Note: calculateTrafficOnRoute requires a route with routeHandle.
    // Enable it by setting routeOptions.enableRouteHandle to true when creating the route.
    routingEngine.calculateTrafficOnRoute(
        route: route!,
        lastTraveledSectionIndex: Int32(lastTraveledSectionIndex),
        traveledDistanceOnLastSectionInMeters: Int32(traveledDistanceOnLastSectionInMeters)
    ) { routingError, trafficOnRoute in
        if let error = routingError {
            print("CalculateTrafficOnRoute error: \(error)")
        } else if let trafficOnRoute = trafficOnRoute {
            self.showUpdatedETA(trafficOnRoute: trafficOnRoute)
        }
    }
}

TrafficOnRouteからの最新のETAはTrafficOnSpanから確認できます。各TrafficOnSpanはルート沿いの交通情報を提供します。次のメソッドを使用して更新されたETAを抽出できます。

private func showUpdatedETA(trafficOnRoute: TrafficOnRoute) {
    for section in trafficOnRoute.trafficSections {
        var updatedETAInSeconds = 0.0;
        section.trafficSpans.forEach{ updatedETAInSeconds = updatedETAInSeconds + Double($0.duration)}
        var updatedTrafficDelayInSeconds = 0.0;
        section.trafficSpans.forEach{ updatedTrafficDelayInSeconds = updatedTrafficDelayInSeconds + Double($0.trafficDelay)}
        let updatedETAString = String(format: "Updated travel duration %@\nUpdated traffic delay %@",
                                      timeUtils.formatTime(sec: updatedETAInSeconds),
                                      timeUtils.formatTime(sec: updatedTrafficDelayInSeconds))
        showDialog(title: "Updated traffic", message: updatedETAString)
    }
}

交通状況の更新では、予測モデルを使用してルートに沿った状況を予測しますが、マップレイヤーに表示されるリアルタイムの交通状況とは異なる場合があります。これらの違いの詳細については、「トラフィック」を参照してください。

ターン・バイ・ターンナビの実行中に交通状況を更新する (Navigateでのみ使用可能)

ターン・バイ・ターンナビの実行中は、calculateTrafficOnRoute()を呼び出して専用のTrafficOnRouteオブジェクトを計算することをお勧めします。交通状況は走行中に頻繁に変化する可能性があるため、アプリケーションはこの呼び出しを定期的に繰り返します。

以下の実装例では、設定可能な間隔で交通状況の更新が実行されます。

calculateTrafficOnRoute()が完了すると、VisualNavigatorを新しいTrafficOnRouteオブジェクトで更新することができます。これによりRouteProgressオブジェクトが提供する所要時間に関する情報が調整されます。

func updateTrafficOnRoute(routeProgress: RouteProgress) {
    guard let currentRoute = visualNavigator.route else {
        // Should never happen.
        return
    }

    // Below, we use 10 minutes. A common range is between 5 and 15 minutes.
    let trafficUpdateIntervalInMilliseconds = 10 * 60000 // 10 minutes
    let now = Int(Date().timeIntervalSince1970 * 1000) // Current time in milliseconds
    if (now - lastTrafficUpdateInMilliseconds) < trafficUpdateIntervalInMilliseconds {
        return
    }
    // Store the current time when we update trafficOnRoute.
    lastTrafficUpdateInMilliseconds = now

    let sectionProgressList = routeProgress.sectionProgress
    guard let lastSectionProgress = sectionProgressList.last else {
        // Should never happen if the list is valid.
        return
    }
    let traveledDistanceOnLastSectionInMeters =
    currentRoute.lengthInMeters - lastSectionProgress.remainingDistanceInMeters
    let lastTraveledSectionIndex = routeProgress.routeMatchedLocation.sectionIndex

    routeCalculator.calculateTrafficOnRoute(
        currentRoute: currentRoute,
        lastTraveledSectionIndex: Int(lastTraveledSectionIndex),
        traveledDistanceOnLastSectionInMeters: Int(traveledDistanceOnLastSectionInMeters)
    ) { routingError, trafficOnRoute in
        if let routingError = routingError {
            print("CalculateTrafficOnRoute error: \(routingError)")
            return
        }

        // Sets traffic data for the current route, affecting RouteProgress duration in SectionProgress,
        // while preserving route distance and geometry.
        self.visualNavigator.trafficOnRoute = trafficOnRoute
        print("Updated traffic on route.")
    }
}

このコードはHERE Routingバックエンドへの定期的な呼び出しを開始します。契約に応じて、 通話ごとに個別に課金される場合があります。このコードの実行方法および実行頻度は、 アプリケーション側が決定します。

visualNavigator.setTrafficOnRoute()メソッドはすぐには有効になりません。その代わりに、更新された所要時間 (ETA) は次のRouteProgressイベントに反映されます。ETAをRouteProgressイベントから抽出する方法の詳細については、ETAのセクションを参照してください。


EN 日本語

HERE documentation

Find answers to your product and technical questions

Documentation

What's new

Videos

EN 日本語

HERE ドキュメント

製品や技術に関する質問の答えを見つけましょう。より多くの内容と最新の情報については、英語版をご覧ください。

ドキュメント

ダイナミックマップ

動的コンテンツ関連のAPIをアプリやサービスに活用して、ドライバーが安全・快適かつ予定どおりに目的地へ到着できるよう支援します。

地図とデータ

世界中を走行する多数のマッピング車両から得られる最新の位置情報データを活用し、精度の高い地図やカスタムレイヤーを構築できます。

最新情報

動画

(function () { const input = document.querySelector('input[data-typeahead]'); if (!input) return; // Prevent the form from submitting/navigating input.closest('form')?.addEventListener('submit', e => e.preventDefault()); input.addEventListener('input', function () { const q = this.value.trim().toLowerCase(); document.querySelectorAll('.nav-group-name').forEach(group => { let anyVisible = false; group.querySelectorAll('.nav-group-task').forEach(task => { const text = task.textContent.trim().toLowerCase(); const show = !q || text.includes(q); task.style.display = show ? '' : 'none'; if (show) anyVisible = true; }); // Hide the whole group header if nothing matches group.style.display = anyVisible || !q ? '' : 'none'; }); }); })(); (function () { function onTokenClick(event) { var link = event.target.closest('.sdk-for-ios .item .token'); if (!link) return; event.preventDefault(); console.log('token clicked', link.textContent.trim()); var item = link.closest('.item'); if (!item) return; var content = item.querySelector('.height-container'); if (!content) { console.log('no .height-container found for item', item); return; } var isHidden = window.getComputedStyle(content).display === 'none'; content.style.display = isHidden ? 'block' : 'none'; link.classList.toggle('token-open', isHidden); var href = link.getAttribute('href'); if (href) { if (history.pushState) history.pushState({}, '', href); else location.hash = href; } } function openHashTarget() { var hash = window.location.hash.slice(1); if (!hash) return; var anchor = document.querySelector('.sdk-for-ios a[name="' + hash + '"]'); if (!anchor) return; var item = anchor.closest('.item'); if (!item) return; var link = item.querySelector('.token'); var content = item.querySelector('.height-container'); if (!link || !content) return; content.style.display = 'block'; link.classList.add('token-open'); } function init() { console.log('HERE SDK accordion init'); openHashTarget(); } document.removeEventListener('click', onTokenClick); document.addEventListener('click', onTokenClick); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } window.addEventListener('hashchange', openHashTarget); window.addEventListener('pageLoad', init); })();