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

マップ ビューを調整する

HERE SDKには、マップビューを変更するさまざまな方法が用意されています。マップ スタイルを使用すると地図の外観を変更できますが、MapCamera 機能を使用すると地図を別の視点で表示できます。

仕組み

HERE SDK を使用すると、ターゲット位置の設定、カメラの傾斜、ズーム インとズーム アウト、方位角の調整など、さまざまな機能を使用できます。

  • mapView.camera によって返された MapCamera を使用して、地図のビューを操作します。
  • camera.lookAt(point: GeoCoordinates(latitude: 52.530932, longitude: 13.384915)) を呼び出して、新しいターゲットの位置を設定します。これにより、マップ ビューが新しい位置に即座に切り替わります。
  • mapView.camera.state.targetCoordinates を呼び出して、マップ ビューの現在の中心位置を取得します。
  • 距離をメートル単位で設定して地図をズームします:camera.lookAt(point: GeoCoordinates(latitude: 52.373556, longitude: 13.114358), zoom: MapMeasure(kind: .distanceInMeters, value: 1000 * 7))。カメラの State プロパティから現在の距離を取得します。State では現在のズーム レベルも確認できます。
  • GeoOrientationUpdate() を設定して、カメラの傾斜角と方位角を指定します。
  • MapCamera.principalPoint を使用して変換の中心を設定し、マップ ビューの中心にあるデフォルトのピボット ポイントを変更します。
  • camera.boundingBox から現在表示されている領域の境界を取得します。
  • camera.lookAt(area: geoBox, orientation: GeoOrientationUpdate()) を呼び出して、表示するエリアの境界を設定します。
  • 地図を移動します。MapCameraAnimationFactory を使用して、A から B まで基本的なアニメーションを実行します。オーバーロードされたメソッドの 1 つを使用してアニメーションをカスタマイズします。たとえば、高度なアニメーションには flyTo() を使用します。

デフォルトでは、カメラは地図の中央に配置されます。真上から見た鳥瞰視点から見ると、地図は北が上を向いています。これは、デバイスで上端が地図の北を向いていることを意味します。

カメラの位置を変更する

アニメーションを使用して地図を新しい位置に移動する場合は、MapCameraAnimationFactoryflyTo() メソッドを使用します。新しい地図の位置に即座に切り替える場合は、新しいターゲットを設定することで実行できます。

新しいカメラ ターゲットを設定すると、カメラの位置が変更され、マップ ビューの中心に表示される位置を実際に変更できます。lookAt() メソッドはさまざまなオーバーロードで利用できます。いくつか例を示します。

// Change only the location.
camera.lookAt(point: GeoCoordinates(latitude: 52.530932, longitude: 13.384915))

// Change zoom and location.
let distanceInMeters = MapMeasure(kind: .distanceInMeters, value: 1000 * 2)
camera.lookAt(point: GeoCoordinates(latitude: 52.530932, longitude: 13.384915),
              zoom: distanceInMeters)

// Change location area and orientation.
let geoBox = GeoBox(southWestCorner: GeoCoordinates(latitude: 52.373556, longitude: 13.114358),
                    northEastCorner: GeoCoordinates(latitude: 52.611022, longitude: 13.479493))
let orientation = GeoOrientationUpdate(bearing: 0,
                                       tilt: 45)
camera.lookAt(area: geoBox,
              orientation: orientation)

カメラの向き (方位、傾斜) を変更しても、地図の位置は変更されないことに注意してください。

HERE SDK は専用のズーム レベル ([0,22] の範囲) もサポートしており、必要な詳細レベルをすばやく達成する方法を提供します。カメラの zoomTo() メソッドを呼び出してズーム レベルを設定し、カメラの State プロパティから現在のズーム レベルにアクセスします。ズームレベルはDoubleとして設定されています。同じDouble型のdistanceInMetersパラメーターと混合しないように注意してください。

カメラを変更すると、マップ ビューの視点をプログラムでのみ変更できますが、地図のズームする、またはマップの回転、傾斜させるジェスチャーの実行など、マップ ビュー自体を直接制御することはできません。地図の直接操作に使用できるジェスチャーの概要については、ジェスチャーのセクションを参照してください。

MapCamera は常に定義された State になります。たとえば、State は現在のターゲット位置を提供しています。このターゲット位置は、デフォルトの主点が変更されていない限り、マップ ビューの現在の中心を示します (以下を参照)。

あるいは、特定の位置まで凹状の弓の動きをして移動します。

private func flyTo(target: GeoCoordinates) {
    let geoCoordinatesUpdate = GeoCoordinatesUpdate(target)
    let durationInSeconds: TimeInterval = 3
    let animation = MapCameraAnimationFactory.flyTo(target: geoCoordinatesUpdate,
                                                    bowFactor: 1,
                                                    duration: durationInSeconds)
    mapView.camera.startAnimation(animation)
}

カメラを回転する

カメラを使用すると、地図を直接回転させることはできませんが、代わりにカメラの向きを変更できます。GeoOrientationUpdate()bearing パラメーターを変更すると、地図を回転させたときと同じ効果が得られます。

地図の向きは通常、方位角によって指定されます。「方位」とはナビゲーション用語で、北から時計回りの方向を度単位で数えます。

デフォルトでは、カメラの方位値は 0° です。上の図に示すように、方位角度を 45° に設定すると、カメラの視点からは地図が反時計回りに回転して見え、方位の方向が地図の新しい上方向になりデバイスの上端を向きます。これは、ハイキング中に紙の地図を特定の方向に回転させるのと似ています。地図の上端が自分の行きたい方向を向いていると、方向を確認しやすくなります。しかし、常に真の北方向 (方位 = 0° ) にはなりません。

なお、方位軸は現在のカメラの向きに関係なく常に地面に対して垂直であり、カメラをパススルーします。

次のコードはカメラを 90° 回転させます。

let orientation = GeoOrientationUpdate(bearing: 90,
                                       tilt: 0)
let distanceInMeters = MapMeasure(kind: .distanceInMeters, value: 1000 * 7)
mapView.camera.lookAt(point: GeoCoordinates(latitude: 52.373556, longitude: 13.114358),
                      orientation: orientation,
                      zoom: distanceInMeters)

実際には、これにより、ビューアーから見て地図は左に 90° 回転して表示されます。

カメラを傾斜させる

カメラを使用して、平らな 2D 地図の表面を 3D 視点に変換できます。たとえば、地平線の方向に見える、より遠くにある道路を見ることができます。デフォルトでは、カメラは傾斜していません (傾斜 = 0°)。

カメラの傾斜値に加えて、カメラの方位角 (上を参照) も操作できます。ここでは、傾斜値を変更した場合の効果を示します。下の図を参照して、有効なカメラ軸を確認してください。

傾斜値 0° は、カメラの光軸が地面に対して垂直であることを意味します。傾斜角は常にこの垂直軸から計算されます。傾斜角はカメラの光軸に関係します。

図に示すように、カメラを 45° 傾けるとカメラの鳥瞰視点が 3D 視点に変わります。カメラの傾斜値のみを変更するには、次のコードを使用します。

let orientation = GeoOrientationUpdate(bearing: 0,
                                       tilt: 45)
let distanceInMeters = MapMeasure(kind: .distanceInMeters, value: 1000 * 7)
mapView.camera.lookAt(point: GeoCoordinates(latitude: 52.373556, longitude: 13.114358),
                      orientation: orientation,
                      zoom: distanceInMeters)

下の図に示すように、傾斜角はターゲット位置の垂直軸から計算されます。観測者の真下を指す方向は天底と呼ばれます。傾斜値を設定すると、カメラが実際に動いて、カメラのターゲットに焦点を合わせ続けます。

なお、各傾斜値はデルタではなく絶対値として適用されます。これは、それ以降の傾斜値は常にカメラのデフォルトの位置から適用され、前の位置から適用されるわけではないことを意味します。したがって、同じ傾斜値を複数回設定してもカメラの傾斜軸は変わりません。これはほとんどのカメラ操作に共通しています。範囲外の値は指定範囲内に制限されます。

<Image align="center" caption="Illustration:Tilt the map." src="https://files.readme.io/6f2620f89290f4cbabc1b0c4ee3020ec792474c3f9350fb58b55ed3a4a494a43-tilt.png"

すべての軸を同時に操作できます。

なお、以下に示すように、カメラが傾いている場合は方位値を変更すると異なる結果が生じます。傾斜しているカメラは方位値を設定すると異なるターゲット位置になりますが、傾斜していないカメラは元のターゲット位置を維持します。

変換の中心を変更する

デフォルトでは、地図のピボット ポイント (主点) は、マップ ビューの中心に配置されます。これはターゲット座標を配置するマップ ビュー内のポイントを決定します。新しい主点を設定すると地図が即座に移動し、新しい主点で現在のターゲット座標がレンダリングされます。これはマップ ビューの左上の原点 (0, 0) を基準とし、ピクセル単位で相対的に設定されます。

主点はすべてのプログラムによる地図の変換 (回転、周回、傾斜、ズーム)、地図を傾斜させるための 2 本指のパン ジェスチャーに影響します。ピンチによる回転などの他のジェスチャーは影響を受けません。

通常、主点は 1 回のみ設定します。たとえば、ターン・バイ・ターンナビ中に変換の中心を少し下げることで、ユーザーには前方の道路がより多く見えるようになります。これを実現するには、マップビューのピクセル寸法 (レイアウトとデバイスの画面サイズに基づく) を取得し、次に高さを3/4下げる、つまり、mapViewHeightInPixelsに0.75を掛ける必要があります。次の例を参照してください。

// Repositions principal point 3/4 lower than default.
let scaleFactor = UIScreen.main.scale
let mapViewWidthInPixels = Double(mapView.bounds.width * scaleFactor)
let mapViewHeightInPixels = Double(mapView.bounds.height * scaleFactor)
let newTransformCenter = Point2D(x: mapViewWidthInPixels / 2, y: mapViewHeightInPixels * 0.75)
camera.principalPoint = newTransformCenter

// Reposition a circle view on screen to indicate the new target.
cameraTargetView.center = CGPoint(x: newTransformCenter.x / Double(scaleFactor),
                                  y: newTransformCenter.y / Double(scaleFactor))

print("New transform center: \(newTransformCenter.x), \(newTransformCenter.y)")

上のコード スニペットでは新しい主点を設定し、現在の地図の中心を画面に表示されている地図領域の 3/4 下方に瞬時に移動させます。一度設定すると、その後のすべての地図操作はこの新しい主点を中心に回転します。たとえば、プログラムで地図を回転させると、地図は常にこの主点を中心に回転します。

上の例では、主点を中心としたカスタムのcameraTargetViewをレンダリングする方法も示しています。これの完全なコードは、Cameraサンプルアプリで見ることができます。

VisualNavigator (Navigateでのみ使用可能) を使用する場合はナビゲーターが主点を制御するため、これは当てはまりません。ターン・バイ・ターンナビ中にカスタム主点を使用する場合は、これをマップビューで直接設定するのではなく、CameraBehaviorに設定する必要があります。

let fixedCameraBehavior = FixedCameraBehavior();
visualNavigator.cameraBehavior = fixedCameraBehavior;

// Repositions principal point higher than default during navigation.
let newTransformCenter = Anchor2D(horizontal: 0.5, vertical: 0.5);
fixedCameraBehavior.normalizedPrincipalPoint = newTransformCenter;

アニメーションを追加する

より高度なアニメーションの例は、GitHubCameraKeyframeTracks サンプル アプリで見ることができます。

Route または GeoBox にズームする方法の例を探している場合は、こちらのルート検索のセクションを参照してください。これは、アニメーションの有無 (任意のパディングも含む) にかかわらず実行できます。

ジェスチャーとカメラ動作をカスタマイズする

デフォルトでは、マップビューは地図を操作することによってカメラを動かせる、複数のジェスチャーをサポートしています。たとえば、2本指のジェスチャーを使用して地図をピンチしたり回転したりできます。それぞれのジェスチャーによりcameraのプロパティを調整します。デフォルトの動作をカスタマイズする場合は、サポートされているGestureTypeアクションのいずれかを無効にして、独自のカメラ操作を定義できます。

これはジェスチャーのカスタマイズを使用して行うころができます。「カスタムズーム動作を追加する」を参照してください。

Cameraサンプルアプリを試す

上のコードスニペットのほとんどは、「Camera」サンプルアプリから取得できます。このサンプルアプリは、GitHubでお好みのプラットフォームのものを見つけることができます。


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); })();