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

地図の使用を開始する

HERE SDK は堅牢なマッピング機能を提供しているため、開発者はマップ ビューをアプリケーションに途切れることなく統合できます。主な機能には、マップ ビューの追加とカスタマイズ、表示される位置情報の調整、マップ プロパティの変更などがあります。地図検索 API の中心にあるのは、View のサブクラスである MapView であり、さまざまな設定可能なプロパティを持つ地図のベクトル ベースおよびラスター ベースの表現を提供します。

HERE Map Data は毎週更新され、常に利用可能な最新のマップ データを取得できるようになっています。マップ ビューを統合することで、このメリットを自動的に享受できます。

HERE SDK(エクスプローラ)の場合、 MapViewまた、非衛星ベースのマップスキームは、OMVベクトルタイルと組み合わせてHERE Vector Tile APIに基づいています。

HERE SDK(ナビゲート)の場合、 MapViewまた、非衛星ベースのマップスキームは、****OCMベクタータイルと組み合わせてData IOに基づいています。これは、地図データがキャッシュ、プリフェッチ、またはインストールされていない場合にオンラインで使用する場合に適用されます。**データIOは、**を使用してオフラインマップをダウンロードまたは更新するときにもカウントされます。 MapDownloaderまたは MapUpdaterです。HERE SDK (Navigate) にのみ適用されます。

これらの機能の価格については、HERE基本プランの価格を参照してください。 価格についてご質問がある場合は、お問い合わせください。

地図を表示する

マップビューを表示する前に、こちらに示すように、MapViewを統合する必要があります。XML (JavaおよびKotlinに対応) またはKotlinのJetpack Composeを使用できます。

マップシーンのロードは、たとえばMainActivityクラスから実行できます。次のコードを追加して、NORMAL_DAYマップレンダリングスタイルを表すマップスキームを使用してシーンを読み込みます。

private void loadMapScene() {
    // Load a scene from the HERE SDK to render the map with a map scheme.
    mapView.getMapScene().loadScene(MapScheme.NORMAL_DAY, new MapScene.LoadSceneCallback() {
        @Override
        public void onLoadScene(@Nullable MapError mapError) {
            if (mapError == null) {
                double distanceInMeters = 1000 * 10;
                MapMeasure mapMeasureZoom = new MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters);
                mapView.getCamera().lookAt(
                        new GeoCoordinates(52.530932, 13.384915), mapMeasureZoom);
            } else {
                Log.d("loadMapScene()", "Loading map failed: mapError: " + mapError.name());
            }
        }
    });
}
private fun loadMapScene() {
    // Load a scene from the HERE SDK to render the map with a map scheme.
    mapView!!.mapScene.loadScene(MapScheme.NORMAL_DAY) { mapError ->
        if (mapError == null) {
            val distanceInMeters = (1000 * 10).toDouble()
            val mapMeasureZoom = MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters)
            mapView!!.camera.lookAt(
                GeoCoordinates(52.530932, 13.384915), mapMeasureZoom
            )
        } else {
            Log.d("loadMapScene()", "Loading map failed: mapError: " + mapError.name)
        }
    }
}

上記では、分離されたコードスニペットのみが表示されています。HERE SDKの統合と初期化を含む、簡単な地図アプリケーションの構築方法については、「利用開始」を参照してください。

Screenshot: Showing a normal day map scheme.

地図の準備完了時に通知を受信する

HERE Rendering Engine は、onResume() が呼び出されるたびに接続されます。接続が発生すると、OnReadyListener によって通知されます。

mapView.setOnReadyListener(new MapView.OnReadyListener() {
    @Override
    public void onMapViewReady() {
        // This will be called each time after this activity is resumed.
        // It will not be called before the first map scene was loaded.
        // Any code that requires map data may not work as expected until this event is received.
        Log.d(TAG, "HERE Rendering Engine attached.");
    }
});
mapView!!.setOnReadyListener { // This will be called each time after this activity is resumed.
    // It will not be called before the first map scene was loaded.
    // Any code that requires map data may not work as expected until this event is received.
    Log.d(TAG, "HERE Rendering Engine attached.")
}

ほとんどの場合、このイベントを待つ必要はありません。たとえば、マップ アイテムはいつでも追加できます。HERE Rendering Engine が接続されると、地図が表示されます。マップ ビューからマップ アイテムを選択するなど、マップ データを必要とするコードの場合のみ、期待される結果を得るためにこのイベントを待つ必要があります。

埋め込みPOI (施設情報) を選択する

デフォルトでは、地図にはレストラン、公共交通機関、その他の名所のアイコンがいくつか表示されます。これらの施設情報 (POI) は Carto POI と呼ばれ、ユーザーが選択して詳細を取得できます。これらの埋め込み POI の表示を制御するオプションもあります。

埋め込み POI は、事前設定された Carto POI マーカーであり、デフォルトでは MapView に表示されます。MapMarker アイテムとは異なり、HERE Style Editor を使用せずにアイテムの内容や外観を変更することはできません。ただし、ユーザーはこれらのアイコンをタップして、場所、PlaceCategory、POI の名前を取得することはできます。

埋め込みPOIは、現在他のマップアイテムに隠れている場合を除き、他のMapMarkerアイテムと並行して選択できます。

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

private void pickMapContent(final Point2D touchPoint) {
    // You can also use a larger area to include multiple map icons.
    Rectangle2D rectangle2D = new Rectangle2D(touchPoint, new Size2D(50, 50));
    // 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 Carto POIs so adding the MAP_CONTENT filter.
    contentTypesToPickFrom.add(MapScene.MapPickFilter.ContentType.MAP_CONTENT);
    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, rectangle2D, mapPickResult -> {
        if (mapPickResult == null) {
            Log.e("onPickMapContent", "An error occurred while performing the pick operation.");
            return;
        }
        PickMapContentResult pickedContent = mapPickResult.getMapContent();
        handlePickedCartoPOIs(pickedContent.getPickedPlaces());
        handlePickedVehicleRestrictions(pickedContent.getVehicleRestrictions());
        // ... handle more content results when needed.
    });
}

private void handlePickedCartoPOIs(List<PickedPlace> cartoPOIList) {
    int listSize = cartoPOIList.size();
    if (listSize == 0) {
        return;
    }

    PickedPlace topmostPickedPlace = cartoPOIList.get(0);
    showDialog("Carto POI picked:", topmostPickedPlace.name + ", Location: " +
            topmostPickedPlace.coordinates.latitude + ", " +
            topmostPickedPlace.coordinates.longitude + ". " +
            "See log for more place details.");

    // Now you can use the SearchEngine or the OfflineSearchEngine, when available for your license,
    // to retrieve the Place object containing more details.
}
private fun setTapGestureHandler() {
    mapView.gestures.tapListener = TapListener { touchPoint -> pickMapMarker(touchPoint) }
}

private fun pickMapContent(touchPoint: Point2D) {
    // You can also use a larger area to include multiple map icons.
    val rectangle2D = Rectangle2D(touchPoint, Size2D(50.0, 50.0))
    // 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<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 Carto POIs so adding the MAP_CONTENT filter.
    contentTypesToPickFrom.add(MapPickFilter.ContentType.MAP_CONTENT)
    val filter = 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, rectangle2D) { mapPickResult: MapPickResult? ->
        if (mapPickResult == null) {
            Log.e("onPickMapContent", "An error occurred while performing the pick operation.")
            return@pick
        }
        val pickedContent = mapPickResult.mapContent
        handlePickedCartoPOIs(pickedContent!!.pickedPlaces)
    }
}

private fun handlePickedCartoPOIs(cartoPOIList: List<PickedPlace>) {
    val listSize = cartoPOIList.size
    if (listSize == 0) {
        return
    }

    val topmostPickedPlace = cartoPOIList[0]
    showDialog(
        "Carto POI picked:", topmostPickedPlace.name + ", Location: " +
                topmostPickedPlace.coordinates.latitude + ", " +
                topmostPickedPlace.coordinates.longitude + ". " +
                "See log for more place details."
    )

    // Now you can use the SearchEngine or the OfflineSearchEngine, when available for your license,
    // to retrieve the Place object containing more details.
}

あるいは、SearchEngineまたはOfflineSearchEngine (すべてのライセンスで使用できるわけではない) を使用して、さらなる詳細を含むPlaceオブジェクトを取得できます。PickMapContentResultを使用して、Placeの検索に使用できるPickedPlaceオブジェクトを取得します。

埋め込みの車両制限アイコンを選択する

MapFeatures.VEHICLE_RESTRICTIONSが有効で、車両制限アイコンを地図上にレンダリングできることを確認します。

1つまたは複数の車両制限アイコンが選択されると、選択された制限の詳細を取得するために、getVehicleRestrictions()を呼び出せるPickMapContentResultオブジェクトを含むMapPickResultを受け取ります。

このオブジェクトを使用して、ビットマップとしてアイコンにアクセスしたり、TruckTypeなどのその他の任意のプロパティを取得したりできます。

private void handlePickedVehicleRestrictions(List<PickMapContentResult.VehicleRestrictionResult> vehicleRestrictions) {
    int listSize = vehicleRestrictions.size();
    if (listSize == 0) {
        return;
    }

    PickMapContentResult.VehicleRestrictionResult topmostVehicleRestriction = vehicleRestrictions.get(0);
    createVehicleRestrictionIcon(topmostVehicleRestriction);
}
private fun handlePickedVehicleRestrictions(vehicleRestrictions: List<PickMapContentResult.VehicleRestrictionResult>) {
    if (vehicleRestrictions.isEmpty()) {
        return
    }

    val topmostVehicleRestriction = vehicleRestrictions.first()
    createVehicleRestrictionIcon(topmostVehicleRestriction)
}

VehicleRestrictionResultでは、IconProviderを使用して、地図に表示される画像表現を生成できます。画像の生成にはiconProvider.createVehicleRestrictionIcon(..)を使用します。

このメソッドには次のパラメーターが必要です。

  • vehicleRestrictionResultPickMapContentResultからの車両制限オブジェクトの選択結果です。
  • currentMapSchemeMapViewの現在のマップスキームです。
  • IconProviderAssetType:UIまたは地図のアイコン最適化を指定します。
  • size:コールバックで生成される画像のサイズです。
  • iconProviderCallback:生成されたアイコンを受け取るコールバックオブジェクトです。

これには、次のコードを使用します。

private void createVehicleRestrictionIcon(PickMapContentResult.VehicleRestrictionResult vehicleRestrictionResult) {
IconProvider iconProvider = new IconProvider(mapView.getMapContext());

    IconProvider.IconCallback iconProviderCallback = new IconProvider.IconCallback() {
        @Override
        public void onCreateIconReply(@Nullable Bitmap bitmap, @Nullable String description, @Nullable IconProviderError iconProviderError) {
            if (iconProviderError == null) {
                // Now you can make use of the bitmap representation.
            }
        }
    };

    iconProvider.createVehicleRestrictionIcon(vehicleRestrictionResult, currentMapScheme, IconProviderAssetType.UI, new Size2D(), iconProviderCallback);
}
private fun createVehicleRestrictionIcon(vehicleRestrictionResult: PickMapContentResult.VehicleRestrictionResult) {
    val iconProviderCallback = object : IconCallback {
        override fun onCreateIconReply(
            bitmap: Bitmap?,
            description: String?,
            iconProviderError: IconProviderError?
        ) {
            if (iconProviderError == null) {
                // Now you can make use of the bitmap representation.
            }
        }
    }

    iconProvider.createVehicleRestrictionIcon(
        vehicleRestrictionResult,
        currentMapScheme,
        IconProviderAssetType.UI,
        Size2D(),
        iconProviderCallback
    )
}

HERE SDK for Android Navigateについては、GitHubで「CartoPOIPicking」サンプルアプリを参照してください。

埋め込みPOIの表示を制御する

HERE SDK for Android Navigateでは、地図上の埋め込みPOIの表示は、MapContentSettings.setPoiCategoriesVisibility(...)を使用して制御できます。これにより、POIカテゴリーのリストにVisibilityStateを設定できます。

// Note: You can change the visibility of individual embedded POI categories. This allows hiding specific categories of carto POIs.
List<String> categoryIds = new ArrayList<>();
categoryIds.add(PlaceCategory.EAT_AND_DRINK_RESTAURANT);
MapContentSettings.setPoiCategoriesVisibility(categoryIds, VisibilityState.HIDDEN);
// Note: You can change the visibility of individual embedded POI categories. This allows hiding specific categories of carto POIs.
val categoryIds = mutableListOf<String>()
categoryIds.add(PlaceCategory.EAT_AND_DRINK_RESTAURANT)
MapContentSettings.setPoiCategoriesVisibility(categoryIds, VisibilityState.HIDDEN)

地図上の埋め込みPOIの表示/非表示は、Navigateでは制御できますが、Exploreでは制御できません。

すべてのPOIカテゴリーがすべてのマップスキームで使用できるわけではないことに注意してください。

サポートされているカテゴリーの一覧については、HERE Style Editorドキュメントを参照してください。

さらに、Exploreは埋め込みPOIとして表示されるすべてのPlaceCategoryフィールドをサポートしているわけではありません。たとえば、EAT_AND_DRINKSHOPPINGは、HERE SDK (Navigate) を使用している場合にのみ表示されます。

現在、以下の埋め込みPOIカテゴリーグループは、ExploreのMapViewには表示されません。

  • 宿泊施設
  • オートモーティブ
  • 飲食店
  • ショッピング

向きの変更を処理する

マップ ビュー コンポーネントの向きの変更をサポートするための最も簡単な方法は、アクティビティを再作成しないことです。画面は回転しますが、横向きまたは縦向きのどちらの形式でも同じコンテンツが表示されます。

これは、よりシンプルなアプリ レイアウトに最も便利なオプションであり、HERE SDK に付属のほとんどのサンプル アプリで使用されています。このオプションは以下の方法で有効にできます。

<activity android:name=".YourActivity"
          android:configChanges="orientation">
    
</activity>

android:configChanges の値 orientation は、アクティビティが向きの変更 (縦から横向きへの変更、またはその逆) を処理することを示します。この値は、画面の向きが変わったときに Android システムがアクティビティを再開するのを防ぎます。代わりに、アクティビティの onConfigurationChanged(Configuration newConfig) メソッドが呼び出され、向きの変更を任意で処理できます。

ただし、向きが変更されるたびに新しいアプリ レイアウトを作成する場合は、次の 2 つのオプションがあります。

  • アクティビティを切り替えるときに HERE SDK を存続させ、HERE SDK を 1 回だけ初期化します (たとえば、savedInstanceStatenull のとき、または SDKNativeEngine.getSharedInstance()null のとき)。方向が変更された後、savedInstanceState を使用してマップ ビューを再作成できます。mapView.onSaveInstanceState(outState) を呼び出すと、マーカーやポリラインなど、マップに追加されたすべてのマップ アイテムは、画面の向きが変わってマップ ビューが再作成されても、バンドルされた状態に基づいて維持されます。
  • または、HERE SDK を再初期化し、mapView.onCreate(null) を呼び出して新しいマップ ビュー インスタンスも作成します。これは新しいHERE SDKインスタンスとして必要です。同様に、新しいMapViewインスタンスを、以前のインスタンスに基づいて作成されたバンドル状態と一緒に使用することはできません。

後者の場合のHERE SDK for Android Navigateの例は、「NavigationQuickStart」のサンプルアプリ (Java版およびKotlin版) を参照してください。GitHubで見つけることができます。

Webメルカトル投影法と地球投影法に対応する

HERE SDKには、地図の投影法のタイプを設定できるオプションが用意されており、Webメルカトル投影法と地球投影法という、2つの主要なタイプをサポートしています。投影は、XMLレイアウト属性を使用する方法と、MapViewOptionsをプログラムで使用して設定する方法の2つで設定できます。

Webメルカトル

Webメルカトル投影法は、地球の表面を長方形のグリッドとして表現する円筒型の地図投影法です。この投影法では、地図は平らに表示され、緯度線と経度線がグリッドを形成し、極に近づくにつれて縮小していきます。そのため、特に緯度が高くなると、面積とスケールに歪みが生じます。

メソッド1:XMLレイアウトの設定

レイアウトリソースにWebメルカトル投影法を設定するには、次の手順で行います。

<com.here.sdk.mapview.MapView
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/map_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:projection="web_mercator">
    </com.here.sdk.mapview.MapView>

メソッド2:プログラム的な設定

MapViewOptionsを使用してWebメルカトル投影をプログラムで設定するには、次の手順を行います。

MapViewOptions mapViewOptions = new MapViewOptions();
mapViewOptions.setProjectionType(ProjectionType.WEB_MERCATOR);
MapView mapView = new MapView(this, mapViewOptions);

地球投影法

地球投影法では、地図が3Dの地球としてレンダリングされます。この投影法では、地球が実物に近い形で表現され、相対的な大きさや距離が保たれるため、地球規模での空間的な関係をより正確に把握できます。地球投影法はデフォルトで有効になっています。

メソッド1:XMLレイアウトの設定

レイアウトリソースで地球投影法を設定するには、次の手順に従います。

<com.here.sdk.mapview.MapView
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/map_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:projection="globe">
    </com.here.sdk.mapview.MapView>

メソッド2:プログラム的な設定

MapViewOptionsを使用して地球投影法をプログラムで設定するには、次の手順を行います。

MapViewOptions mapViewOptions = new MapViewOptions();
mapViewOptions.setProjectionType(ProjectionType.GLOBE);
MapView mapView = new MapView(this, mapViewOptions);

地図の言語を設定する

道路、都市、その他のマップ データのラベルを表示するために地図で使用する言語をカスタマイズできます。デフォルトでは、地域のローカル言語が使用されます。

MapView.setPrimaryLanguage(languageCode) を呼び出して世界の言語を設定するか、null を設定してデフォルトの動作に戻します。これにより、MapView のすべてのインスタンスの言語が設定されます。特定の言語が世界の任意の地域でサポートされない場合は、代わりにその地域の現地言語で表示されます。

MapView.setSecondaryLanguage(languageCode) を使用して、二重ラベルを表示できる場所に対応する第 2 地図言語を設定します。第 1 言語と第 2 言語のテキストが同じ場合は、第 1 言語のみが表示されます。リクエストされた言語がサポートされていない場合は、ローカル言語が使用されます。たとえば、インドのいくつかの都市では、ラテン語 (英語) とヒンディー語のテキストを使用する二重ラベルが同時に表示されます。

係争中の地域を処理する

HERE SDK は、複数の地理的・政治的な見解や紛争のある境界に対応し、国際的な見解 (デフォルト) またはローカル国の見解に基づいて地図の境界を表示します。ローカルな見解は、2つ以上の政治組織 (通常は国) が国境および所有権または支配権を主張する場合に、地図上の特定の領域にのみ影響を与えます。

デフォルトの地政学的見解を変更するには、SDKOptionsを使用してアクセスできるpoliticalViewメンバーに3文字の国コードを設定します。サポートされている国コードは、カバレージのページからアクセスできます。

国コードを設定すると、マップ ビューには設定されている国の地政学的見解に従ってすべての国の境界が表示され、MapView にはそれに応じて国境が表示されます。

これはベータ機能としてリリースされていることに注意してください。

実行時に地政学的見解を変更する場合は、次のコード スニペットを使用します。

// Optionally, clear the cache, so that changing the options has an immediate effect.
SDKCache.fromEngine(SDKNativeEngine.getSharedInstance()).clearCache(error -> {
    if (error != null) {
      // ...
    }

    SDKOptions options = SDKNativeEngine.getSharedInstance().getOptions();
    options.politicalView = "ARG";
    SDKNativeEngine.getSharedInstance().dispose();

    // Now, initialize the HERE SDK again using the updated options.
});
// Optionally, clear the cache, so that changing the options has an immediate effect.
SDKCache.fromEngine(SDKNativeEngine.getSharedInstance()!!).clearCache { error: MapLoaderError? ->
    if (error != null) {
        // ...
    }
    val options = SDKNativeEngine.getSharedInstance()!!.options
    options.politicalView = "ARG"
    SDKNativeEngine.getSharedInstance()!!.dispose()

    // Now, initialize the HERE SDK again using the updated options.
}

これは、進行中の HERE SDK 操作中には呼び出さないようにしてください。新しいオプションを設定するには、新しい共有インスタンスも作成する必要があるためです。オプションと politicalView は、アプリケーションのライフサイクル中に HERE SDK を初めて初期化する前に 1 回のみ設定することが理想的です。

HERE ウォーターマークを管理する

HERE SDK を使用する場合は、常に HERE のロゴがマップ ビューに表示されている必要があります。デフォルトでは、HERE のロゴは地図の右下に配置されます。ただし、マップ ビュー インスタンスで setWatermarkLocation() を呼び出すことで、アプリのデザインに合わせて簡単にロゴの場所をカスタマイズできます。UI 要素が重なっているため必要であるという場合にのみ、デフォルトの配置を変更することをお勧めします。非常に小さいビューでは、地図の両端のサイズが 250 密度非依存ピクセル未満の場合、ウォーターマークが自動的に非表示になります。

HERE との特別な合意がある場合にのみ、HERE のロゴを削除できます。


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