マップアイテムを追加する

マップアイテムを追加する

HERE SDK を使用すると、マップ ポリラインやマーカーなど、いくつかのタイプのアイテムを地図に追加できます。これらの詳細については、以下のセクションで説明します。現在、次のマップ アイテムがサポートされています。

  • マップ ポリライン: 移動できないレンダリングされた線。
  • マップ矢印: 地図上に矢印インジケーターを表示する便利な方法。
  • マップ ポリゴン: 移動できないレンダリングされたシェイプ。
  • マップ円: ジオ ポリゴンとして定義できる、移動できないレンダリングされた円。
  • マップ マーカー: 地図上の特定のスポットを「マーク」するために固定できる画像。
  • マップ マーカー クラスタリング: ズーム レベルに応じてクラスター化できるマップ マーカーのグループ。
  • 埋め込み POI: 地図に埋め込まれた事前設定済みの公共交通機関の駅、レストラン、現金自動預け払い機、その他の施設などの選択可能な POI オブジェクト (Carto POI)。
  • マップ マーカー 3D: 指定した地理座標で地図上にレンダリングされた 3D シェイプ。
  • フラット マップ マーカー: 地図と一緒に回転および傾斜するフラット マップ マーカー。
  • 位置インジケーター: 地図上で現在のデバイス位置を示すための、事前定義済みアセット。
  • マップ表示ピン: 地図上にネイティブな Android の View レイアウトを表示する便利な方法。

ポリライン、ポリゴン、円は現在のズーム レベルに基づいてサイズが調整されますが、マーカーとピンはズームした場合も変化しません。

どのマップ アイテムにも、地図からこれらのアイテムを選択できる便利な方法が備わっています。

マップ ポリラインを追加する

ポリラインは、地図上にルート ジオメトリーをレンダリングする場合などに便利です。作成方法を以下に示します。

private MapPolyline createPolyline() {
    ArrayList<GeoCoordinates> coordinates = new ArrayList<>();
    coordinates.add(new GeoCoordinates(52.53032, 13.37409));
    coordinates.add(new GeoCoordinates(52.5309, 13.3946));
    coordinates.add(new GeoCoordinates(52.53894, 13.39194));
    coordinates.add(new GeoCoordinates(52.54014, 13.37958));

    GeoPolyline geoPolyline;
    try {
        geoPolyline = new GeoPolyline(coordinates);
    } catch (InstantiationErrorException e) {
        // Thrown when less than two vertices.
        return null;
    }

    float widthInPixels = 20;
    Color lineColor = Color.valueOf(0, 0.56f, 0.54f, 0.63f);
    MapPolyline routeMapPolyline = null;
    try {
        routeMapPolyline = new MapPolyline(routeGeoPolyline, new MapPolyline.SolidRepresentation(
                new MapMeasureDependentRenderSize(RenderSize.Unit.PIXELS, widthInPixels),
                lineColor,
                LineCap.ROUND));
    } catch (MapPolyline.Representation.InstantiationException e) {
        Log.e("MapPolyline Representation Exception:", e.error.name());
    } catch (MapMeasureDependentRenderSize.InstantiationException e) {
        Log.e("MapMeasureDependentRenderSize Exception:", e.error.name());
    }

    return mapPolyline;
}
private fun createPolyline(): MapPolyline? {
    val coordinates = ArrayList<GeoCoordinates>()
    coordinates.add(GeoCoordinates(52.53032, 13.37409))
    coordinates.add(GeoCoordinates(52.5309, 13.3946))
    coordinates.add(GeoCoordinates(52.53894, 13.39194))
    coordinates.add(GeoCoordinates(52.54014, 13.37958))

    val geoPolyline: GeoPolyline
    try {
        geoPolyline = GeoPolyline(coordinates)
    } catch (e: InstantiationErrorException) {
        // Thrown when less than two vertices.
        return null
    }

    val widthInPixels = 20f
    val lineColor: Color = Color(0f, 0.56.toFloat(), 0.54.toFloat(), 0.63.toFloat())
    var mapPolyline: MapPolyline? = null
    try {
        mapPolyline = MapPolyline(
            geoPolyline, MapPolyline.SolidRepresentation(
                MapMeasureDependentRenderSize(RenderSize.Unit.PIXELS, widthInPixels.toDouble()),
                lineColor,
                LineCap.ROUND
            )
        )
    } catch (e: MapPolyline.Representation.InstantiationException) {
        Log.e("MapPolyline Representation Exception:", e.error.name)
    } catch (e: MapMeasureDependentRenderSize.InstantiationException) {
        Log.e("MapMeasureDependentRenderSize Exception:", e.error.name)
    }

    return mapPolyline
}

MapPolylineは3つの要素で構成されます。

  • 地図上にポリラインを配置する場所を定義する2つ以上の地理座標のリスト。
  • この座標のリストを含むGeoPolyline。
  • ポリラインの表示方法を定義する DashPattern や LineCap などのスタイル パラメーター。

Since a geometric line is defined by two or more points, you need to create an ArrayList, which must contain at least two GeoCoordinates.これを行わなかった場合は、例外がスローされます。線の外観を変更するには、線の太さ (ピクセル単位) と色を設定します。スクリーンショットの例を参照してください。

1 つ以上のマップ ポリラインを作成したら、次のようにしてマップ シーンに追加できます。

mapScene = mapView.getMapScene();

mapPolyline = createPolyline();
mapScene.addMapPolyline(mapPolyline);
mapScene = mapView.getMapScene()

mapPolyline = createPolyline()
mapScene.addMapPolyline(mapPolyline)

マップポリラインのインスタンスがすでにマップシーンに添付されている場合は、さらにそれを追加しようとする試みは無視されます。

スクリーンショット:ポリラインを表示。

マップビューでは1つのシーンのみが許可され、すべてのマップアイテムがそのシーンに直接配置されます。マップアイテムをグループ化する場合は、配列を使用してマップアイテムを整理し、個別に追加または削除できます。

mapPolyline を地図から直ちに削除するには、次のように呼び出します。

mapScene.removeMapPolyline(mapPolyline);
mapScene.removeMapPolyline(mapPolyline)

注

MapPolyline アイテムは選択可能で、アイテムを選択するときに取得できる Metadata を保存できます。例については、以下のマップマーカーのセクションを参照してください。

MapPolylineの可視性は、現在のズームレベルに基づいて、以下に示すようにKind、minimumZoomLevel、maximumZoomLevelで定義されるMapMeasureRangeアイテムのリストを設定することで調整できます。

public void enableVisibilityRangesForPolyline(){
    ArrayList<MapMeasureRange> visibilityRanges = new ArrayList<>();
    visibilityRanges.add(new MapMeasureRange(MapMeasure.Kind.ZOOM_LEVEL,1,10));
    visibilityRanges.add(new MapMeasureRange(MapMeasure.Kind.ZOOM_LEVEL,11,22));

    // Sets the visibility ranges for this map polyline based on zoom levels.
    // Each range is half-open: [minimumZoomLevel, maximumZoomLevel],
    // meaning the polyline is visible at minimumZoomLevel but not at maximumZoomLevel.
    // The polyline is rendered only when the map zoom level falls within any of the defined ranges.
    mapPolyline.setVisibilityRanges(visibilityRanges);
}
fun enableVisibilityRangesForPolyline() {
    val visibilityRanges = ArrayList<MapMeasureRange>()

    visibilityRanges.add(MapMeasureRange(MapMeasure.Kind.ZOOM_LEVEL, 1.0, 10.0))
    visibilityRanges.add(MapMeasureRange(MapMeasure.Kind.ZOOM_LEVEL, 11.0, 22.0))

    // Sets the visibility ranges for this map polyline based on zoom levels.
    // Each range is half-open: [minimumZoomLevel, maximumZoomLevel],
    // meaning the polyline is visible at minimumZoomLevel but not at maximumZoomLevel.
    // The polyline is rendered only when the map zoom level falls within any of the defined ranges.
    mapPolyline?.visibilityRanges = visibilityRanges
}

現在のところ、可視範囲でサポートされているのは、MapMeasure.Kind.ZOOM_LEVELのみです。その他の種類は無視されます。

注

描画順序を設定することで、どのアイテムを重ねて描画するかを指定できます。現時点では、描画順序の設定は、同じタイプのクラス内の順序のみを定義するため、他のマップアイテムとの関係には影響しません。

DrawOrderType を指定すると、エクスペリエンスをさらに最適化できます。たとえば、DrawOrderType.mapSceneAdditionOrderIndependent を使用すると、アイテムを追加するときの順序に描画順序が依存しないように指定できます。代わりに、同じ描画順序を持つ同じ種類の複数のマップ アイテムを任意の順序で描画でき、色などの類似属性を持つマップ アイテムをグループ化してまとめて描画することで、レンダリング パフォーマンスを向上させることができます。

マップ ポリラインは破線でレンダリングすることもできます。破線のパターン スタイルを設定するには、MapPolyline.DashImageRepresentation を使用します。

マップ矢印を追加する

マップ矢印は MapPolyline アイテムと同じように動作し、任意の数のポイントを持つポリラインで構成されていますが、端に矢印の先端が表示されます。マップ矢印は、ズーム レベルが 13 を超える場合にのみ表示されます。地図上で方向を示す場合、たとえば、ルートジオメトリーの一部にレンダリングするときなどに便利です。

private MapArrow createMapArrow() {
    ArrayList<GeoCoordinates> coordinates = new ArrayList<>();
    coordinates.add(new GeoCoordinates(52.53032, 13.37409));
    coordinates.add(new GeoCoordinates(52.5309, 13.3946));
    coordinates.add(new GeoCoordinates(52.53894, 13.39194));
    coordinates.add(new GeoCoordinates(52.54014, 13.37958));

    GeoPolyline geoPolyline;
    try {
        geoPolyline = new GeoPolyline(coordinates);
    } catch (InstantiationErrorException e) {
        // Thrown when less than two vertices.
        return null;
    }

    float widthInPixels = 20;
    Color lineColor = Color.valueOf(0, 0.56f, 0.54f, 0.63f); // RGBA
    MapArrow mapArrow = new MapArrow(geoPolyline, widthInPixels, lineColor);

    return mapArrow;
}
private fun createMapArrow(): MapArrow? {
    val coordinates = ArrayList<GeoCoordinates>()
    coordinates.add(GeoCoordinates(52.53032, 13.37409))
    coordinates.add(GeoCoordinates(52.5309, 13.3946))
    coordinates.add(GeoCoordinates(52.53894, 13.39194))
    coordinates.add(GeoCoordinates(52.54014, 13.37958))

    val geoPolyline: GeoPolyline
    try {
        geoPolyline = GeoPolyline(coordinates)
    } catch (e: InstantiationErrorException) {
        // Thrown when less than two vertices.
        return null
    }

    val widthInPixels = 20f
    val lineColor: Color = Color.valueOf(0f, 0.56f, 0.54f, 0.63f) // RGBA
    val mapArrow = MapArrow(geoPolyline, widthInPixels.toDouble(), lineColor)

    return mapArrow
}

MapArrowは3つの要素で構成されます。

  • 地図上にポリラインを配置する場所を定義する2つ以上の地理座標のリスト。
  • この座標のリストを含むGeoPolyline。
  • 矢印の表示方法を定義する color や widthInPixelsなどのスタイル パラメーター。

幾何学的な線は2つ以上の点で定義されるため、少なくとも2つのGeoCoordinatesを含む配列を作成する必要があります。これを行わなかった場合は、例外がスローされます。線の外観を変更するには、線の太さ (ピクセル単位) と色を設定します。スクリーンショットの例を参照してください。

1 つ以上のマップ矢印を作成したら、次のようにしてマップ シーンに追加できます。

mapScene = mapView.getMapScene();

mapArrow = createMapArrow();
mapScene.addMapArrow(mapArrow);
mapScene = mapView.getMapScene()

mapArrow = createMapArrow()
mapScene.addMapArrow(mapArrow)

マップ矢印のインスタンスがすでにマップシーンに添付されている場合は、さらにそれを追加しようとする試みは無視されます。

スクリーンショット:マップ矢印を表示。

マップビューでは1つのシーンのみが許可され、すべてのマップアイテムがそのシーンに直接配置されます。マップアイテムをグループ化する場合は、配列を使用してマップアイテムを整理し、個別に追加または削除できます。

mapArrow を地図から直ちに削除するには、次のように呼び出します。

mapScene.removeMapArrow(mapArrow);
mapScene.removeMapArrow(mapArrow)

注

MapArrow アイテムは選択可能で、アイテムを選択するときに取得できる Metadata を保存できます。例については、以下のマップマーカーのセクションを参照してください。

マップ ポリゴンを追加する

MapPolygon は、少なくとも 3 つの座標で構成される図形です。それ以外の場合は、レンダリングできません。MapPolyline と同様に、座標が接続されます。ポリゴンは、地図上の領域を強調表示するのに役立ちます。

注

座標の順序は重要です。

ポリゴンの作成方法については、次の例を参照してください。座標は、リスト内での時計回りの順序に基づいて接続されます。結果として得られるシェイプは、色で塗りつぶすことができます。

private MapPolygon createPolygon() {
    ArrayList<GeoCoordinates> coordinates = new ArrayList<>();
    // Note that a polygon requires a clockwise order of the coordinates.
    coordinates.add(new GeoCoordinates(52.54014, 13.37958));
    coordinates.add(new GeoCoordinates(52.53894, 13.39194));
    coordinates.add(new GeoCoordinates(52.5309, 13.3946));
    coordinates.add(new GeoCoordinates(52.53032, 13.37409));

    GeoPolygon geoPolygon;
    try {
        geoPolygon = new GeoPolygon(coordinates);
    } catch (InstantiationErrorException e) {
        // Thrown when less than three vertices.
        return null;
    }

    Color fillColor = Color.valueOf(0, 0.56f, 0.54f, 0.63f); // RGBA
    MapPolygon mapPolygon = new MapPolygon(geoPolygon, fillColor);

    return mapPolygon;
}
private fun createPolygon(): MapPolygon? {
    val coordinates = ArrayList<GeoCoordinates>()
    // Note that a polygon requires a clockwise or counter-clockwise order of the coordinates.
    coordinates.add(GeoCoordinates(52.54014, 13.37958))
    coordinates.add(GeoCoordinates(52.53894, 13.39194))
    coordinates.add(GeoCoordinates(52.5309, 13.3946))
    coordinates.add(GeoCoordinates(52.53032, 13.37409))

    val geoPolygon: GeoPolygon
    try {
        geoPolygon = GeoPolygon(coordinates)
    } catch (e: InstantiationErrorException) {
        // Less than three vertices.
        return null
    }

    val fillColor: Color = Color.valueOf(0f, 0.56f, 0.54f, 0.63f) // RGBA
    val mapPolygon = MapPolygon(geoPolygon, fillColor)

    return mapPolygon
}

MapPolygonは3つの要素で構成されます。

  • 地図上にポリゴンを配置する場所を定義する 3 つ以上の地理座標のリスト。
  • この座標のリストを含むGeoPolygon。
  • Color はポリゴン領域の塗りつぶし色を定義します。

ポリゴンは 3 つ以上のポイントによって定義されるため、少なくとも 3 つの GeoCoordinates を含む配列リストを作成する必要があります。これを行わなかった場合は、例外がスローされます。スクリーンショットの例を参照してください。

マップ ポリゴンを使用して、複雑な塗りつぶしシェイプや塗りつぶしなしのシェイプを作成できます。ただし、自己交差するポリゴンは、座標がリストの順序で結合されているため、望ましくない結果につながる可能性があります。別の方法として、複数のポリゴンを追加することや、目的のシェイプのアウトラインに表示されているとおりに座標を追加することができます。

マップ ポリラインとは異なり、マップ ポリゴンのアウトラインは、リストの最後の座標と最初の座標の間で自動的に接続されます。

1 つ以上のマップ ポリゴンを作成したら、次のようにしてマップ シーンに追加できます。

MapPolygon mapPolygon = createPolygon();
MapScene mapScene = mapView.getMapScene();
mapScene.addMapPolygon(mapPolygon);
val mapPolygon = createPolygon()
val mapScene = mapView.mapScene
mapScene.addMapPolygon(mapPolygon!!)

マップポリゴンがすでにマップシーンに添付されている場合は、さらにそれを追加しようとする試みは無視されます。

スクリーンショット:ポリゴンを表示。

マップビューでは1つのシーンのみが許可され、すべてのマップアイテムがそのシーンに直接配置されます。マップアイテムをグループ化する場合は、配列を使用してマップアイテムを整理し、個別に追加または削除できます。

mapPolygon を地図から直ちに削除するには、次のように呼び出します。

mapScene.removeMapPolygon(mapPolygon);
mapScene.removeMapPolygon(mapPolygon)

注

MapPolygon アイテムは選択可能で、アイテムを選択するときに取得できる Metadata を保存できます。例については、以下のマップマーカーのセクションを参照してください。

MapMeasureRangeアイテムのリストを設定すると、MapPolygonの表示を現在のズーム レベルに応じて調整できます。

注

描画順序を設定することで、どのアイテムを重ねて描画するかを指定できます。現時点では、描画順序の設定は、同じタイプのクラス内の順序のみを定義するため、他のマップアイテムとの関係には影響しません。

マップに円を追加する

円形は、地図上の領域を強調表示したり、透明なハローを描いたり、特定の地点を示したりするのに便利です。円は、技術的には三角形のポリゴン図形のシーケンスとしてレンダリングされます。

そのため、円は GeoCircle を使用した MapPolygon インスタンスとして作成できます。

private MapPolygon createMapCircle() {
    float radiusInMeters = 300;
    GeoCircle geoCircle = new GeoCircle(new GeoCoordinates(52.530932, 13.384915), radiusInMeters);

    GeoPolygon geoPolygon = new GeoPolygon(geoCircle);
    Color fillColor = Color.valueOf(0, 0.56f, 0.54f, 0.63f); // RGBA
    MapPolygon mapPolygon = new MapPolygon(geoPolygon, fillColor);

    return mapPolygon;
}
private fun createMapCircle(): MapPolygon {
    val radiusInMeters = 300f
    val geoCircle = GeoCircle(GeoCoordinates(52.51760485151816, 13.380312380535472), radiusInMeters.toDouble())

    val geoPolygon = GeoPolygon(geoCircle)
    val fillColor: Color = Color.valueOf(0f, 0.56f, 0.54f, 0.63f) // RGBA
    val mapPolygon = MapPolygon(geoPolygon, fillColor)

    return mapPolygon
}

円はポリゴンの特殊なシェイプであるため、前述のMapPolygonのセクションで示したように、円をマップシーンに追加 (または削除) できます。

スクリーンショット:円を表示。

マップマーカーを追加する

マップ マーカー使用して、地図上の位置を正確に指すことができます。マップ マーカーは常に、地図上にレンダリングされている他のアイテムの上に描画されます。

次のコードにより、マップ マーカーを地図に追加します。

MapImage mapImage = MapImageFactory.fromResource(context.getResources(), R.drawable.here_car);
MapMarker mapMarker = new MapMarker(geoCoordinates, mapImage);

mapView.getMapScene().addMapMarker(mapMarker);
val mapImage = MapImageFactory.fromResource(context.getResources(), R.drawable.here_car)
val mapMarker = MapMarker(geoCoordinates, mapImage)

mapView.mapScene.addMapMarker(mapMarker)

この例では、リソースから PNG (「here_care.png」) を読み込み、そこから MapImage を作成します。その後、このMapImageをMapMarkerインスタンスに設定します。

上記では、画像がデフォルトのピクセル サイズでロードされます。MapImage(@NonNull byte[] imageData, @NonNull ImageFormat imageFormat, long width, long height) を使用すると、カスタム サイズを設定できます。

注

HERE SDK for Android は、透過性 (アルファ チャネル) の有無にかかわらず PNG リソースをサポートする他、Android でネイティブにサポートされているその他すべての一般的なビットマップ リソースもサポートします。ベクター グラフィックは上記のファクトリではサポートされておらず、これは Android Studio 内で SVG から XML 表現に変換された場合も同じです。ただし、オーバーロードされた MapImage コンストラクタを使用して、SVG Tiny 形式でグラフィックをロードすることはできます。

静止画像のアセットとは対照的に、SVG アセットはその XML コンテンツのみを更新する必要があるため、さまざまなコンテンツを表示するのにも役立ちます。静止画像のアセットと SVG アセットは、その場で更新できます。別の方法として、より複雑なコンテンツについては、MapViewPins を使用することをお勧めします (以下を参照)。

画像を表示するには、MapMarkerをマップシーンに追加する必要があります。MapImageは、指定されたgeoCoordinatesを中心として表示されます。

スクリーンショット:ランダムに配置されたマップ画像を表示。上にある赤いマップ円は、マーカーの位置を示す。

マーカーが地図に追加された後でgeoCoordinatesを更新することもできます。mapMarker.setCoordinates()を呼び出すと、マーカーは直ちに新しい位置に表示されます。

注

マップ マーカーが地図に追加される時系列的な順序により、どのマップ マーカーが最初にレンダリングされるかが決まります。これは、明示的な描画順序を設定することで調整できます。現時点では、描画順序の設定は、同じタイプのクラス内の順序のみを定義するため、他のマップアイテムとの関係には影響しません。

マップ マーカーを削除するには、次のように呼び出します。

mapView.getMapScene().removeMapMarker(mapMarker);
mapView.getMapScene().removeMapMarker(mapMarker)

List<MapMarker> タイプのマップ マーカーのリストを一度に削除することもできます。

mapView.getMapScene().removeMapMarkers(mapMarkerList);
mapView.getMapScene().removeMapMarkers(mapMarkerList)

同様に、addMapMarkers(mapMarkerList) を使用してバッチ呼び出しで複数のマップ マーカーを追加できます。

HERE SDK は、MapMarker アイテムの高度にカスタマイズ可能なアニメーションのサポートも提供しています。フェード イン/アウト アニメーションは、1 行のコードで適用できます。

// Optionally, enable a fade in-out animation.
mapMarker.setFadeDuration(Duration.ofSeconds(3));
// Optionally, enable a fade in-out animation.
mapMarker.setFadeDuration(Duration.ofSeconds(3))

マーカーが MapView に追加または削除されたときに、マーカーがアニメーションでフェードインまたはフェードアウトします。マーカーがビューポートに戻ったとき、つまり地図をパンしてマーカーが再び表示されるようになったときにも、アニメーションが再生されます。

マーカーを移動するなどの高度なカスタム アニメーションは、MapMarkerAnimation クラスを使用します。

MapMeasureRangeアイテムのリストを設定すると、MapMarkerの表示を現在のズーム レベルに応じて調整できます。

さらに多くの機能を利用でき、たとえば不透明度の値を設定してマーカーを透明にすることができます。

さまざまな解像度に対応する Retina サポート

SVG 画像は画質を損なうことなく拡大/縮小できますが、PNG などのピクセルベースの画像形式については、Android プラットフォームではさまざまなピクセル密度の解像度に依存するフォルダーを提供することで、Retina をネイティブにサポートしています。

  • drawable-mdpi - デフォルト。アセットサイズの例:100 x 100 ピクセル。
  • drawable-xhdpi - Retina ディスプレイ用。2 倍のアセット サイズ:200 x 200 ピクセル。
  • drawable-xxhdpi - Retina HD ディスプレイ用。3 倍のアセット サイズ:300 x 300 ピクセル。
  • ...

これには特定の HERE SDK コードは必要ありません。Android は、デバイスの画面とファイル名に応じて適切な画像をロードします。アプリでは、上述の MapMarker のコード スニペットでも示したように、MapImageFactory.fromResource(context.getResources(), R.drawable.poi) を使用して画像をネイティブに読み込むため、フォルダーを省略し、Android によって適切なアセットがロードされます。結果として得られる画像は、画面上では同じサイズになりますが、大きな画面ではより高品質のアセットが表示されます。使用例については、MapItems のサンプル アプリを参照してください。アセット フォルダーには、さまざまな解像度が含まれています。このような方法は、より高い解像度で詳細を表示するアセットを作成した場合に理にかなっています。解像度に依存するアセットを省略した場合、Android は大きな画面ではぼやけて見えるアセットを拡大/縮小する場合があります。

アンカー付き POI マーカー

デフォルトでは、各画像は指定された位置を中心として配置されますが、一部のタイプのマーカーについては、この配置を変更する場合があります。例として POI マーカーがあります。通常、このマーカーは下中央部分で位置を指します。

そのため、画像がレンダリングされる場所をシフトする必要があります。デフォルトの中心は (0.5, 0.5) です。設定されたGeoCoordinatesの位置を、ビューの右下隅で指すようにするには、アンカーポイントを (1, 1) に設定します。

アンカー ポイントを使用すると、マーカーをレンダリングする場所を簡単に指定できます。左上隅は (0, 0) のアンカー ポイントと等しく、右下隅は (1, 1) のアンカー ポイントと等しくなります。ビューの大きさに関係なく、幅または高さの半分のポイントは常に0.5になります。これは、正規化されたテクスチャUV座標の概念に似ています。

図:正規化されたアンカーポイントでは、マップマーカーの内部または外部の任意の場所を指定できる。

位置を指すようにPOIをシフトする場合は、デフォルトの中央の位置 (0.5) はそのまま使用できますが、画像を上方向に1ポイント分シフトする必要があります。「1」は、画像の高さと同じ長さです。「1」よりも大きい値または「0」よりも小さい値を指定して、画像を任意の場所に移動することもできます。「2」は画像の 2 倍の高さを表します。

アンカー付き POI マーカーを地図に追加するには、次の例を参照してください。

MapImage mapImage = MapImageFactory.fromResource(context.getResources(), R.drawable.poi);

// The bottom, middle position should point to the location.
// By default, the anchor point is set to 0.5, 0.5.
Anchor2D anchor2D = new Anchor2D(0.5F, 1);
MapMarker mapMarker = new MapMarker(geoCoordinates, mapImage, anchor2D);

mapView.getMapScene().addMapMarker(mapMarker);
val mapImage = MapImageFactory.fromResource(context.getResources(), R.drawable.poi)

// The bottom, middle position should point to the location.
// By default, the anchor point is set to 0.5, 0.5.
val anchor2D = Anchor2D(0.5, 1.0)
val mapMarker = MapMarker(geoCoordinates, mapImage, anchor2D)

mapView.mapScene.addMapMarker(mapMarker)

上記の例では、"poi.png" という名前のカスタム POI 画像がさまざまな解像度でプロジェクトに追加されています。Android プラットフォームは、デバイスのディスプレイ密度に基づいて適切な画像解像度を選択します。その方法については、付属のサンプルアプリを参照してください。

スクリーンショット:ランダムに配置されたマップマーカーを表示。赤いマップ円は、マーカーのアンカー位置を示す。

ポリラインとは異なり、各MapImageは地図の拡大/縮小率にかかわらず、サイズが維持されます。

テキスト付きのマップ マーカー

MapMarker では、アウトラインの色やテキストのサイズなど、カスタマイズ可能なスタイル オプションのある文字列を表示することもできます。

文字列は mapMarker.setText("Hello Text") を呼び出すことでいつでも設定できます。また、既存のマーカーのテキストを動的に更新することもできます。

オプションをリストとして設定し、テキストの有無にかかわらず複数のMapMarker項目が重なり合う場合にテキストを再配置する優先順位を定義できます。リストの最初の項目がデフォルトの配置を表します。ズーム アウトするなどしてマーカーが近づくと、重なり合うテキストはマーカーとテキストが完全に消えるまでリスト内の次の利用可能な位置に移動します。配置の優先順位が機能するには、setOverlapAllowed(false) も呼び出す必要があります。デフォルトでは、マーカーは重なり合うことができ、テキストは下部にのみ表示されます。単一の配置オプションは、配置が変更されないことを意味します。

カスタムフォントを使用したマップマーカー

必要に応じて、TextStyleを使用してフォントのレンダリング方法をカスタマイズできます。さらに、テキストをレンダリングするためのカスタムフォントアセットを指定できます。これを行うには、AssetManagerでフォントをグローバルに登録してから、MapMarkerインスタンスに対してTextStyleを介してフォント名を設定します。カスタムフォントを追加するには、次の手順に従います。

  • カスタムフォントファイルをプロジェクトのアセットフォルダーに追加します。
  • AssetManagerクラスを使用し、assetManager.registerFont(...)メソッドを呼び出してフォントを登録します。
  • 登録すると、カスタムフォントをHERE SDK内で使用できるようになります。

次の例はカスタムフォントを登録する方法を示しています。

String fontFileName = "SimpleSans.ttf";
AssetsManager assetManager = new AssetsManager(mapView.getMapContext());

// "SimpleSans" specifies the font name to be referenced wherever required.
assetManager.registerFont("SimpleSans", fontFileName);
val fontFileName = "SimpleSans.ttf"
val assetManager = AssetsManager(mapView.mapContext)

// "SimpleSans" specifies the font name to be referenced wherever required.
assetManager.registerFont("SimpleSans", fontFileName)

サポートされているフォント形式については、APIリファレンスを参照してください。

スクリーンショット:テキスト付きのマップマーカーを表示しています。

以下の例は、先ほど登録したカスタムフォントで使用可能なTextStyleオプションの利用方法を示しています。

MapMarker.TextStyle textStyleCurrent = mapMarker.getTextStyle();
MapMarker.TextStyle textStyleNew = mapMarker.getTextStyle();
double textSizeInPixels = 30;
double textOutlineSizeInPixels = 5;

// Placement priority is based on order. It is only effective when
// overlap is disallowed. The below setting will show the text
// at the bottom of the marker, but when the marker or the text overlaps
// then the text will swap to the top before the marker disappears completely.
// Note: By default, markers do not disappear when they overlap.
List<MapMarker.TextStyle.Placement> placements = new ArrayList<>();
placements.add(MapMarker.TextStyle.Placement.BOTTOM);
placements.add(MapMarker.TextStyle.Placement.TOP);
mapMarker.setOverlapAllowed(false);

try {
    textStyleNew = new MapMarker.TextStyle(
            textSizeInPixels,
            textStyleCurrent.getTextColor(),
            textOutlineSizeInPixels,
            textStyleCurrent.getTextOutlineColor(),
            placements,
            "SimpleSans"
            );
} catch (MapMarker.TextStyle.InstantiationException e) {
    // An error code will indicate what went wrong, for example, when negative values are set for text size.
    Log.e("TextStyle", "Error code: " + e.error.name());
}

mapMarker.setText("Hello Text");
mapMarker.setTextStyle(textStyleNew);
val textStyleCurrent: MapMarker.TextStyle = mapMarker.getTextStyle()
var textStyleNew: MapMarker.TextStyle = mapMarker.getTextStyle()
val textSizeInPixels = 30.0
val textOutlineSizeInPixels = 5.0

// Placement priority is based on order. It is only effective when
// overlap is disallowed. The below setting will show the text
// at the bottom of the marker, but when the marker or the text overlaps
// then the text will swap to the top before the marker disappears completely.
// Note: By default, markers do not disappear when they overlap.
val placements: MutableList<Placement> = ArrayList()
placements.add(Placement.BOTTOM)
placements.add(Placement.TOP)
mapMarker.setOverlapAllowed(false)

try {
    textStyleNew = MapMarker.TextStyle(
        textSizeInPixels,
        textStyleCurrent.textColor,
        textOutlineSizeInPixels,
        textStyleCurrent.textOutlineColor,
        placements,
        "SimpleSans"
    )
} catch (e: MapMarker.TextStyle.InstantiationException) {
    // An error code will indicate what went wrong, for example, when negative values are set for text size.
    Log.e("TextStyle", "Error code: " + e.error.name)
}

mapMarker.setText("Hello Text")
mapMarker.setTextStyle(textStyleNew)

異なる名前で複数のフォントを登録できます。同じフォント名での繰り返しの登録は無視されます。

マップマーカーを選択する

地図上にマップ マーカーを追加したら、タップ ジェスチャー リスナーを使用して、ユーザーがマップ マーカーをタップしたかどうかを確認できます。

private void setTapGestureHandler() {
    mapView.getGestures().setTapListener(new TapListener() {
        @Override
        public void onTap(@NonNull Point2D touchPoint) {
            pickMapMarker(touchPoint);
        }
    });
}

private void pickMapMarker(final Point2D touchPoint) {
    Point2D originInPixels = new Point2D(touchPoint.x, touchPoint.y);
    Size2D sizeInPixels = new Size2D(1, 1);
    Rectangle2D rectangle = new Rectangle2D(originInPixels, sizeInPixels);

    // Creates a list of map content type from which the results will be picked.
    // The content type values can be MAP_CONTENT, MAP_ITEMS and CUSTOM_LAYER_DATA.
    ArrayList<MapScene.MapPickFilter.ContentType> contentTypesToPickFrom = new ArrayList<>();

    // MAP_CONTENT is used when picking embedded carto POIs, traffic incidents, vehicle restriction etc.
    // MAP_ITEMS is used when picking map items such as MapMarker, MapPolyline, MapPolygon etc.
    // Currently we need map markers so adding the MAP_ITEMS filter.
    contentTypesToPickFrom.add(MapScene.MapPickFilter.ContentType.MAP_ITEMS);
    MapScene.MapPickFilter filter = new MapScene.MapPickFilter(contentTypesToPickFrom);

    // If you do not want to specify any filter you can pass filter as NULL and all of the pickable contents will be picked.
    mapView.pick(filter, rectangle, new MapViewBase.MapPickCallback() {
        @Override
        public void onPickMap(@Nullable MapPickResult mapPickResult) {
            if (mapPickResult == null) {
                // An error occurred while performing the pick operation.
                return;
            }
            PickMapItemsResult pickMapItemsResult = mapPickResult.getMapItems();

            // Note that 3D map markers can't be picked yet. Only marker, polygon and polyline map items are pickable.
            List<MapMarker> mapMarkerList = pickMapItemsResult.getMarkers();
            int listSize = mapMarkerList.size();
            if (listSize == 0) {
                return;
            }
            MapMarker topmostMapMarker = mapMarkerList.get(0);

            showDialog("Map marker picked:", "Location: " +
                    topmostMapMarker.getCoordinates().latitude + ", " +
                    topmostMapMarker.getCoordinates().longitude);
        }
    });
}
private fun setTapGestureHandler() {
    mapView.gestures.tapListener = TapListener { touchPoint -> pickMapMarker(touchPoint) }
}

private fun pickMapMarker(touchPoint: Point2D) {
    val originInPixels = Point2D(touchPoint.x, touchPoint.y)
    val sizeInPixels = Size2D(1.0, 1.0)
    val rectangle = Rectangle2D(originInPixels, sizeInPixels)

    // Creates a list of map content type from which the results will be picked.
    // The content type values can be MAP_CONTENT, MAP_ITEMS and CUSTOM_LAYER_DATA.
    val contentTypesToPickFrom = ArrayList<MapScene.MapPickFilter.ContentType>()

    // MAP_CONTENT is used when picking embedded carto POIs, traffic incidents, vehicle restriction etc.
    // MAP_ITEMS is used when picking map items such as MapMarker, MapPolyline, MapPolygon etc.
    // Currently we need map markers so adding the MAP_ITEMS filter.
    contentTypesToPickFrom.add(MapScene.MapPickFilter.ContentType.MAP_ITEMS)
    val filter = MapScene.MapPickFilter(contentTypesToPickFrom)

    // If you do not want to specify any filter you can pass filter as NULL and all of the pickable contents will be picked.
    mapView.pick(filter, rectangle, MapViewBase.MapPickCallback { mapPickResult ->
        if (mapPickResult == null) {
            // An error occurred while performing the pick operation.
            return@MapPickCallback
        }
        val pickMapItemsResult = mapPickResult.mapItems

        // Note that MapMarker items contained in a cluster are not part of pickMapItemsResult.getMarkers().
        handlePickedMapMarkerClusters(pickMapItemsResult)

        // Note that 3D map markers can't be picked yet. Only marker, polygon and polyline map items are pickable.
        val mapMarkerList = pickMapItemsResult!!.markers
        val listSize = mapMarkerList.size
        if (listSize == 0) {
            return@MapPickCallback
        }
        val topmostMapMarker = mapMarkerList[0]

        val metadata: Metadata? = topmostMapMarker.metadata
        if (metadata != null) {
            var message: String? = "No message found."
            val string: String? = metadata.getString("key_poi")
            if (string != null) {
                message = string
            }

            val stringMarkerText: String? = metadata.getString("key_poi_text")
            if (stringMarkerText != null) {
                // You can update text for a marker on-the-fly.
                topmostMapMarker.text = "Marker was picked."
                message = stringMarkerText
            }

            if (message != null) {
                showDialog("Map marker picked", message)
            }
            return@MapPickCallback
        }
        showDialog(
            "Map marker picked:", "Location: " +
                    topmostMapMarker.coordinates.latitude + ", " +
                    topmostMapMarker.coordinates.longitude
        )
    })
}

タップ ジェスチャーが検出されたら、すぐに画面上のタップされた位置のビュー座標を使用して、その位置の周囲にあるマップ マーカーをマップ ビューに要求できます。ほとんどの場合、半径を 2 ピクセルに指定すれば十分です。すると、PickMapItemsCallback により、MapPolygon や MapMarker などの検出されたマップ アイテムにアクセスできるようになります。

注

慣例として、HERE SDK はジェスチャー イベントなどの繰り返し発生するイベントにリスナーを使用します。1 回ごとに処理する必要がある単一のイベントには、コールバックが必要です。

同じタイプのアイテムを選択する場合、オーバーライドされた equals() メソッドを呼び出してインスタンスを比較できます。

メタデータを追加する

多くの場合、ユーザーは表示されたマーカーを操作しようとします。たとえば、検索結果をタップしてレストランの詳細を確認しようとします。そのため、MapMarker は Metadata クラスのインスタンスを保持し、さまざまなタイプのデータを添付できます。カスタム タイプもサポートされます。

Metadata は複数のキー/valueのペアを保持できます。以下では、"key_poi" という名前の新しいキーを作成し、マーカーのタイプに関する情報を含む値として String を設定します。

Metadata metadata = new Metadata();
metadata.setString("key_poi", "This is a POI.");
mapMarker.setMetadata(metadata);
val metadata = Metadata()
metadata.setString("key_poi", "This is a POI.")
mapMarker.metadata = metadata

必要に応じて、任意の情報を設定できます。Metadata インスタンスのコンテンツを読もうとする場合は、キーに保存されているデータ (この例では "key_poi") を要求するだけです。

Metadata metadata = topmostMapMarker.getMetadata();
if (metadata != null) {
    String message = "No message found.";
    String string = metadata.getString("key_poi");
    if (string != null) {
        message = string;
    }
    showDialog("Map Marker picked", message);
    return;
}
val metadata: Metadata = topmostMapMarker.getMetadata()
if (metadata != null) {
    var message: String? = "No message found."
    val string = metadata.getString("key_poi")
    if (string != null) {
        message = string
    }
    showDialog("Map Marker picked", message!!)
    return
}

デフォルトでは、MapMarker インスタンスに Metadata は含まれないため、mapMarker.getMetadata() で nullが返される可能性があります。キーによってアクセスされるデータも、Metadataオブジェクトにそのような情報が含まれない場合はnullになる場合があります。

情報が含まれる場合は、キーの "key_poi" に保存されている String を探し、ヘルパー メソッドを呼び出して、含まれている String をユーザーに提示します。好みに応じて任意の文字列をキーとして選択できますが、一意のキーを使用する必要があります。そうしないと、別のデータ項目に保存されているコンテンツが上書きされます。サンプルの完全なソース コードを確認するには、「MapMarker」のサンプル アプリを参照してください。

注

CustomMetadataValue インターフェースを使用して、カスタム オブジェクトを Metadata に保存することもできます。「検索」セクションで、検索結果のデータ オブジェクトが全体として保存されている例を参照できます。

マップ マーカー クラスターを追加する

ズーム レベルによっては、複数の MapMarker アイテムが重なる場合があります。MapMarkerCluster クラスを使用すると、複数の MapMarker アイテムをグループ化して視覚的な混乱を減らすことができます。重複しているマーカーは、単一の画像表現に置き換えられます。このようなクラスター画像は選択でき、これにはその中に含まれるマーカーのみが含まれています。

次のコードは、複数の MapMarker アイテムを含むクラスターを作成する方法を示しています。

public void showMapMarkerCluster() {
    MapImage clusterMapImage = MapImageFactory.fromResource(context.getResources(), R.drawable.green_square);

    // Defines a text that indicates how many markers are included in the cluster.
    MapMarkerCluster.CounterStyle counterStyle = new MapMarkerCluster.CounterStyle();
    counterStyle.textColor = new Color(0, 0, 0, 1); // Black
    counterStyle.fontSize = 40;
    counterStyle.maxCountNumber = 9;
    counterStyle.aboveMaxText = "+9";

    MapMarkerCluster mapMarkerCluster = new MapMarkerCluster(
            new MapMarkerCluster.ImageStyle(clusterMapImage), counterStyle);
    mapView.getMapScene().addMapMarkerCluster(mapMarkerCluster);
    mapMarkerClusterList.add(mapMarkerCluster);

    for (int i = 0; i < 10; i++) {
        mapMarkerCluster.addMapMarker(createRandomMapMarkerInViewport("" + i));
    }
}
fun showMapMarkerCluster() {
    val clusterMapImage = MapImageFactory.fromResource(context.resources, R.drawable.green_square)

    // Defines a text that indicates how many markers are included in the cluster.
    val counterStyle = MapMarkerCluster.CounterStyle()
    counterStyle.textColor = Color(0f, 0f, 0f, 1f) // Black
    counterStyle.fontSize = 40.0
    counterStyle.maxCountNumber = 9
    counterStyle.aboveMaxText = "+9"

    val mapMarkerCluster = MapMarkerCluster(
        MapMarkerCluster.ImageStyle(clusterMapImage), counterStyle
    )
    mapView.mapScene.addMapMarkerCluster(mapMarkerCluster)
    mapMarkerClusterList.add(mapMarkerCluster)

    for (i in 0..9) {
        mapMarkerCluster.addMapMarker(createRandomMapMarkerInViewport("" + i))
    }
}

複数の重複するマップ マーカーのクラスターを表すのに使用する MapImage を設定できます。

MapMarker アイテムは、すでに地図に表示されている MapMarkerCluster に対して、追加または削除することができます。すべてのマーカーを含むクラスターを削除する場合は、次のように呼び出します。

mapView.getMapScene().removeMapMarkerCluster(mapMarkerCluster);
mapView.getMapScene().removeMapMarkerCluster(mapMarkerCluster)

クラスターに含まれている MapMarker アイテムは、pickMapItemsResult.getMarkers() の一部ではありません。そのため、pickMapItems() の呼び出しから選択結果を受け取った後、以下に示すコードを使用してそれらを個別に選択できます (MapMarker のセクションを参照)。

private void handlePickedMapMarkerClusters(PickMapItemsResult pickMapItemsResult) {
    List<MapMarkerCluster.Grouping> groupingList = pickMapItemsResult.getClusteredMarkers();
    if (groupingList.size() == 0) {
        return;
    }

    MapMarkerCluster.Grouping topmostGrouping = groupingList.get(0);
    int clusterSize = topmostGrouping.markers.size();
    if (clusterSize == 0) {
        // This cluster does not contain any MapMarker items.
        return;
    }
    if (clusterSize == 1) {
        showDialog("Map marker picked",
                "This MapMarker belongs to a cluster. Metadata: " + getClusterMetadata(topmostGrouping.markers.get(0)));
    } else {
        String metadata = "";
        for (MapMarker mapMarker: topmostGrouping.markers) {
            metadata += getClusterMetadata(mapMarker);
            metadata += " ";
        }
        showDialog("Map marker cluster picked",
                "Number of contained markers in this cluster: " + clusterSize + ". " +
                "Contained Metadata: " + metadata + ". " +
                "Total number of markers in this MapMarkerCluster: " + topmostGrouping.parent.getMarkers().size());
    }
}

private String getClusterMetadata(MapMarker mapMarker) {
    Metadata metadata = mapMarker.getMetadata();
    String message = "No metadata.";
    if (metadata != null) {
        String string = metadata.getString("key_cluster");
        if (string != null) {
            message = string;
        }
    }
    return message;
}
private fun handlePickedMapMarkerClusters(pickMapItemsResult: PickMapItemsResult?) {
    val groupingList = pickMapItemsResult!!.clusteredMarkers
    if (groupingList.size == 0) {
        return
    }

    val topmostGrouping = groupingList[0]
    val clusterSize = topmostGrouping.markers.size
    if (clusterSize == 0) {
        // This cluster does not contain any MapMarker items.
        return
    }
    if (clusterSize == 1) {
        showDialog(
            "Map marker picked",
            "This MapMarker belongs to a cluster. Metadata: " + getClusterMetadata(topmostGrouping.markers[0])
        )
    } else {
        var metadata = ""
        for (mapMarker in topmostGrouping.markers) {
            metadata += getClusterMetadata(mapMarker)
            metadata += " "
        }
        showDialog(
            "Map marker cluster picked",
            "Number of contained markers in this cluster: " + clusterSize + ". " +
                    "Contained Metadata: " + metadata + ". " +
                    "Total number of markers in this MapMarkerCluster: " + topmostGrouping.parent.markers.size
        )
    }
}

private fun getClusterMetadata(mapMarker: MapMarker): String {
    val metadata: Metadata? = mapMarker.metadata
    var message = "No metadata."
    if (metadata != null) {
        val string: String? = metadata.getString("key_cluster")
        if (string != null) {
            message = string
        }
    }
    return message
}

このコードにより、クラスターが選択されたかどうかを検出し、含まれているマーカーについてユーザーに通知できます。また、markersリストに1つのアイテムのみが含まれている場合は、単一のMapMarkerインスタンスを特定できます。

複数のマップマーカークラスター。番号は含まれているマーカーを示す。

通常、必要なMapMarkerClusterインスタンスは1つだけです。これを超えると、最上位のクラスターのみが処理されます。

マーカーの距離に応じて、複数のクラスター画像が同じMapMarkerClusterインスタンスに表示される場合があります。各画像には、クラスター化されたマーカーの総数のサブセットが含まれます。

GitHubでの例については、「MapItems」サンプルアプリ (JavaおよびKotlin版) を参照してください。

3Dマップマーカーを追加する

HERE SDK を使用すると、カスタム 3D モデルを地図に追加できます。必要に応じて、これらのモデルをブレンド Color と一緒にテクスチャ化することができます。共通の .obj ファイル形式を使用して、3D モデルのジオメトリーを指定します。3Dモデルは無料のThree.jsオンラインエディターなどの、一般的な3Dモデリングソフトウェアを使用して生成できます。

この例で使用するobstacle.obj 3Dオブジェクト。

objファイル形式では、頂点、法線、テクスチャ座標、面を指定して、モデルのレンダリング方法を定義します。作成されたモデルは、その座標を更新することにより、地図内で動かすことができます。モデルの向きは、方位、ピッチ、ロールを更新することで変更できます。

HERE SDK ではマテリアル ファイル (*。mtl) およびマルチ テクスチャリングはサポートされないことに注意してください。

obj 形式で定義されたモデルとモデルをラップするテクスチャを作成したら、両方のファイルをプロジェクトの assets ディレクトリに追加します。例:app/src/main/assets/...

以下では、obj ファイルと PNG テクスチャを追加しました。

  • app/src/main/assets/obstacle.obj
  • app/src/main/assets/obstacle_texture.png
この例で使用するobstacle_texture.pngテクスチャ。

ヒントとして、AndroidのAssetManagerを使用して、次のようにファイルが存在することを確認します。

private void checkIfFileExistsInAssetsFolder(String fileName) {
    AssetManager assetManager = context.getAssets();
    try {
        assetManager.open(fileName);
    } catch (IOException e) {
        Log.e("MapMarkerExample", "Error: File not found!");
    }
}
private fun checkIfFileExistsInAssetsFolder(fileName: String) {
    val assetManager = context.assets
    try {
        assetManager.open(fileName)
    } catch (e: IOException) {
        Log.e("MapItemsExample", "Error: File not found!")
    }
}

これにより、ファイルが予期されたファイルの場所に存在しない場合は例外が返されます。

これで、次のコードを使用して MapMarker3D を地図に追加できるようになります。

String geometryFile = "obstacle.obj";
String textureFile = "obstacle_texture.png";
checkIfFileExistsInAssetsFolder(geometryFile);
checkIfFileExistsInAssetsFolder(textureFile);

MapMarker3DModel mapMarker3DModel = new MapMarker3DModel(geometryFile, textureFile);
MapMarker3D mapMarker3D = new MapMarker3D(geoCoordinates, mapMarker3DModel);
mapMarker3D.setScale(6);
mapMarker3D.setDepthCheckEnabled(true);

mapView.getMapScene().addMapMarker3d(mapMarker3D);
val geometryFile = "obstacle.obj"
val textureFile = "obstacle_texture.png"
checkIfFileExistsInAssetsFolder(geometryFile)
checkIfFileExistsInAssetsFolder(textureFile)

val mapMarker3DModel = MapMarker3DModel(geometryFile, textureFile)
val mapMarker3D = MapMarker3D(geoCoordinates, mapMarker3DModel)
mapMarker3D.scale = 6.0
mapMarker3D.isDepthCheckEnabled = true

mapView.mapScene.addMapMarker3d(mapMarker3D)

上の例では、両方のアセット ファイルを、モデルを定義する MapMarker3DModel コンストラクタに渡します。同様に、MapImage 要素ですでに説明したとおり、利用可能な MapMarker3D コンストラクタのいずれかにモデルを渡すことができます。また、倍率を設定して、モデルが 6 倍の大きさで表示されるようにします。obj モデルは3D座標空間で定義されるため、長さの単位は含まれません。

MapMarker3D アイテムは、他のマップ アイテムと同じように MapScene を介して追加および削除できます。

注

テクスチャのサイズは1ピクセル以上である必要があります。透明なピクセルをテクスチャ画像として追加する場合は、テクスチャなしのモデルを、Color (3 番目のパラメーターとして MapMarker3DModel コンストラクタに渡すことができる) とブレンドすることができます。

以下に、表示例を示します。モデルは、指定された地理座標の中心に配置されます。モデルの中心は、その座標系の原点によって定義されます。

傾斜した地図上に表示される2つのカスタム3Dマップマーカー。

setDepthCheckEnabledメソッドは、3Dマーカーの頂点の深さをレンダリング中に考慮するかどうかを指定します。デフォルトでは、これはfalseに設定されています。

  • setDepthCheckEnabled が false に設定されている場合は、MapMarker3D アイテムは常に、地図に表示されている他のアイテムの上に描画されます。
  • setDepthCheckEnabledが true に設定されている場合は、3D マーカーが建物の形状などの他のマップ オブジェクトによって隠れる可能性があります。setDepthCheckEnabled メソッドは、内側と外側の領域があるトーラスのような複雑な 3D オブジェクトを描画するのに便利です。

2D MapMarker アイテムと同様に、MapMarker3D は地図を拡大/縮小してもサイズは変わりませんが、地図と一緒に回転します。

3D マーカーを地図に合わせて拡大/縮小させるにはどうすればよいでしょうか。

そのためには、RenderSize.Unit を受け取る MapMarker3D 用の簡易コンストラクタを使用します。たとえば、densityIndependentPixels を使用して拡大/縮小を禁止すると、結果として得られるマーカーはズーム レベルに依存しない、固定サイズで作成されます。拡大/縮小を許可するには、RenderSize.Unitとmetersを使用します。

MapMeasureRangeアイテムのリストを設定すると、MapMarker3Dの表示を現在のズーム レベルに応じて調整できます。

MapMarker3D の透明度を変更する場合は、opacity 係数を指定します。この係数はマーカーのテクスチャのアルファ チャネルに適用されます。renderInternalsEnabledフラグを設定することで、前面に配置されたポリゴンによって隠された内部ジオメトリーをレンダリングするかどうかを指定できます。

フラット マップ マーカーを追加する

デフォルトでは、MapMarker は地図とともに回転せず、また地図を傾けても傾きません。これは、MapMarker3Dを使用してフラットにすることで変更できます。実際、フラット マップ マーカーは 3D 空間の Z 軸に 0 の長さを含む、MapMarker3D アイテムの特殊なケースです。

MapImage パラメーターを受け取る簡易コンストラクタを使用して、フラットな MapMarker3D オブジェクトを作成できます。拡大/縮小を禁止するには、RenderSize.Unit と densityIndependentPixels を使用します。結果として得られるマーカーは、ズーム レベルに依存しない、固定サイズで作成されます。拡大/縮小を許可するには、RenderSize.UnitとMETERSを使用します。

結果として得られるフラットマーカーは、地図とともに傾き、地図を回転すると一緒に回転します。

MapImage mapImage = MapImageFactory.fromResource(context.getResources(), R.drawable.poi);

// The default scale factor of the map marker is 1.0. For a scale of 2, the map marker becomes 2x larger.
// For a scale of 0.5, the map marker shrinks to half of its original size.
double scaleFactor = 1.0;

// With DENSITY_INDEPENDENT_PIXELS the map marker will have a constant size on the screen regardless if the map is zoomed in or out.
MapMarker3D mapMarker3D = new MapMarker3D(geoCoordinates, mapImage, scaleFactor, RenderSize.Unit.DENSITY_INDEPENDENT_PIXELS);

mapView.getMapScene().addMapMarker3d(mapMarker3D);
val mapImage = MapImageFactory.fromResource(context.resources, R.drawable.poi)

// The default scale factor of the map marker is 1.0. For a scale of 2, the map marker becomes 2x larger.
// For a scale of 0.5, the map marker shrinks to half of its original size.
val scaleFactor = 1.0

// With DENSITY_INDEPENDENT_PIXELS the map marker will have a constant size on the screen regardless if the map is zoomed in or out.
val mapMarker3D = MapMarker3D(geoCoordinates, mapImage, scaleFactor, RenderSize.Unit.DENSITY_INDEPENDENT_PIXELS)

mapView.mapScene.addMapMarker3d(mapMarker3D)

この例では、リソースから PNG ("poi.png") を読み込み、そこから MapImage を作成します。その後、このMapImageをMapMarkerインスタンスに設定します。

画像を表示するには、MapMarkerをマップシーンに追加する必要があります。MapImage は、指定された geoCoordinates を中心として表示されます。

フラット 3D マーカーを地図に合わせて拡大/縮小させるにはどうすればよいでしょうか。

MapMarker3D を使用してフラット マップ マーカーを作成し、RenderSize.Unit と METERS を使用してズーム イン/アウト時の拡大/縮小を許可します。

2D モデルからフラット 2D マップ マーカーを作成する方法

次の段落では、手書きの obj ファイルから 2D モデルを作成する方法を説明します。その結果、前のセクションと同じフラット マップ マーカーを作成できます。

以下に、2D の平面の例を示します。これは、X 軸と Y 軸方向に 2 単位分の大きさです。3D オブジェクトは簡単に拡大/縮小できるため、モデルのサイズは重要ではありません。この例では、座標系の原点は平面の下部にあります。このようにして、POI マーカー アセットを、指定された地理座標を指すテクスチャとしてラップできます。

# A 2 x 2 square, centered upon origin.

v -1 2 0
v 1 2 0
v -1 0 0
v 1 0 0
# 4 vertices

vt 0 1
vt 1 1
vt 0 0
vt 1 0
# 4 texture vertices

vn 0 0 1
vn 0 0 1
vn 0 0 1
vn 0 0 1
# 4 vertex normals

f 1/1/1 3/3/3 2/2/2
f 3/3/3 4/4/4 2/2/2
# 2 faces

この例では、上記の平面のモデル定義を"plane.obj"というテキストファイルに格納します。

この例で使用するplane.obj 3Dモデル。

平面は正方形であるため、POI画像のサイズを透明な領域で左右に拡大し、画像が正方形になるようにしています。元の画像は正方形ではなく長方形であるため、平面にラップされると歪みが生じます。

obj 形式で定義されたモデルとモデルをラップするテクスチャを作成したら、両方のファイルをプロジェクトの assets ディレクトリに追加します。例:app/src/main/assets/...

以下では、obj ファイルと PNG テクスチャを追加しました。

  • app/src/main/assets/plane.obj
  • app/src/main/assets/poi_texture.png
この例で使用するpoi_texture.pngテクスチャ。

次のコードを使用して、地図にフラットマーカーを追加します。

String geometryFile = "plane.obj";
String textureFile = "poi_texture.png";
checkIfFileExistsInAssetsFolder(geometryFile);
checkIfFileExistsInAssetsFolder(textureFile);

MapMarker3DModel mapMarker3DModel = new MapMarker3DModel(geometryFile, textureFile);
MapMarker3D mapMarker3D = new MapMarker3D(geoCoordinates, mapMarker3DModel);
mapMarker3D.setScale(60);

mapView.getMapScene().addMapMarker3d(mapMarker3D);
val geometryFile = "plane.obj"
val textureFile = "poi_texture.png"
checkIfFileExistsInAssetsFolder(geometryFile)
checkIfFileExistsInAssetsFolder(textureFile)

val mapMarker3DModel = MapMarker3DModel(geometryFile, textureFile)
val mapMarker3D = MapMarker3D(geoCoordinates, mapMarker3DModel)
mapMarker3D.scale = 60.0

mapView.mapScene.addMapMarker3d(mapMarker3D)

checkIfFileExistsInAssetsFolder() メソッドのコードは、前のセクションを参照してください。

3D 空間では 2 単位の正規化された長さを使用しているため、モデルを 60 倍に拡大します。結果については、下のスクリーンショットを参照してください。

フラットマップマーカー - 地図とともに回転および傾斜する。

フラットマーカーが指している位置を示す赤い円を追加しました。

フラット マップ マーカーは、地図を回転させると一緒に回転し、地図を傾けるとマップ マーカーも傾きます。これにより、2D モデルが平坦であっても 3D のような効果が得られます。デフォルトでは、フラット マップ マーカーのスケール値は地図のズーム レベルと一緒に変更されません。たとえば、地図をズーム アウトしてもマップ マーカーは表示されたままになります。フラット化されていない MapMarker の場合も同じです。

マーカーを地図と一緒に拡大/縮小させるには、前のセクションで示したように、フラット マップ マーカーを作成します。

位置情報インジケーターを追加する

3D マップ アイテムのもう 1 つのタイプとして、LocationIndicator があります。通常、地図上にはユーザーのデバイスの現在地 (進行方向を含む) を示すインスタンスが 1 つだけ追加されます。

HERE SDK では、さまざまなユースケース用に事前定義された 3D アセットが用意されています。必要に応じて、これらの定義済みの各スタイルを、独自のカスタマイズされた MapMarker3DModel に置き換えることができます。

すべてのマップ マーカーと同様に、マップ ビューのズーム レベルを変更しても、LocationIndicator は拡大/縮小されません。ただし、地図を傾けた場合は LocationIndicator が水平線方向に移動して小さくなります。

地図に LocationIndicator を追加する方法の例を見てみましょう。

private void addLocationIndicator(GeoCoordinates geoCoordinates,
                                  LocationIndicator.IndicatorStyle indicatorStyle) {
    LocationIndicator locationIndicator = new LocationIndicator();
    locationIndicator.setLocationIndicatorStyle(indicatorStyle);

    // A LocationIndicator is intended to mark the user's current location,
    // including a bearing direction.
    // For testing purposes, we create a Location object. Usually, you may want to get this from
    // a GPS sensor instead.
    Location location = new Location(geoCoordinates);
    location.time = new Date();
    location.bearingInDegrees = getRandom(0, 360);

    locationIndicator.updateLocation(location);

    // Show the indicator on the map view.
    locationIndicator.enable(mapView);
}
private fun addLocationIndicator(
  geoCoordinates: GeoCoordinates,
  indicatorStyle: LocationIndicator.IndicatorStyle
) {
  val locationIndicator = LocationIndicator()
  locationIndicator.locationIndicatorStyle = indicatorStyle

  // A LocationIndicator is intended to mark the user's current location,
  // including a bearing direction.
  val location: Location = Location(geoCoordinates)
  location.time = Date()
  location.bearingInDegrees = getRandom(0.0, 360.0)

  locationIndicator.updateLocation(location)

  // Show the indicator on the map view.
  locationIndicator.enable(mapView)

  locationIndicatorList.add(locationIndicator)
}

上に示すとおり、アセットは必要ありません。代わりに IndicatorStyle が設定されています。

  • LocationIndicator.IndicatorStyle.NAVIGATION:ナビゲーションのユースケース用に設計されたアセット。
  • LocationIndicator.IndicatorStyle.PEDESTRIAN:座っているときや歩いているときなど、ハンドヘルドでの使用のために設計されたアセット。

どちらのスタイルも、現在の方位を示します。これは、ユーザーの進行方向を表します。この例では、0° ~ 360° の間のランダムな方位値を設定しています。0°の方位は北が上を示しているため、矢印は上を指しています。これは地図もデフォルトで北が上を指しているためです。

ナビゲーションのユースケース用の位置情報インジケーター。

ナビゲーション中の一般的なユーザー体験のアプローチは、ユーザーが運転している方向に地図を回転させて、方位が変化しても方向矢印が常に上を指すようにすることです。通常、ナビゲーション中の矢印は、ユーザーが走行中の道路の進行方向を指すことが期待されます。

歩行者のユースケースでは、ユーザーの現在地が焦点となります。そのため、方向を示す矢印ははるかに小さくなります。

歩行者のユースケース用の位置情報インジケーター。

方位値の活用方法は、アプリケーションによって異なります。Location オブジェクトから取得された方位は移動方向を示す一方、アプリケーションでは真北を基準にして方位を設定する場合もあります (コンパス モード)。矢印が真北を指すようにするには、方位値を 0° に変更します。このような調整は、位置情報源から新しい Location の更新情報を受信するたびに実施する必要があります (以下を参照)。

通常、地図に設定される LocationIndicator のインスタンスは 1 つのみです。updateLocation() を呼び出すことでその場所を更新でき、setLocationIndicatorStyle() を呼び出すことで、そのスタイルをその場で更新できます。

各スタイルには、GPS 信号が失われたときのグレー状態など、さまざまな状態を定義する、いつかの関連付けられた MarkerType の値があります。LocationIndicator がカスタマイズされている場合は、すべてのタイプを設定することが重要です。そうしないと、状態を変更しても効果はありません。

次のコードスニペットは、非アクティブ状態を示す定義済みのグレーのタイプとデフォルト状態を切り替える方法を示しています。

boolean isActive = locationIndicator.isActive();
// Toggle between active / inactive state.
locationIndicator.setActive(!isActive);
val isActive: Boolean = locationIndicator.isActive()
// Toggle between active / inactive state.
locationIndicator.setActive(!isActive)

精度のハローの色はsetHaloColor() メソッドを使用して設定できます。この機能は現在ベータ版であり、今後のリリースで動作が変更される可能性があります。
たとえば、次のコードスニペットでは、ハローの色を半透明の黄色に設定しています。

locationIndicator.setHaloColor(IndicatorStyle.PEDESTRIAN, new Color(255F, 255F, 0F, 0.30F));
locationIndicator.setHaloColor(IndicatorStyle.PEDESTRIAN, Color(255f, 255f, 0f, 0.30f))
半透明の黄色のハローを使った位置情報のインジケーター

RGBA値でハローの色と透明度を定義しており、0.30Fは透明度レベルを設定しています。現在のハローの色を取得するには、getHaloColor()メソッドを使用します。

LocationIndicatorを削除するには、次のように呼び出します。

// Remove locationIndicator from map view.
locationIndicator.disable();
// Remove locationIndicator from map view.
locationIndicator.disable()

注

LocationIndicator はまだ選択することはできません。また、常に他のすべての要素の上に描画され、描画順序を設定する必要はありません。

ほとんどのユースケースでは、頻繁に更新される Location に基づいて、LocationIndicator を更新します。MapItems のサンプル アプリの一部として、分離された使用例を見ることができます。

注

LocationIndicator は、常に 0 に近い固定された高度でレンダリングされます。MapCameraを変更して、高い高度で地理座標を表示すると、問題が発生する可能性があります。MapCameraの角度が傾いていて、高度が高すぎると、この新たな視点が原因でLocationIndicatorがビューポートから消えることがあります。

HERE SDK for Android Navigateについては、位置情報の取得に関するセクションを参照して、デバイスのGPSチップから実際のLocationの更新情報を取得する方法を確認してください。Positioningのサンプルアプリでは、LocationIndicatorを使用してこれを行う方法を示しています。

位置信号の水平精度を視覚化することもできます。上にあるLocationIndicatorでは上に精度のハローのカスタムカラーを設定できます。デフォルトでは、精度の視覚化は無効になっています。

注 (HERE SDK for Android Navigateの場合)

NavigationCustomのサンプルアプリは、ナビゲーションが停止したときにカスタムのLocationIndicatorや別のマーカータイプに切り替える方法を示しています。

MapViewLifecycleListener の使用方法

MapViewLifecycleListener は、MapView のライフサイクルをリッスンする任意のクラスで実装できます。この実装により、次のイベントに対応します。

  • onAttach(MapViewBase mapView):マップ ビューに実装するオブジェクトを追加するときに呼び出されます。
  • onPause():実装するオブジェクトが添付されているマップ ビューが一時停止したとき (通常、アプリがバックグラウンドに移動したとき) に呼び出されます 。
  • onResume():実装するオブジェクトが添付されているマップ ビューが再開したとき (通常、アプリがフォアグラウンドに移動したとき) に呼び出されます。
  • onDetach(MapViewBase mapView):マップ ビューから実装するオブジェクトを削除するときに呼び出されます。
  • onDestroy():実装するオブジェクトが添付されているマップ ビューが破棄されたときに呼び出されます。

実装するオブジェクトは、次のように添付および削除できます。

  • オブジェクトを MapView ライフサイクルに添付する:mapView.addLifecycleListener(myObject);
  • オブジェクトを MapView ライフサイクルから削除する:mapView.removeLifecycleListener(myObject);

MapView からマップ アイテムを選択する方法

次の表に、現在選択可能なマップ アイテムを選択する方法を示します。

マップ アイテム
選択方法
MapPolyline mapView.pick(filter, viewArea, MapViewBase.MapPickCallback())
MapPolygon mapView.pick(filter, viewArea, MapViewBase.MapPickCallback())
MapMarker mapView.pick(filter, viewArea,MapViewBase.MapPickCallback())
MapMarkerCluster.Grouping mapView.pick(filter, viewArea, MapViewBase.MapPickCallback())
埋め込みPOI mapView.pick(filter, viewArea, MapViewBase.MapPickCallback())
MapViewPin linearLayout.setOnClickListener(new View.OnClickListener()){...}

mapView.pick()メソッドの詳細については、NavigateおよびExploreの「APIリファレンス」を参照してください。

マップビューピンを追加する

マップマーカーを使用すると、地図にアイテムをスムーズに配置できますが、マップピンはネイティブな View を地図に固定するために使用できます。これは、情報のポップアップ吹き出し (またはアニメーション化された情報の吹き出し)、注釈、カスタマイズされたコントロールを表示する場合に便利です。たとえば、マップ マーカーをタップすると、マーカーの位置に関する追加情報を含むマップ ピンを表示できます。

マップ ピンは複数の Views で構成でき、それぞれを他の View と同じように使用できます。これにより、任意のネストされたレイアウトを追加したり、クリック ハンドラーを追加したり、アニメーションを適用したりすることができます。

注

ビュー ピンはマップ ビューに添付されていますが、地図自体の一部ではありません。これは、ネイティブ ビューで構成されているためです。そのため、マップ ビューをパンすると、ピンはマップ ビューと一緒に移動しますが、わずかな遅延が発生します。この問題を回避するには、特に一度に複数のインスタンスを表示する場合は、代わりに MapMarker を使用することを検討してください。

カスタムと同様に、ビューを XML レイアウト ファイルで定義してプログラムで拡張することも、必要なビュー コンテンツをプログラムで生成することもできます。例:

TextView textView = new TextView(context);
textView.setTextColor(Color.parseColor("#FFFFFF"));
textView.setText("Centered ViewPin");

LinearLayout linearLayout = new LinearLayout(context);
linearLayout.setBackgroundResource(R.color.colorAccent);
linearLayout.setPadding(10, 10, 10, 10);
linearLayout.addView(textView);
val textView = TextView(context)
textView.setTextColor(Color.parseColor("#FFFFFF"))
textView.text = "Centered ViewPin"

val linearLayout = LinearLayout(context)
linearLayout.setBackgroundResource(R.color.colorAccent)
linearLayout.setPadding(10, 10, 10, 10)
linearLayout.addView(textView)

これにより、TextView を保持する LinearLayout (View から派生) が作成されます。TextViewを中間レイアウトに追加せずに、直接追加することもできます。あらゆるビューの組み合わせ(または単一のビュー)を追加できます。

これであと必要なのは、小さなビュー構成を地図に追加することだけになりました。ポリゴンやマーカーなどの他のマップ アイテムと違い、ピンは地図に直接追加できます。

ViewPin viewPin = mapView.pinView(linearLayout, geoCoordinates);
val viewPin = mapView.pinView(linearLayout, geoCoordinates)

このメソッドは、ピンの制御 (アンカー ポイントの指定など) に使用できるプロキシ オブジェクトを返します。

スクリーンショット:AndroidのTextViewを示すマップピン。デフォルトでは、ビューは指定された位置を中心として配置されます。

Viewでタップジェスチャーリスナーを設定して、ユーザーがマップ表示ピンをタップしたかどうかを確認することもできます。

linearLayout.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Log.i(TAG, "Tapped on MapViewPin");
    }
});
linearLayout.setOnClickListener(View.OnClickListener { Log.i(TAG, "Tapped on MapViewPin") })

ビューにアニメーションを適用したり、他のインタラクション リスナーをアタッチしたりすることもできます。View がマップ ビューに添付されると、他の Android View と同じように動作します。ただし、地図上で固定されたままになり、パンまたはズーム時に一緒に移動します。マップ ポリラインやマップ マーカーと同様に、ViewPin は地図を回転しても回転しません。

マップ ピンはいくつでも追加できますが、パフォーマンスを考慮してください。たとえば、地図上に複数の検索結果を表示する場合、マップ ピンはマップ マーカーよりもパフォーマンスが劣ります。

地図からピンを削除するには、次のように呼び出します。

mapView.unpinView(view);
mapView.unpinView(view)

複数の ViewPin インスタンスを追加した場合は、次のように呼び出すことで mapView オブジェクトからすべてのピンにアクセスできます。

List<ViewPin> viewPins = mapView.getViewPins();
val viewPins: List<ViewPin> = mapView.viewPins

通常、マップ ピンは地図上の特定の場所について、追加のダイナミック コンテンツを表示するのに最適です。

アンカー付きマップ表示ピン

デフォルトでは、マップ ピンは指定された位置を中心として配置されます。しかし、下の領域を隠すことなくピンを使用するにはどうすればよいでしょうか。

そのためには、アンカー ポイントを指定します。アンカー ポイントは、すでに上のセクションで確認したマップ マーカーと同じように画面上のビューの位置に影響を与えます。

viewPin.setAnchorPoint(new Anchor2D(0.5F, 1));
viewPin.setAnchorPoint(Anchor2D(0.5, 1.0))

これにより、ビューはその位置の水平方向の中心に配置され、ビューの下部が指定された座標と一致します。下のスクリーンショットに表示されているように、マップピンは、マップピンの指定された中心位置を示すマップ円オブジェクトの上に配置されます。

スクリーンショット:アンカー付きマップピン。

アンカーポイントを使用すると、ビューをレンダリングする場所を簡単に指定できます。左上隅は (0, 0) のアンカーポイントと等しく、右下隅は (1, 1) のアンカーポイントと等しくなります。ビューの大きさに関係なく、幅または高さの半分のポイントは常に0.5になります。これは、正規化されたテクスチャUV座標の概念に似ています。図については、上のマップ マーカーのセクションを参照してください。

デフォルトでは、アンカー ポイントは (0.5, 0.5) で、ビューはその位置を中心としてレンダリングされます。設定されたGeoCoordinatesの位置を、ビューの右下隅で指すようにするには、アンカーポイントを (1, 1) に設定します。

ビューは任意のサイズにできるため、最大の幅および高さの値は「1」となります。ビューの寸法は、完全に拡張した後に計算されます。ビューの正確な寸法がわかっている場合は、最大値の 1 を基準にして、ビュー内の特定のポイントを簡単に計算できます。

注

オフセットを使用すると、X 軸および Y 軸に沿った移動を指定できますが、アンカー ポイントはビューなどの長方形の左上隅の相対位置を定義します。アンカーポイントは、ビューの境界との関連で、指定されたGeoCoordinatesの位置に中心を合わせるビューのポイントを定義します。

マップポリラインのグラデーションを有効にする

HERE SDKでは、グラデーションをレンダリングしてポリラインをカスタマイズできます。MapPolyline.lineColorとMapPolyline.progressColor間の遷移を徐々にレンダリングできます。このグラデーション遷移の長さは、ズームレベルに依存するピクセル単位で定義され、MapPolyline.setProgressGradientLengthおよびMapPolyline.getProgressGradientLengthを使用して設定または取得できます。

// Create the polyline.
mapPolyline = createPolyline();

// Configure the progress color. Currently, cyan color is being used.
Color progressColor = new Color(0f, 1f, 1f, 0.5f);
mapPolyline.setProgressColor(progressColor);

// Set the progress value, ranging from 0 to 1. For example, 0.40 represents 40% progress.
mapPolyline.setProgress(0.40);

// Define the gradient length using MapMeasureDependentRenderSize.
MapMeasureDependentRenderSize gradientLength;
try {
    double widthInPixels = 20.0;
    gradientLength = new MapMeasureDependentRenderSize(RenderSize.Unit.PIXELS, widthInPixels);
} catch (MapMeasureDependentRenderSize.InstantiationException e) {
    Log.e("MapMeasureDependentRenderSize Exception:", e.error.name());
    return;
}

// Set the maximum gradient length between 'lineColor' and 'progressColor' in zoom-level-dependent pixels.
mapPolyline.setProgressGradientLength(gradientLength);
mapScene.addMapPolyline(mapPolyline);
// Create the polyline.
mapPolyline = createPolyline()

mapPolyline?.apply {
    // Configure the progress color. Currently, cyan is being used.
    progressColor = Color(0f, 1f, 1f, 0.5f)

    // Set the progress value, ranging from 0 to 1. For example, 0.40 represents 40% progress.
    progress = 0.40
}

// Define the gradient length using MapMeasureDependentRenderSize.
val gradientLength: MapMeasureDependentRenderSize
try {
    val widthInPixels = 20.0
    gradientLength = MapMeasureDependentRenderSize(RenderSize.Unit.PIXELS, widthInPixels)
} catch (e: MapMeasureDependentRenderSize.InstantiationException) {
    Log.e("MapMeasureDependentRenderSize Exception:", e.error.name)
    return
}

// Set the maximum gradient length between 'lineColor' and 'progressColor' in zoom-level-dependent pixels.
mapPolyline?.let {
    it.progressGradientLength = gradientLength
    mapScene?.addMapPolyline(it)
}

これにより、次のようなグラデーションポリラインが作成されます。

スクリーンショット:グラデーションマップポリライン。

gradientLengthてサポートされているのはRenderSize.Unit.PIXELSのみで、MapMeasureDependentRenderSizeを設定する際にサポートされているのはMapMeasure.Kind.ZOOM_LEVELのみです。サポートされていないパラメーターはすべて無視されます。

ズームレベルに基づいてグラデーションの長さを変更するには、複数の値をMapMeasureDependentRenderSizeで使用します。デフォルトでは、グラデーション長はゼロピクセルの固定値です。

注

グラデーションはポリラインの長さに基づいてレンダリングされるため、実際のグラデーションはポリラインより短くなる場合があります。

サンプルアプリを試す

上記のコードスニペットはすべて、サンプルアプリで提供されている「MapItems」サンプルアプリ (Java版およびKotlin版) でご覧いただけます。お使いのプラットフォームのGitHubでご確認ください。


このページは役に立ちましたか?