Run Example Apps

The Data Inspector Library provides example applications designed to help you understand the different use cases. There are two ways to access the examples:

  • Follow this link to access the examples hosted on the HERE platform. You can start investigating Data Inspector capabilities right away, without any installations. The only thing you need is to log into the platform.

  • Follow the steps described in the Install Example Apps chapter to install and run the examples locally. Once installed, open the examples at http://localhost:5000/.

Each example runs in the Data Inspector application window (represented by the DataInspector class) and explains a single feature of a certain Data Inspector Library component or a combination of various features.

Data Inspector Library Examples
Figure 1. Data Inspector Library Examples

Click the Details button to view a detailed example description.

To view the source code of an example, click the Source code button.

To download a ZIP archive with the sources of all example applications, click the Download examples button.

Examples List

This chapter describes all the examples that the Data Inspector Library contains, including their source code (click to expand):

Highlighted

Control the Visualization

Click here to open the app.

This example showcases how an embedded application can control the DataInspector from outside.

It is possible to change the catalog's HERE Resource Name (HRN), layer, layer version, as well as zoom level and map view location based on user input or URL parameters.

In this example, an input form is provided where you can enter the HRN, layer, version, latitude, longitude, and zoom level values in order to change the state of the DataInspector.

For this purpose, DataInspector provides these public methods:

  • setState: Sets a new state for the DataInspector and reloads with a new HRN, layer, and layer version.
  • focusMapCameraAt: Centers the camera at the specified coordinates and sets the desired zoom level.

Also, you can get the state of the DataInspector and maintain it in the URL parameters when you move around, or specify a new HRN, version, or layer, for example:

?hrn=hrn:here-cn:data::olp-cn-here:here-map-content-china-2&layer=topology-geometry&location=52.4956004,13.3553675&zoomLevel=10

Example Source Code


/*
 * Copyright (C) 2018-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { GeoCoordinates } from "@here/harp-geoutils";
import { MapViewEventNames } from "@here/harp-mapview";
import { VersionedLayer, PlatformDataProvider } from "@here/interactive-datasource-protocol";
import {
    DataInspector,
    I18n,
    PanelDisplayMode,
    WidgetAbstract
} from "@here/interactive-mapview-ui";
import { Action, History, createBrowserHistory, Update } from "history";
import {
    geoCenter,
    useToken,
    locale,
    showLanguageSelector,
    enableExtendedCoverage,
    layerBrowserAppDataLayer,
    layerBrowserAppHostHrn,
    lookupServiceEnvironment,
    hideURL
} from "../config";
import { bearerTokenProvider } from "./common";

/**
 * This example showcases how embedded application can control the data inspector from outside.
 *
 * It is possible to change the catalog HRN, layer, and layer version, as well as
 * zoom level and location of the map view based on user input or URL parameters.
 *
 * In this example the input form provided where user can input HRN, Layer, Version, Latitude,
 * Longitude and Level in order to change the state of the data inspector.
 *
 * For this purpose the `DataInspector` provides public methods such as:
 * `setState` - Sets new state for a component and reloads with new HRN, layer and layer version.
 * `focusMapCameraAt` - Centers the camera at the specified coordinates and sets desired zoom level.
 *
 * Also, it allows to get state of the data inspector and maintain it in the URL parameters
 * when user moves around or gives new HRN/version/layer:
 * ?hrn=hrn:here:data::olp-here:rib-2&layer=topology-geometry&location=52.4956004,13.3553675&zoomLevel=10
 */

/**
* Interface for parameters which controls the data inspector.
*/
interface DataInspectorControlParams {
    /**
     * A catalog HRN string for the data source.
     */
    hrn: string;

    /**
     * A layer name for the data source.
     */
    layer: string;

    /**
     * A version of the data source layer.
     */
    version?: number;

    /**
     * Map zoom level.
     */
    zoomLevel?: number;

    /**
     * Camera position.
     */
    location?: {
        latitude: number;
        longitude: number;
    };
}

/** Available strategies to store/retrieve data from URL. */
enum BrowserHistoryStrategy {
    /** Custom strategy. */
    Custom,
    /** Build in into DataInspector strategy. */
    DataInspector,
    /** Data will not be stored/retrieved from URL. Used to avoid URL parameters conflict. */
    None
}

/**
 * Class which implements functionality of controlling the data inspector.
 */
class LayerBrowserApplication {
    /** An instance of [[DataInspector]] UI widget. */
    private m_dataInspector: DataInspector;

    /**
     * Parameters which controls the data inspector.
     * Catalog HRN and layer already set by default. Can be changed to any other supported
     * catalog/layer.
     */
    private m_controlParams: DataInspectorControlParams = {
        hrn: layerBrowserAppHostHrn,
        layer: layerBrowserAppDataLayer
    };

    /**
     * An object which lets easily manage browser history.
     */
    private m_browserHistory: History | undefined;

    /**
     * One of PUSH, REPLACE, or POP depending on how the URL was set.
     */
    private m_browserAction = Action.Push;

    /**
     * Constructor initializes browser history, control parameters, data inspector, listeners and
     * user input form.
     *
     * @param browserHistoryStrategy Defines which strategy will be used to store/retrieve data
     * from URL.
     * @default BrowserHistoryStrategy.Custom.
     */
    constructor(browserHistoryStrategy = BrowserHistoryStrategy.Custom) {
        if (browserHistoryStrategy === BrowserHistoryStrategy.Custom) {
            this.m_browserHistory = createBrowserHistory();
            this.m_browserHistory.listen(this.browserHistoryHandler.bind(this));
        }

        // Fetch control parameter from URL before creating data inspector instance in order to
        // initialize with defined in URL parameters.
        this.fetchControlParams();

        // Set browser title.
        this.setBrowserTitle();

        // Create data inspector.
        this.m_dataInspector = new DataInspector(
            {
                mapView: {
                    theme: "../resources/normal.reduced.night.json",
                    decoder: {
                        url: "../decoder.bundle.js"
                    },
                    defaultZoomLevel: this.m_controlParams.zoomLevel,
                    ...(this.m_controlParams.location
                        ? { geoCenter: this.m_controlParams.location }
                        : { geoCenter }
                    )
                },
                monacoEditorWorkersBasePath: "../monaco-editor",
                translationsBasePath: "../resources/i18n/",
                streamSaverBasePath: "../resources/mitm/",
                defaultLocale: locale || undefined,
                getBearerToken: useToken ? bearerTokenProvider : undefined,
                widgets: {
                    authForm: !useToken ? {
                        tokenForm: false,
                        accessKeyForm: true,
                        localAuthForm: true
                    } : undefined
                },
                toolbar: {
                    languageSelector: showLanguageSelector
                },
                logMessages: true,
                lookupServiceEnvironment,
                pageUrlParams: {
                    enabled: browserHistoryStrategy === BrowserHistoryStrategy.DataInspector
                }
            },
            document.getElementById("map-here") as HTMLElement,
            {
                interactiveDataSources: [{
                    hrn: this.m_controlParams.hrn,
                    layer: this.m_controlParams.layer,
                    catalogVersion: this.m_controlParams.version
                }],
                enableCoverage: true,
                enableExtendedCoverage,
                enableFiltering: true,
                enableInfoPanel: true
            }
        );

        // Open control panel to pay attention of the user on authorization form in case if not
        // logged in.
        if (
            this.m_dataInspector.toolBar !== undefined &&
            this.m_dataInspector.authForm !== undefined &&
            this.m_dataInspector.authForm.isDisabled === false
        ) {
            const leftPanelBtn = this.m_dataInspector.toolBar.getLeftPanelBtn();
            if (leftPanelBtn) {
                leftPanelBtn.switchOn();
            }
        }

        // Add listeners after data inspector created.
        this.addDataInspectorStateListeners();

        // During update of the data inspector event listeners destroyed, so it requires to add
        // listeners again.
        this.m_dataInspector.addEventListener(
            WidgetAbstract.EVENT_AFTER_UPDATE,
            this.addDataInspectorStateListeners.bind(this)
        );

        // Adds submit handler for user input form.
        this.initializeUserInputForm();
    }

    /**
     * Changes state of the data inspector when navigating
     * by browser buttons ("Back", "Forward") without page reload.
     *
     * @param location The current location.
     * @param action The current navigation action (PUSH, REPLACE, or POP).
     */
    private browserHistoryHandler(update: Update): void {
        this.m_browserAction = update.action;
        this.fetchControlParams();

        // Update browser title.
        this.setBrowserTitle();

        // Change state of the data inspector only on actions caused by
        // browser buttons ("Back", "Forward").
        if (update.action !== Action.Pop) {
            return;
        }

        this.changeState(
            this.m_controlParams.hrn,
            this.m_controlParams.layer,
            this.m_controlParams.version,
            this.m_controlParams.location !== undefined
                ? this.m_controlParams.location.latitude
                : undefined,
            this.m_controlParams.location !== undefined
                ? this.m_controlParams.location.longitude
                : undefined,
            this.m_controlParams.zoomLevel
        );
    }

    /**
     * Adds listeners of events which changes state of the data inspector
     * in order to represent actual parameter values in URL.
     */
    private addDataInspectorStateListeners(): void {
        if (this.m_browserHistory === undefined || this.m_dataInspector.mapView === undefined) {
            return;
        }

        // Covers `zoomLevel`, `location.latitude` and `location.longitude`.
        this.m_dataInspector.mapView.addEventListener(MapViewEventNames.MovementFinished, () => {
            // Don't change URL in case of `window.history.back()` or `window.history.forward()`
            // since it already changed.
            if (this.m_browserAction === Action.Pop) {
                this.m_browserAction = Action.Push;
                return;
            }
            if (this.m_dataInspector.mapView === undefined) {
                return;
            }

            this.pushToHistory({
                ...this.m_controlParams,
                zoomLevel: this.m_dataInspector.mapView.zoomLevel,
                location: {
                    latitude: this.m_dataInspector.mapView.geoCenter.latitude,
                    longitude: this.m_dataInspector.mapView.geoCenter.longitude,
                }
            });
        });

        // Covers `version`.
        this.m_dataInspector.mapView.addEventListener(MapViewEventNames.DataSourceConnect, async (event) => {
            const dataSource = this.m_dataInspector.interactiveDataSource;
            if (
                dataSource === undefined
                || (event as any).dataSourceName !== dataSource.name
            ) {
                return;
            }

            const dataProvider = dataSource.dataProvider() as PlatformDataProvider;
            if (dataProvider !== undefined) {
                const layer = dataProvider.layer;
                if (layer instanceof VersionedLayer) {
                    layer.addEventListener(
                        VersionedLayer.ON_VERSION_CHANGE,
                        (event: any) => {
                            this.pushToHistory({
                                ...this.m_controlParams,
                                version: event.catalogVersion
                            });
                        }
                    );
                }
            }
        });
    }

    /**
     * Fetch data inspector control parameters from page URL.
     */
    private fetchControlParams(): void {
        if (this.m_browserHistory === undefined) {
            return;
        }

        const searchParams = new URLSearchParams(location.search);

        const urlHrn = searchParams.get("hrn");
        if (urlHrn !== null) {
            this.m_controlParams.hrn = urlHrn;
        }

        const urlLayer = searchParams.get("layer");
        if (urlLayer !== null) {
            this.m_controlParams.layer = urlLayer;
        }

        const urlVersion = searchParams.get("version");
        if (urlVersion !== null) {
            const version = Number.parseInt(urlVersion, undefined);
            this.m_controlParams.version = !Number.isNaN(version) ? version : undefined;
        } else {
            // If `version` parameter not present in URL it should be latest version.
            this.m_controlParams.version = undefined;
        }

        const urlZoomLevel = searchParams.get("zoomLevel");
        if (urlZoomLevel !== null) {
            const zoomLevel = Number.parseInt(urlZoomLevel, undefined);
            this.m_controlParams.zoomLevel = !Number.isNaN(zoomLevel) ? zoomLevel : undefined;
        }

        const urlLocation = searchParams.get("location");
        if (urlLocation !== null) {
            const coordinates = urlLocation.split(",");
            if (coordinates.length === 2) {
                const latitude = Number.parseFloat(coordinates[0]);
                const longitude = Number.parseFloat(coordinates[1]);
                if (!isNaN(latitude) && !isNaN(longitude)) {
                    this.m_controlParams.location = {
                        latitude,
                        longitude
                    };
                }
            }
        }
    }

    /**
     * Updates page URL to represent state of the data inspector.
     * This method manipulates the browser history by pushing new URL into history which
     * allows to navigate through different states of data inspector without page reload.
     *
     * @param controlParams Parameters which controls the data inspector.
     */
    private pushToHistory(controlParams: DataInspectorControlParams): void {
        if (this.m_browserHistory === undefined) {
            return;
        }

        const searchParams: string[] = [];

        searchParams.push("showLanguageSelector=" + showLanguageSelector);

        if (controlParams.hrn !== undefined) {
            searchParams.push("hrn=" + controlParams.hrn);
        }

        if (controlParams.layer !== undefined) {
            searchParams.push("layer=" + controlParams.layer);
        }

        if (controlParams.version !== undefined) {
            searchParams.push("version=" + controlParams.version);
        }

        if (
            controlParams.location !== undefined &&
            controlParams.location.latitude !== undefined &&
            controlParams.location.longitude !== undefined
        ) {
            const location = Number(controlParams.location.latitude).toFixed(5)
                + "," + Number(controlParams.location.longitude).toFixed(5);
            searchParams.push("location=" + location);
        }

        if (controlParams.zoomLevel !== undefined) {
            searchParams.push("zoomLevel=" + Math.floor(controlParams.zoomLevel));
        }

        const search = "?" + searchParams.join("&");

        if (this.addOptionalParameters(search) ===
            this.addOptionalParameters(this.m_browserHistory.location.search)
        ) {
            if (search === this.m_browserHistory.location.search) {
                // Don't add to history if URL the same as current one.
                return;
            } else {
                // Replace latest URL in the history in case if it's just extended with optional
                // parameter(s) (e.g. &zoomLevel=10 added).
                this.m_browserHistory.replace({
                    pathname: this.m_browserHistory.location.pathname,
                    search: this.addOptionalParameters(search)
                });
            }
        } else {
            // Add new URL to the history.
            this.m_browserHistory.push({
                pathname: this.m_browserHistory.location.pathname,
                search
            });
        }
    }

    /**
     * Adds optional parameters to search query in order to be able to compare all configuration
     * parameters.
     * @param search URL search query
     */
    private addOptionalParameters(search: string): string {
        // Optional parameters.
        const params = new Map();
        params.set("hrn", this.m_controlParams.hrn);
        params.set("layer", this.m_controlParams.layer);

        if (this.m_dataInspector.mapView) {
            params.set(
                "location",
                Number(this.m_dataInspector.mapView.geoCenter.latitude).toFixed(5) + "," +
                Number(this.m_dataInspector.mapView.geoCenter.longitude).toFixed(5)
            );
            params.set("zoomLevel", Math.floor(this.m_dataInspector.mapView.zoomLevel).toString());
        }

        // Extend/replace optional parameters with actual values from URL.
        search.substr(1).split("&").forEach(param => {
            const paramPair = param.split("=");
            if (paramPair.length === 2) {
                params.set(paramPair[0], paramPair[1].toString());
            }
        });

        // Get final search query with all parameters.
        const fullSearch = [];
        for (const entry of params.entries()) {
            fullSearch.push(entry.join("="));
        }

        return "?" + fullSearch.join("&");
    }

    /**
     * Adds submit handler of user input form where user can change some parameters to control data
     * inspector from outside.
     */
    private initializeUserInputForm(): void {
        const form = document.getElementById("userInputForm") as HTMLFormElement;
        if (form === null) {
            return;
        }
        const formFields = form.elements;
        (formFields.namedItem("userHrn") as HTMLInputElement).placeholder =
            I18n.translate("olpdi.examples.control-di.hrn");
        (formFields.namedItem("userLayer") as HTMLInputElement).placeholder =
            I18n.translate("olpdi.examples.control-di.layer");
        (formFields.namedItem("userVersion") as HTMLInputElement).placeholder =
            I18n.translate("olpdi.examples.control-di.version");
        (formFields.namedItem("userLatitude") as HTMLInputElement).placeholder =
            I18n.translate("olpdi.examples.control-di.latitude");
        (formFields.namedItem("userLongitude") as HTMLInputElement).placeholder =
            I18n.translate("olpdi.examples.control-di.longitude");
        (formFields.namedItem("userZoomLevel") as HTMLInputElement).placeholder =
            I18n.translate("olpdi.examples.control-di.zoom-level");
        (formFields.namedItem("submitBtn") as HTMLInputElement).value =
            I18n.translate("olpdi.examples.control-di.change");

        //hide `See URL` button in case examples hosted from a portal
        if (hideURL !== true) {
            // Since olp-examples shows each example in iframe, it is not possible to
            // track the URL, so the link was added which opens example in new tab to demonstrate URL.
            const viewURL = document.createElement("a");
            viewURL.href = "#";
            viewURL.textContent = I18n.translate("olpdi.examples.control-di.view-url");
            viewURL.setAttribute("target", "_blank");
            viewURL.classList.add("userInputFormLink");
            (document.getElementById("submitContainer") as HTMLElement).appendChild(viewURL);
        }
        form.onsubmit = this.userInputFormHandler.bind(this);
        this.populateUserInputForm(form);
    }

    /**
     * Populate form fields with default configurations.
     * @param form From object.
     */
    private populateUserInputForm(form: HTMLFormElement): void {
        const config = this.m_dataInspector.getConfig();
        if (config === undefined) {
            return;
        }

        const formFields = form.elements;

        if (config.interactiveDataSource !== undefined) {
            (formFields.namedItem("userHrn") as HTMLInputElement).value =
                config.interactiveDataSource.hrn !== undefined
                    ? config.interactiveDataSource.hrn.toString() : "";
            (formFields.namedItem("userLayer") as HTMLInputElement).value =
                config.interactiveDataSource.layer !== undefined
                    ? config.interactiveDataSource.layer.toString() : "";
            (formFields.namedItem("userVersion") as HTMLInputElement).value =
                config.interactiveDataSource.catalogVersion !== undefined
                    ? config.interactiveDataSource.catalogVersion.toString() : "";
        }
        const geoCenter = config.mapView.geoCenter || config.mapView.defaultGeoCenter;
        (formFields.namedItem("userLatitude") as HTMLInputElement).value =
            geoCenter.latitude.toFixed(5);
        (formFields.namedItem("userLongitude") as HTMLInputElement).value =
            geoCenter.longitude.toFixed(5);
        (formFields.namedItem("userZoomLevel") as HTMLInputElement).value =
            config.mapView.defaultZoomLevel.toString();
    }

    /**
     * Gathers user input, changes data inspector state and updates URL.
     */
    private userInputFormHandler(event: Event): boolean {
        const formData = new FormData(event.target as HTMLFormElement);

        // Data source.
        const hrn = formData.get("userHrn") as string || this.m_controlParams.hrn;
        const layer = formData.get("userLayer") as string || this.m_controlParams.layer;
        let version: number | undefined = Number.parseInt(
            formData.get("userVersion") as string,
            undefined
        );
        version = !isNaN(version) ? version : undefined;

        // Camera position.
        let latitude: number | undefined = Number.parseFloat(
            formData.get("userLatitude") as string
        );
        latitude = !isNaN(latitude) ? latitude : undefined;
        let longitude: number | undefined = Number.parseFloat(
            formData.get("userLongitude") as string
        );
        longitude = !isNaN(longitude) ? longitude : undefined;
        const location = latitude !== undefined && longitude !== undefined ? {
            latitude,
            longitude
        } : undefined;
        const zoomLevel: number | undefined = Number.parseInt(
            formData.get("userZoomLevel") as string,
            undefined
        ) || undefined;

        this.changeState(hrn, layer, version, latitude, longitude, zoomLevel);

        this.pushToHistory({
            hrn,
            layer,
            version,
            zoomLevel,
            location
        });

        // Prevent default submit behavior.
        return false;
    }

    /**
     * Changes state of data inspector (data source and position of camera).
     * @param hrn Catalog HRN.
     * @param layer Catalog layer.
     * @param version Layer version.
     * @param latitude Latitude.
     * @param longitude Longitude.
     * @param zoomLevel Zoom level.
     */
    private changeState(
        hrn: string,
        layer: string,
        version?: number,
        latitude?: number,
        longitude?: number,
        zoomLevel?: number
    ): void {
        this.changeDataInspectorState(hrn, layer, version);

        const coordinates = latitude !== undefined && longitude !== undefined
            ? new GeoCoordinates(latitude, longitude)
            : undefined;

        this.m_dataInspector.focusMapCameraAt(coordinates, zoomLevel);
    }

    /**
     * Sets new state of the data inspector with changed HRN, layer and/or layer version.
     * @param hrn Catalog HRN.
     * @param layer Catalog layer.
     * @param version Layer version.
     */
    private changeDataInspectorState(hrn: string, layer: string, version?: number): void {
        const config = this.m_dataInspector.getConfig();
        // Don't change state if hrn, layer or version wasn't changed.
        if (config !== undefined
            && config.interactiveDataSource !== undefined
            && config.interactiveDataSource.hrn === hrn
            && config.interactiveDataSource.layer === layer
            && config.interactiveDataSource.catalogVersion === version
        ) {
            return;
        }

        const prevState = this.m_dataInspector.state;
        const controlPanel = this.m_dataInspector.controlPanel;
        const prevControlPanelDisplayMode =
            controlPanel ? controlPanel.state.displayMode : undefined;

        this.m_dataInspector.setInteractiveDataSources([{
            hrn,
            layer,
            catalogVersion: version
        }]);

        if (controlPanel !== undefined) {
            if (prevControlPanelDisplayMode === PanelDisplayMode.Expanded) {
                controlPanel.show();
            } else {
                controlPanel.hide();
            }
        }
    }

    /**
     * Sets browser title with HRN and layer.
     */
    private setBrowserTitle(): void {
        document.title = this.m_controlParams.hrn + "/" + this.m_controlParams.layer;
    }
}

// Run example application.
new LayerBrowserApplication(BrowserHistoryStrategy.DataInspector);

Embed the Visualization in a TypeScript Application

Click here to open the app.

This example creates an instance of DataInspector. It creates a mapView within an HTML element of fixed size and creates a GeoJSON data source connected to the Data API.

This example offers a minimum number of Data Inspector options. To show a single map, just remove the interactiveDataSource object from the DataInspector constructor.

Example Source Code


/*
 * Copyright (C) 2018-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { DataInspector } from "@here/interactive-mapview-ui";
import { useToken, locale, showLanguageSelector, lookupServiceEnvironment, ribCartoLayer, ribHostHrn } from "../config";
import { bearerTokenProvider } from "./common";

new DataInspector(
    {
        mapView: {
            theme: "../resources/normal.reduced.night.json",
            decoder: {
                url: "../decoder.bundle.js"
            }
        },
        monacoEditorWorkersBasePath: "../monaco-editor",
        translationsBasePath: "../resources/i18n/",
        streamSaverBasePath: "../resources/mitm/",
        defaultLocale: locale || undefined,
        getBearerToken: useToken ? bearerTokenProvider : undefined,
        widgets: {
            authForm: !useToken ? {
                accessKeyForm: true
            } : undefined
        },
        toolbar: {
            languageSelector: showLanguageSelector
        },
        lookupServiceEnvironment,
        pageUrlParams: { enabled: true }
    },
    document.getElementById("map-here") as HTMLElement,
    {
        // this "interactiveDataSource" object can be commented to just show the map.
        interactiveDataSource: {
            hrn: ribHostHrn,
            layer: ribCartoLayer
        },
        enableCoverage: true,
        enableFiltering: true,
        enableInfoPanel: true
    }
);

Token Provider

Click here to open the app.

This example demonstrates how to create and use a simple server-side token provider. Rather than having a login that works on all accounts for demo purposes, the token provider generates login tokens based on your own credentials only. A client application can request and use these tokens for all its requests.

For more details on how to run this example, see Use Token from Server Token Provider

Example Source Code


/*
 * Copyright (C) 2018-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

/*
 * This file shows the simple NodeJS back-end application that provides tokens to clients.
 *
 * Current example hands out tokens to anybody who has access, therefore an access to the the server
 * should be additionally protected (e.g. some company specific login mechanism).
 */

// Raw function, that is used to retrieve tokens.
const requestToken = require("@here/olp-sdk-authentication").requestToken;

// Initialize the server.
const express = require("express");
const app = express();


// Get credentials from the file ./credentials.properties
// snippet:token-provider-credentials.js
const credentials = require("fs").readFileSync("./credentials.properties");
const url = (/here\.token\.endpoint\.url\s*=\s*([\S]*)/g).exec(credentials)[1];
const consumerKey = (/here\.access\.key\.id\s*=\s*([\S]*)/g).exec(credentials)[1];
const secretKey = (/here\.access\.key\.secret\s*=\s*([\S]*)/g).exec(credentials)[1];
const scope = ((/here\.token\.scope\s*=\s*([\S]*)/g).exec(credentials) || [])[1];
// end:token-provider-credentials.js

// snippet:token-provider-app.js
// Cached data
let tokenExpirationTime = new Date();
let tokenInfo = null;

// Add GET endpoint on this server, that will fetch the token from the token endpoint.
// API format: /getToken?ttl={number}, where ttl is an optional parameter which defines the time to
// live of a token in seconds.
app.get("/getToken", async (request, response) => {
    try {
        if (new Date() >= tokenExpirationTime) {
            console.log('Request a new token...');

            tokenInfo = await requestToken({
                // Set the token endpoint
                url,

                // Set the time to live of the token. If not defined, then 3600 sec will be used by default.
                expiresIn: request.query.ttl,

                // Pass credential data.
                consumerKey,
                secretKey,
                scope
            });

            tokenExpirationTime = new Date(Date.now() + tokenInfo.expiresIn * 1000);

            console.log(`The token expires on: ${tokenExpirationTime}`);
        }

        // Allow CORS. Optional, if token provider and client application will be hosted on different server
        response.set("Access-Control-Allow-Origin", "*");

        // Send back token to the requestor.
        response.status(200).send(tokenInfo.accessToken);
    } catch (e) {
        // For code brevity, we don't analyze error type and return HTTP 500 response.
        console.error(`Error acquiring new token: ${e.message}`);
        response.status(500).send(e.message);
    }
});
// end:token-provider-app.js


// snippet:token-provider-listen.js
// Define the server port.
const PORT = 3000;

// Start the server.
app.listen(PORT, () => {
    console.log(`Token provider is listening port ${PORT}`);
});
// end:token-provider-listen.js
Data Inspector Full Setup

Click here to open the app.

This example creates an instance of DataInspector. It creates a mapView within an HTML element of fixed size and creates a GeoJSON data source connected to the Data API.

This example demonstrates all the features of the Data Inspector, including the Stats panel. This panel shows a log with information about decoded tiles and an expanded panel with information about the decoded tile. For all possible configuration options for UI elements, see the source code of this example below.

Example Source Code


/*
 * Copyright (C) 2018-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

/*
 * This example shows all properties `DataInspector` can accept to customize visualization.
 *
 * Please visit API documentation to see the detailed description of all constructor arguments:
 * https://developer.here.com/olp/documentation/data-inspector-library/api_reference_typedoc/classes/_here_interactive_mapview_ui.hostcomponent.html#constructor
 */


import { DataInspector, PanelDisplayMode } from "@here/interactive-mapview-ui";
import {
    useToken,
    locale,
    showLanguageSelector,
    boundingBox,
    enableExtendedCoverage,
    geoCenter,
    lookupServiceEnvironment,
    omvHostHrn,
    omvDataLayer,
    ribHostHrn,
    ribTopologyLayer
} from "../config";
import { bearerTokenProvider } from "./common";


new DataInspector(
    {
        elementId: "my-host-component",

        // The property below sets custom auth token provider without authentication form.
        // getBearerToken: () => Promise.resolve("Your Token"),

        mapView: {
            theme: "../resources/normal.reduced.night.json",
            decoder: {
                url: "../decoder.bundle.js",
                count: 2
            },
            maxZoomLevel: 15,
            defaultZoomLevel: 12,
            geoCenter: geoCenter,
            // Please note that the "boundingBox" property will override the values of "geoCenter"
            // and "defaultZoomLevel" properties.
            boundingBox,
            enableTilt: false,
            enableRotation: false
        },
        monacoEditorWorkersBasePath: "../monaco-editor",
        translationsBasePath: "../resources/i18n/",
        streamSaverBasePath: "../resources/mitm/",
        defaultLocale: locale || undefined,
        baseMap: {
            hrn: omvHostHrn,
            layer: omvDataLayer,
            // Catalog version for the base map.
            // version: -1;
            styleSetName: "tilezen" //The name of the style set from the theme
        },
        getBearerToken: useToken ? bearerTokenProvider : undefined,
        widgets: {
            zoomLevel: true,
            statusBar: true,
            searchField: true,
            decodedPanel: {
                enabled: true,
                initialState: PanelDisplayMode.Expanded,
                width: 400
            },
            statsPanel: {
                enabled: true,
                initialState: PanelDisplayMode.Collapsed
            },
            authForm: !useToken ? {
                tokenForm: false,
                accessKeyForm: true,
                localAuthForm: true
            } : undefined,
        },
        toolbar: {
            enabled: true,
            fullScreenButton: true,
            languageSelector: showLanguageSelector
        },
        logMessages: true,
        lookupServiceEnvironment,
        pageUrlParams: { enabled: true },
        locales: [
            "en-US",
            "ja-JP",
            "zh-CN",
            "zz-ZZ"
        ]
    },
    document.getElementById("map-here") as HTMLElement,
    {
        interactiveDataSources: [{
            hrn: ribHostHrn,
            layer: ribTopologyLayer,
            catalogVersion: 0,
            levelsWithData: [12],
            externalRendererPluginName: "interactive_host_full.plugin.template",
            preferRendererPlugin: false,
            selectedPartitions: ["23600040", "23605525", "23600039"]
        }],
        enableCoverage: true,
        enableExtendedCoverage,
        enableInfoPanel: true,
        enableFiltering: true
    }
);

HTML+JS Single Page Application

Click here to open the app.

This example demonstrates the easiest way to embed visualization in a single-page application written in pure HTML and JavaScript. This example uses the DataInspector class with all the default values. To run this example code, no compilation is required.

Other

sdii / DI

Click here to open the app.

This example demonstrates how to interact with the features of the Sensor Data Ingestion Interface (SDII) data source. You can highlight paths and road signs with the mouse pointer and filter out individual SDII messages.

Example Source Code


/*
 * Copyright (C) 2018-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { DataInspector } from "@here/interactive-mapview-ui";
import {
    useToken,
    locale,
    showLanguageSelector,
    omvDataLayer,
    omvHostHrn,
    sdiiHostHrn,
    sdiiDataLayer,
    lookupServiceEnvironment
} from "../config";
import { bearerTokenProvider } from "./common";

new DataInspector(
    {
        mapView: {
            theme: "../resources/normal.reduced.night.json",
            decoder: {
                url: "../decoder.bundle.js"
            },
            defaultZoomLevel: 12
        },
        monacoEditorWorkersBasePath: "../monaco-editor",
        translationsBasePath: "../resources/i18n/",
        streamSaverBasePath: "../resources/mitm/",
        defaultLocale: locale || undefined,
        baseMap: {
            hrn: omvHostHrn,
            layer: omvDataLayer
        },
        getBearerToken: useToken ? bearerTokenProvider : undefined,
        widgets: {
            authForm: !useToken ? {
                tokenForm: false,
                accessKeyForm: true,
                localAuthForm: true
            } : undefined
        },
        toolbar: {
            languageSelector: showLanguageSelector
        },
        lookupServiceEnvironment,
        pageUrlParams: { enabled: true }
    },
    document.getElementById("map-here") as HTMLElement,
    {
        interactiveDataSource: {
            hrn: sdiiHostHrn,
            layer: sdiiDataLayer
        },
        enableCoverage: true,
        enableFiltering: true,
        enableInfoPanel: true
    }
);
sdii / DI / animated

Click here to open the app.

This example shows how you can use sdiiDataSource to animate road signs and paths.

Example Source Code


/*
 * Copyright (C) 2018-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { DataInspector } from "@here/interactive-mapview-ui";
import {
    useToken,
    locale,
    showLanguageSelector,
    omvDataLayer,
    omvHostHrn,
    sdiiHostHrn,
    sdiiDataLayer,
    lookupServiceEnvironment
} from "../config";
import { bearerTokenProvider } from "./common";

new DataInspector(
    {
        mapView: {
            theme: "../resources/normal.reduced.night.json",
            decoder: { url: "../decoder.bundle.js" },
            defaultZoomLevel: 12
        },
        monacoEditorWorkersBasePath: "../monaco-editor",
        translationsBasePath: "../resources/i18n/",
        streamSaverBasePath: "../resources/mitm/",
        defaultLocale: locale || undefined,
        baseMap: {
            hrn: omvHostHrn,
            layer: omvDataLayer
        },
        getBearerToken: useToken ? bearerTokenProvider : undefined,
        widgets: {
            authForm: !useToken ? {
                tokenForm: false,
                accessKeyForm: true,
                localAuthForm: true
            } : undefined
        },
        toolbar: {
            languageSelector: showLanguageSelector
        },
        lookupServiceEnvironment,
        pageUrlParams: { enabled: true }
    },
    document.getElementById("map-here") as HTMLElement,
    {
        interactiveDataSource: {
            hrn: sdiiHostHrn,
            layer: sdiiDataLayer,
            animationEnabled: true
        },
        enableCoverage: true,
        enableFiltering: true,
        enableInfoPanel: true
    }
);

sdii / DI / plugin

Click here to open the app.

This example demonstrates how to visualize Sensor Data Ingestion Interface (SDII) data using a GeoJSON rendering plugin.

Example Source Code


/*
 * Copyright (C) 2020-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { DataInspector } from "@here/interactive-mapview-ui";
import { useToken, locale, showLanguageSelector, sdiiDataLayer, sdiiHostHrn, lookupServiceEnvironment } from "../config";
import { bearerTokenProvider } from "./common";

new DataInspector(
    {
        mapView: {
            defaultZoomLevel: 12,
            theme: "../resources/normal.reduced.night.json",
            decoder: {
                url: "../decoder.bundle.js"
            }
        },
        monacoEditorWorkersBasePath: "../monaco-editor",
        translationsBasePath: "../resources/i18n/",
        streamSaverBasePath: "../resources/mitm/",
        defaultLocale: locale || undefined,
        getBearerToken: useToken ? bearerTokenProvider : undefined,
        widgets: {
            authForm: !useToken ? {
                tokenForm: false,
                accessKeyForm: true,
                localAuthForm: true
            } : undefined
        },
        toolbar: {
            languageSelector: showLanguageSelector
        },
        lookupServiceEnvironment,
        pageUrlParams: { enabled: true }
    },
    document.getElementById("map-here") as HTMLElement,
    {
        interactiveDataSource: {
            hrn: sdiiHostHrn,
            layer: sdiiDataLayer,
            preferRendererPlugin: true,
            externalRendererPluginName: "plugin-sdii"
        },
        enableCoverage: true,
        enableFiltering: true,
        enableInfoPanel: true
    }
);

geojson / simple

Click here to open the app.

This example uses GeoJsonDataSource to obtain data from a catalog with GeoJSON data. It visualizes GeoJSON data from a single tile.

Example Source Code


/*
 * Copyright (C) 2017-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { MapViewEventNames } from "@here/harp-mapview";
import { GeoJsonDataSource } from "@here/olp-geojson-datasource";
import { useToken, geoJsonDataLayer, geoJsonDataTile, geoJsonHrn, lookupServiceEnvironment } from "../config";
import {
    addBaseMapCountryBorder,
    bearerTokenProvider,
    createBaseMapDataSource,
    createTokenResolver,
    initializeMapView,
    setupTileSelection
} from "./common";
import { TileControlHandler } from "@here/interactive-mapview-ui";
import { MapControls } from "@here/harp-map-controls";
import {
    BaseMapDataProvider,
    LookupEnvironment,
    PlatformDataProvider
} from "@here/interactive-datasource-protocol";

const canvas = document.getElementById("mapCanvas") as HTMLCanvasElement;
// For the full map initialization code see sdii/simple example
const mapView = initializeMapView(canvas);

let getBearerToken;
if (useToken) {
    getBearerToken = bearerTokenProvider;
} else {
    const tokenResolver = createTokenResolver(mapView);
    getBearerToken = tokenResolver.getBearerToken.bind(tokenResolver) as () => Promise;
}

// Base map
createBaseMapDataSource(getBearerToken).then(omvDataSource => {
    mapView.addDataSource(omvDataSource);
    if (lookupServiceEnvironment === LookupEnvironment.HERE_CN) {
        addBaseMapCountryBorder(mapView, omvDataSource.dataProvider() as BaseMapDataProvider);
    }
});

const dataProvider = new PlatformDataProvider({
    hrn: geoJsonHrn,
    layer: geoJsonDataLayer,
    getToken: getBearerToken,
    environment: lookupServiceEnvironment
});

// geoJSON Data source
const geoJsonDataSource = new GeoJsonDataSource({
    dataProvider
});

mapView.addEventListener(MapViewEventNames.DataSourceConnect, (event: any) => {
    if (event.dataSourceName === geoJsonDataSource.name) {
        geoJsonDataSource.selectTile(geoJsonDataTile);
    }
});

mapView.addDataSource(geoJsonDataSource);

const mapControls = new MapControls(mapView);
mapControls.zoomLevelDeltaOnDoubleClick = 0;
mapControls.setZoomLevel(13);
setupTileSelection(mapView, new TileControlHandler(mapView, mapControls, geoJsonDataSource));

geojson / without / dataservice

Click here to open the app.

This example visualizes the geometry of a hard-coded GeoJSON object without connecting to the Data API.

Example Source Code


/*
 * Copyright (C) 2017-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { MapViewEventNames } from "@here/harp-mapview";
import {
    BaseMapDataProvider,
    InteractiveIntersectionAgent,
    LookupEnvironment
} from "@here/interactive-datasource-protocol";
import { GeoJsonDataSource } from "@here/olp-geojson-datasource";
import {
    addBaseMapCountryBorder,
    bearerTokenProvider,
    createBaseMapDataSource,
    createTokenResolver,
    initializeMapView,
    setupTileSelection
} from "./common";
import { TileControlHandler } from "@here/interactive-mapview-ui";
import { MapControls } from "@here/harp-map-controls";
import { useToken, geoJsonData, geoJsonMapCenter, lookupServiceEnvironment } from "../config";
import { GeoCoordinates } from "@here/harp-geoutils";

const canvas = document.getElementById("mapCanvas") as HTMLCanvasElement;
// For the full map initialization code see sdii/simple example
const mapView = initializeMapView(canvas);
mapView.geoCenter = new GeoCoordinates(geoJsonMapCenter.latitude, geoJsonMapCenter.longitude);

let getBearerToken;
if (useToken) {
    getBearerToken = bearerTokenProvider;
} else {
    const tokenResolver = createTokenResolver(mapView);
    getBearerToken = tokenResolver.getBearerToken.bind(tokenResolver) as () => Promise;
}

// Base map
createBaseMapDataSource(getBearerToken).then(omvDataSource => {
    mapView.addDataSource(omvDataSource);
    if (lookupServiceEnvironment === LookupEnvironment.HERE_CN) {
        addBaseMapCountryBorder(mapView, omvDataSource.dataProvider() as BaseMapDataProvider);
    }
});

// geoJSON Data source
const geoJsonDataSource = new GeoJsonDataSource({
    intersectionAgent: new InteractiveIntersectionAgent(mapView)
});

mapView.addDataSource(geoJsonDataSource);

/**
 * Show geoJSON data from other resource than DataStore
 * (e.g. read from the file, direct geoJSON object).
 */
mapView.addEventListener(MapViewEventNames.DataSourceConnect, (event: any) => {
    if (event.dataSourceName === geoJsonDataSource.name) {
        geoJsonDataSource.renderGeoJson(geoJsonData);
    }
});

const mapControls = new MapControls(mapView);
mapControls.zoomLevelDeltaOnDoubleClick = 0;
mapControls.setZoomLevel(17);
setupTileSelection(mapView, new TileControlHandler(mapView, mapControls, geoJsonDataSource));

geojson / DI / plugin

Click here to open the app.

This example visualizes speed limits using an external GeoJSON rendering plugin. The plugin uses SegmentAnchorGeometryDataProvider to retrieve road geometries and map speed limit data to them.

Example Source Code


/*
 * Copyright (C) 2017-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { DataInspector, DataInspectorEventNames } from "@here/interactive-mapview-ui";
import { useToken, locale, showLanguageSelector, lookupServiceEnvironment, ribHostHrn, speedLimitTiles } from "../config";
import { bearerTokenProvider } from "./common";

const dataInspector = new DataInspector(
    {
        mapView: {
            defaultZoomLevel: 11,
            theme: "../resources/normal.reduced.night.json",
            decoder: {
                url: "../decoder.bundle.js"
            }
        },
        monacoEditorWorkersBasePath: "../monaco-editor",
        translationsBasePath: "../resources/i18n/",
        streamSaverBasePath: "../resources/mitm/",
        defaultLocale: locale || undefined,
        getBearerToken: useToken ? bearerTokenProvider : undefined,
        widgets: {
            authForm: !useToken ? {
                tokenForm: false,
                accessKeyForm: true,
                localAuthForm: true
            } : undefined
        },
        toolbar: {
            languageSelector: showLanguageSelector
        },
        lookupServiceEnvironment,
        pageUrlParams: { enabled: true }
    },
    document.getElementById("map-here") as HTMLElement,
    {
        interactiveDataSource: {
            hrn: ribHostHrn,
            layer: "navigation-attributes",
            externalRendererPluginName: "renderer.plugin.template"
        },
        enableCoverage: true
    }
);

if (dataInspector.mapView === undefined) {
    throw new Error("MapView was not initialized.");
}

dataInspector.addEventListener(
    DataInspectorEventNames.DATA_INSPECTOR_IS_READY,
    () => speedLimitTiles.forEach(tile => dataInspector.tileControlHandler.selectTile(tile, true))
);

geojson / properties

Click here to open the app.

This example visualizes such custom GeoJSON feature properties as style.color, style.fill, style.width, properties.tooltip, as well as other MapBox styles.

Example Source Code


/*
 * Copyright (C) 2017-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { GeoCoordinates } from "@here/harp-geoutils";
import { MapViewEventNames } from "@here/harp-mapview";
import {
    BaseMapDataProvider,
    InteractiveIntersectionAgent,
    LookupEnvironment
} from "@here/interactive-datasource-protocol";
import { GeoJsonDataSource } from "@here/olp-geojson-datasource";
import {
    addBaseMapCountryBorder,
    bearerTokenProvider,
    createBaseMapDataSource,
    createTokenResolver,
    InformationPanel,
    initializeMapView,
    setupTileSelection
} from "./common";
import {
    useToken,
    geoJsonProperties,
    geoJsonPropertiesCenter,
    lookupServiceEnvironment
} from "../config";
import { MapControls } from "@here/harp-map-controls";
import {
    GeoJsonInfoPanel,
    I18n,
    installInfoWidgets,
    TileControlHandler
} from "@here/interactive-mapview-ui";

const canvas = document.getElementById("mapCanvas") as HTMLCanvasElement;
// For the full map initialization code see sdii/simple example
const mapView = initializeMapView(canvas);
mapView.geoCenter = new GeoCoordinates(
    geoJsonPropertiesCenter.latitude,
    geoJsonPropertiesCenter.longitude
);

// Create info panel
const infoPanelMsg = I18n.translate("olpdi.examples.geojson-properties.hint");
new InformationPanel(infoPanelMsg);

let getBearerToken;
if (useToken) {
    getBearerToken = bearerTokenProvider;
} else {
    const tokenResolver = createTokenResolver(mapView);
    getBearerToken = tokenResolver.getBearerToken.bind(tokenResolver) as () => Promise;
}

// Base map
createBaseMapDataSource(getBearerToken).then(omvDataSource => {
    mapView.addDataSource(omvDataSource);
    if (lookupServiceEnvironment === LookupEnvironment.HERE_CN) {
        addBaseMapCountryBorder(mapView, omvDataSource.dataProvider() as BaseMapDataProvider);
    }
});

// GeoJSON Data source
const geoJsonDataSource = new GeoJsonDataSource({
    intersectionAgent: new InteractiveIntersectionAgent(mapView)
});

mapView.addDataSource(geoJsonDataSource);

installInfoWidgets(GeoJsonInfoPanel, geoJsonDataSource, document.body, "geojson-info-panel");

// Show geoJSON data from other resource than DataStore
// (e.g. read from the file, direct geoJSON object)
mapView.addEventListener(MapViewEventNames.DataSourceConnect, (event: any) => {
    if (event.dataSourceName === geoJsonDataSource.name) {
        geoJsonDataSource.renderGeoJson(geoJsonProperties);
    }
});

const mapControls = new MapControls(mapView);
mapControls.zoomLevelDeltaOnDoubleClick = 0;
mapControls.setZoomLevel(17);
setupTileSelection(mapView, new TileControlHandler(mapView, mapControls, geoJsonDataSource));

geojson / bounding / box

Click here to open the app.

This example automatically adjusts a map's zoom and position to fit a specific GeoJSON object. You can obtain the bounding box of the rendered GeoJSON object in the GeoJsonDataSource.EVENT_TILE_DECODED event. This example provides sample code to calculate the camera's position of the mapView allowing you to fit an object in the map view.

Example Source Code


/*
 * Copyright (C) 2017-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { GeoCoordinates } from "@here/harp-geoutils";
import { MapViewEventNames } from "@here/harp-mapview";
import {
    BaseMapDataProvider,
    InteractiveIntersectionAgent,
    LookupEnvironment
} from "@here/interactive-datasource-protocol";
import { GeoJsonDataSource, GeoJsonDataSourceEvent } from "@here/olp-geojson-datasource";
import {
    bearerTokenProvider,
    createBaseMapDataSource,
    initializeMapView,
    setupTileSelection,
    createTokenResolver,
    addBaseMapCountryBorder
} from "./common";
import { TileBoundingBox, TileControlHandler } from "@here/interactive-mapview-ui";
import { MapControls } from "@here/harp-map-controls";
import { useToken, geoJsonData, lookupServiceEnvironment } from "../config";

const canvas = document.getElementById("mapCanvas") as HTMLCanvasElement;
// For the full map initialization code see sdii/simple example
const mapView = initializeMapView(canvas);
// Initially position map off desired location.
mapView.geoCenter = new GeoCoordinates(10, 10);

let getBearerToken;
if (useToken) {
    getBearerToken = bearerTokenProvider;
} else {
    const tokenResolver = createTokenResolver(mapView);
    getBearerToken = tokenResolver.getBearerToken.bind(tokenResolver) as () => Promise;
}

// Base map
createBaseMapDataSource(getBearerToken).then(omvDataSource => {
    mapView.addDataSource(omvDataSource);
    if (lookupServiceEnvironment === LookupEnvironment.HERE_CN) {
        addBaseMapCountryBorder(mapView, omvDataSource.dataProvider() as BaseMapDataProvider);
    }
});

// GeoJSON Data source
const geoJsonDataSource = new GeoJsonDataSource({
    intersectionAgent: new InteractiveIntersectionAgent(mapView)
});

mapView.addDataSource(geoJsonDataSource);

/**
 * Show geoJSON data from other resource than DataStore
 * (e.g. read from the file, direct geoJSON object).
 */
mapView.addEventListener(MapViewEventNames.DataSourceConnect, (event: any) => {
    if (event.dataSourceName === geoJsonDataSource.name) {
        geoJsonDataSource.renderGeoJson(geoJsonData);
    }
});

// Map centering by bounding box
geoJsonDataSource.addEventListener(
    GeoJsonDataSource.EVENT_BEFORE_TILE_RENDERED,
    (event: GeoJsonDataSourceEvent) => {
        const boundingBox = event.boundingBox;
        if (boundingBox === undefined) {
            return;
        }

        TileBoundingBox.fitMapViewToWorldBoundingBox(mapView, boundingBox, mapControls, 50);
    }
);

const mapControls = new MapControls(mapView);
setupTileSelection(mapView, new TileControlHandler(mapView, mapControls, geoJsonDataSource));

geojson / tilegrid

Click here to open the app.

This example demonstrates how to couple the GeoJSON data source with the coverage data source to visualize those tiles that have data. GeoJsonDataSource obtains data from a catalog with GeoJSON data, and coverageDataSource is connected to the same catalog, so that they represent the same data.

Example Source Code


/*
 * Copyright (C) 2017-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { CoverageDataSource } from "@here/coverage-datasource";
import {
    PlatformDataProvider,
    InteractiveIntersectionAgent,
    LookupEnvironment,
    BaseMapDataProvider
} from "@here/interactive-datasource-protocol";
import { GeoJsonDataSource } from "@here/olp-geojson-datasource";
import {
    useToken,
    geoJsonDataLayer,
    geoJsonHrn,
    geoJsonLevelWithData,
    lookupServiceEnvironment
} from "../config";
import {
    bearerTokenProvider,
    InformationPanel,
    createBaseMapDataSource,
    createTokenResolver,
    initializeMapView,
    setupTileSelection,
    addBaseMapCountryBorder
} from "./common";
import { I18n, TileControlHandler } from "@here/interactive-mapview-ui";
import { MapControls } from "@here/harp-map-controls";

const canvas = document.getElementById("mapCanvas") as HTMLCanvasElement;

const mapView = initializeMapView(canvas);

// Create info panel
new InformationPanel(I18n.translate("olpdi.examples.geojson-tilegrid.hint"));

let getBearerToken;
if (useToken) {
    getBearerToken = bearerTokenProvider;
} else {
    const tokenResolver = createTokenResolver(mapView);
    getBearerToken = tokenResolver.getBearerToken.bind(tokenResolver) as () => Promise;
}

// Base map
createBaseMapDataSource(getBearerToken).then(omvDataSource => {
    mapView.addDataSource(omvDataSource);
    if (lookupServiceEnvironment === LookupEnvironment.HERE_CN) {
        addBaseMapCountryBorder(mapView, omvDataSource.dataProvider() as BaseMapDataProvider);
    }
});

const dataProvider = new PlatformDataProvider({
    hrn: geoJsonHrn,
    layer: geoJsonDataLayer,
    getToken: getBearerToken,
    environment: lookupServiceEnvironment
});

// Tile grid
const coverageDataSource = new CoverageDataSource({
    dataProvider,
    // The grid will be rendered for specified tiles level
    levelsWithData: [geoJsonLevelWithData]
});
mapView.addDataSource(coverageDataSource);

// geoJSON Data source
const geoJsonDataSource = new GeoJsonDataSource({
    dataProvider,
    intersectionAgent: new InteractiveIntersectionAgent(mapView),
    levelsWithData: [geoJsonLevelWithData]
});

mapView.addDataSource(geoJsonDataSource);

const mapControls = new MapControls(mapView);
mapControls.zoomLevelDeltaOnDoubleClick = 0;
mapControls.setZoomLevel(12);
setupTileSelection(
    mapView,
    new TileControlHandler(mapView, mapControls, geoJsonDataSource, coverageDataSource)
);

geojson / events

Click here to open the app.

This example demonstrates how to subscribe to various events of the GeoJsonDataSource. After the tiles have been loaded, you can see the events that are triggered by long-clicking any tile. It adds event listeners to the EVENT_TILE_GET, EVENT_TILE_DECODED, EVENT_BEFORE_TILE_DECODE, EVENT_TILE_SELECT, and EVENT_TILE_DESELECT events.

Example Source Code


/*
 * Copyright (C) 2017-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { CoverageDataSource } from "@here/coverage-datasource";
import {
    PlatformDataProvider,
    InteractiveIntersectionAgent,
    LookupEnvironment,
    BaseMapDataProvider
} from "@here/interactive-datasource-protocol";
import { GeoJsonDataSource } from "@here/olp-geojson-datasource";
import {
    useToken,
    geoJsonDataLayer,
    geoJsonHrn,
    geoJsonLevelWithData,
    lookupServiceEnvironment,
} from "../config";
import {
    bearerTokenProvider,
    createBaseMapDataSource,
    InformationPanel,
    initializeMapView,
    setupTileSelection,
    createTokenResolver,
    addBaseMapCountryBorder
} from "./common";
import { MapControls } from "@here/harp-map-controls";
import { I18n, TileControlHandler } from "@here/interactive-mapview-ui";

const canvas = document.getElementById("mapCanvas") as HTMLCanvasElement;
// For the full map initialization code see sdii/simple example
const mapView = initializeMapView(canvas);

// Create info panel
const infoPanelMsg = I18n.translate("olpdi.examples.geojson-events.hint") + ``
    + I18n.translate("olpdi.examples.geojson-events.events-list-title") + `:`;
const infoPanel = new InformationPanel(infoPanelMsg, true);

let getBearerToken;
if (useToken) {
    getBearerToken = bearerTokenProvider;
} else {
    const tokenResolver = createTokenResolver(mapView);
    getBearerToken = tokenResolver.getBearerToken.bind(tokenResolver) as () => Promise;
}

// Base map
createBaseMapDataSource(getBearerToken).then(omvDataSource => {
    mapView.addDataSource(omvDataSource);
    if (lookupServiceEnvironment === LookupEnvironment.HERE_CN) {
        addBaseMapCountryBorder(mapView, omvDataSource.dataProvider() as BaseMapDataProvider);
    }
});

const dataProvider = new PlatformDataProvider({
    hrn: geoJsonHrn,
    getToken: getBearerToken,
    layer: geoJsonDataLayer,
    environment: lookupServiceEnvironment
});

// Tile grid
const coverageDataSource = new CoverageDataSource({
    dataProvider,
    // The grid will be rendered for specified tiles level
    levelsWithData: [geoJsonLevelWithData]
});
mapView.addDataSource(coverageDataSource);

// geoJSON Data source
const intersectionAgent = new InteractiveIntersectionAgent(mapView);
const geoJsonDataSource = new GeoJsonDataSource({
    dataProvider,
    intersectionAgent,
    levelsWithData: [geoJsonLevelWithData]
});

mapView.addDataSource(geoJsonDataSource);

// all events of GeoJsonDataSource
geoJsonDataSource.addEventListener(GeoJsonDataSource.EVENT_TILE_GET, () => {
    infoPanel.element.innerText += GeoJsonDataSource.EVENT_TILE_GET + "\n";
});

geoJsonDataSource.addEventListener(GeoJsonDataSource.EVENT_TILE_DECODED, () => {
    infoPanel.element.innerText += GeoJsonDataSource.EVENT_TILE_DECODED + "\n";
});

geoJsonDataSource.addEventListener(GeoJsonDataSource.EVENT_BEFORE_TILE_DECODE, () => {
    infoPanel.element.innerText += GeoJsonDataSource.EVENT_BEFORE_TILE_DECODE + "\n";
});

geoJsonDataSource.addEventListener(GeoJsonDataSource.EVENT_BEFORE_TILE_RENDERED, () => {
    infoPanel.element.innerText += GeoJsonDataSource.EVENT_BEFORE_TILE_RENDERED + "\n";
});

geoJsonDataSource.addEventListener(GeoJsonDataSource.EVENT_TILE_SELECT, () => {
    infoPanel.element.innerText += GeoJsonDataSource.EVENT_TILE_SELECT + "\n";
});

geoJsonDataSource.addEventListener(GeoJsonDataSource.EVENT_TILE_DESELECT, () => {
    infoPanel.element.innerText += GeoJsonDataSource.EVENT_TILE_DESELECT + "\n";
});

const mapControls = new MapControls(mapView);
mapControls.setZoomLevel(12);
setupTileSelection(
    mapView,
    new TileControlHandler(mapView, mapControls, geoJsonDataSource, coverageDataSource)
);

geojson / contenttype / versioned

Click here to open the app.

This example shows how to load GeoJSON data from a versioned layer of a catalog.

Example Source Code


/*
 * Copyright (C) 2017-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */


import { CoverageDataSource } from "@here/coverage-datasource";
import {
    PlatformDataProvider,
    InteractiveIntersectionAgent,
    LookupEnvironment,
    BaseMapDataProvider
} from "@here/interactive-datasource-protocol";
import { GeoJsonDataSource } from "@here/olp-geojson-datasource";
import {
    useToken,
    geoJsonContentTypeHrn,
    geoJsonContentTypeLayerVersioned,
    geoJsonContentTypeLevelWithData,
    lookupServiceEnvironment
} from "../config";
import {
    addBaseMapCountryBorder,
    bearerTokenProvider,
    createBaseMapDataSource,
    createTokenResolver,
    InformationPanel,
    initializeMapView,
    setupTileSelection
} from "./common";

import { MapControls } from "@here/harp-map-controls";
import { I18n, TileControlHandler } from "@here/interactive-mapview-ui";

const canvas = document.getElementById("mapCanvas") as HTMLCanvasElement;
// For the full map initialization code see sdii/simple example
const mapView = initializeMapView(canvas);

// Create info panel
const infoPanelMsg = I18n.translate("olpdi.examples.geojson-contenttype-versioned.hint");
new InformationPanel(infoPanelMsg);

let getBearerToken;
if (useToken) {
    getBearerToken = bearerTokenProvider;
} else {
    const tokenResolver = createTokenResolver(mapView);
    getBearerToken = tokenResolver.getBearerToken.bind(tokenResolver) as () => Promise;
}

// Base map
createBaseMapDataSource(getBearerToken).then(omvDataSource => {
    mapView.addDataSource(omvDataSource);
    if (lookupServiceEnvironment === LookupEnvironment.HERE_CN) {
        addBaseMapCountryBorder(mapView, omvDataSource.dataProvider() as BaseMapDataProvider);
    }
});

const dataProvider = new PlatformDataProvider({
    hrn: geoJsonContentTypeHrn,
    getToken: getBearerToken,
    layer: geoJsonContentTypeLayerVersioned,
    environment: lookupServiceEnvironment
});

// GeoJSON Data Source
const geoJsonDataSource = new GeoJsonDataSource({
    dataProvider,
    levelsWithData: [geoJsonContentTypeLevelWithData],
    schemaProviderOptions: {
        enabled: false
    },
    intersectionAgent: new InteractiveIntersectionAgent(mapView)
});

mapView.addDataSource(geoJsonDataSource);

// Tile grid
const coverageDataSource = new CoverageDataSource({
    dataProvider,
    // The grid will be rendered for specified tiles level
    levelsWithData: [geoJsonContentTypeLevelWithData],
    schemaProviderOptions: {
        enabled: false
    }
});
mapView.addDataSource(coverageDataSource);

const mapControls = new MapControls(mapView);
mapControls.setZoomLevel(13);
setupTileSelection(
    mapView,
    new TileControlHandler(mapView, mapControls, geoJsonDataSource, coverageDataSource)
);

geometrydataprovider / speedlimits / DI

Click here to open the app.

This example showcases how to create an instance of custom InteractiveDataSource and dynamically add it to a DataInspector instance. Custom SpeedLimitsDataSource visualizes speed limits from the HERE Map Content catalog. It retrieves the speed limits data from the HERE Map Content Navigation Attributes layer and visualizes it over the roads geometry from the HERE Map Content Road Topology layer. The speed limits data has no geometry information, so it is mapped to road segments from the Roads - Topology & Geometry layer.

Example Source Code


/*
 * Copyright (C) 2017-2023 HERE Global B.V. and its affiliate(s). All rights reserved.
 *
 * This software and other materials contain proprietary information controlled by HERE and are
 * protected by applicable copyright legislation. Any use and utilization of this software and other
 * materials and disclosure to any third parties is conditional upon having a separate agreement
 * with HERE for the access, use, utilization or disclosure of this software. In the absence of such
 * agreement, the use of the software is not allowed.
 */

import { SegmentAnchorGeometryDataProvider } from "@here/geometry-data-provider";
import {
    PlatformDataProvider,
    InteractiveIntersectionAgent
} from "@here/interactive-datasource-protocol";
import {
    DataInspector,
    DataInspectorEventNames,
    InfoPanel,
    installInfoWidgetsWhenDataSourceReady,
    PanelDisplayMode
} from "@here/interactive-mapview-ui";
import {
    useToken,
    locale,
    showLanguageSelector,
    omvDataLayer,
    omvHostHrn,
    lookupServiceEnvironment,
    ribHrn,
    ribTopologyLayer,
    speedLimitTiles
} from "../config";
import { bearerTokenProvider } from "./common";
import { SpeedLimitsDataSource } from "./datasources/speedLimitsDataSource/SpeedLimitsDataSource";

/**
 * This example showcases dynamically creating and using a custom implementation of
 * `InteractiveDataSource` - a datasource to visualize speed limits from RIB catalog.
 *
 * Because custom `SpeedLimitsDataSource` datasource is not determined by `DataInspector` by catalog
 * HRN, it is added to an instance of `DataInspector` after it is initialized.
 */

// Create an instance of `DataInspector`.
const dataInspector = new DataInspector(
    {
        elementId: "may-host-component",
        mapView: {
            theme: "../resources/normal.reduced.night.json",
            decoder: {
                url: "../decoder.bundle.js"
            },
            defaultZoomLevel: 12,
            enableTilt: false,
        },
        monacoEditorWorkersBasePath: "../monaco-editor",
        translationsBasePath: "../resources/i18n/",
        streamSaverBasePath: "../resources/mitm/",
        defaultLocale: locale || undefined,
        baseMap: {
            hrn: omvHostHrn,
            layer: omvDataLayer
        },
        getBearerToken: useToken ? bearerTokenProvider : undefined,
        widgets: {
            zoomLevel: true,
            statusBar: true,
            searchField: true,
            decodedPanel: {
                enabled: true,
                initialState: PanelDisplayMode.Expanded,
                width: 400
            },
            statsPanel: {
                enabled: true,
                initialState: PanelDisplayMode.Collapsed
            },
            authForm: !useToken ? {
                tokenForm: false,
                accessKeyForm: true,
                localAuthForm: true
            } : undefined
        },
        toolbar: {
            enabled: true,
            fullScreenButton: true,
            languageSelector: showLanguageSelector
        },
        logMessages: true,
        lookupServiceEnvironment,
        pageUrlParams: { enabled: true }
    },
    document.getElementById("map-here") as HTMLElement,
    undefined,
    true
);

let speedLimitsDataSource: SpeedLimitsDataSource | undefined;

dataInspector.addEventListener(
    DataInspectorEventNames.DATA_INSPECTOR_IS_READY,
    async () => {
        if (dataInspector.mapView === undefined || dataInspector.interactiveDataSource !== undefined) {
            return;
        }
        //create data provider
        const dataProvider = new PlatformDataProvider({
            hrn: ribHrn,
            layer: "navigation-attributes",
            getToken: dataInspector.getConfig().getBearerToken!,
            environment: lookupServiceEnvironment
        });
        await dataProvider.connect();
        // Create an instance of `SegmentAnchorGeometryDataProvider`, necessary for `SpeedLimitsDataSource`.
        const geometryDataProvider = new SegmentAnchorGeometryDataProvider(
            {
                hrn: ribHrn,
                layer: ribTopologyLayer,
                getToken: dataInspector.getConfig().getBearerToken!,
                environment: lookupServiceEnvironment
            }
        );
        await geometryDataProvider.connect();

        const selectedTiles = speedLimitsDataSource !== undefined
            ? [...speedLimitsDataSource.selectedPartitions]
            : [speedLimitTiles[0]];
        // Create a sample speed limits datasource which uses `RoadSegmentsDataProvider`.
        speedLimitsDataSource = new SpeedLimitsDataSource({
            dataProvider,
            geometryDataProvider
        });
        speedLimitsDataSource.isSelected = true;

        // An instance of `InteractiveIntersectionAgent` is needed to detect speed limit items under mouse
        // pointer.
        const intersectionAgent = new InteractiveIntersectionAgent(dataInspector.mapView);
        speedLimitsDataSource.setUpIntersectionAgent(intersectionAgent);

        if (dataInspector.controlPanel !== undefined) {
            installInfoWidgetsWhenDataSourceReady(
                InfoPanel,
                speedLimitsDataSource,
                dataInspector.controlPanel.container,
                "info-panel"
            );
        }

        await dataInspector.setInteractiveDataSources([speedLimitsDataSource]);

        // Select speed limit tiles.
        for (const tile of selectedTiles) {
            dataInspector.tileControlHandler.selectTile(tile.toString(), true);
        }
    }
);

results matching ""

    No results matching ""