This chapter explains how you can use Leaflet JS to visualize GeoJSON or Protobuf-encoded data from a HERE platform catalog layer on top of the HERE-provided Optimized Map for Visualization Plus (OMV Plus) base map or any other Leaflet-supported map provider of your choice.
The Data Inspector Library comes with two examples that demonstrate Leaflet usage for working with platform data:
The leaflet / geojson example demonstrates how you can use JavaScript to authenticate with the HERE platform and access GeoJSON data in the HERE GeoJSON Samples catalog with the HERE Data SDK for TypeScript, how to show the OMV Plus base map using the HARP plugin for Leaflet, and how to visualize the data on top of the base map.
Figure 1. GeoJSON data visualization with Leaflet
The leaflet / protobuf example demonstrates the same HERE platform authentication and base map rendering mechanisms as the example above. The only difference is that leaflet / protobuf shows how to access Protobuf-encoded data in the Roads - Topology & Geometry layer from the HERE Map Content catalog, how to retrieve a schema from the layer and use it to decode the data into GeoJSON, and how to render the data atop the base map.
Figure 2. Encoded data visualization with Leaflet
Build a Sample Web App
To build a simple app that implements platform data visualization with Leaflet:
Create an empty HTML file.
Depending on what base map you want to use and what type of platform data you want to visualize (GeoJSON or Protobuf-encoded data), add the necessary libraries to the <head> section of your HTML:
The chapters below explain in detail how you should implement the corresponding libraries to authenticate with the platform, retrieve layer data, and visualize the data on the base map.
Add an element where the Leaflet-supported map, including HERE OMV Plus, will be placed in the <body> section:
<divid="map"style="height: 100%"></div>
Authentication with the Platform
To authenticate with the platform, you have to use the function that returns an access token. In the UserAuth constructor, specify your app credentials - access key ID, secret, and project scope (optional):
// Get a function, that will provide a token to access HERE data.const token =newUserAuth({
env,credentials:{
accessKeyId,
accessKeySecret
},tokenRequester: requestToken,
scope
}).getToken();getToken=()=> token;
To fetch platform data, you need an instance of the layer with data:
/**
* Fetch the layer config and return an instance of a layer client.
*
* @param hrn A catalog HRN.
* @param layerId A layer ID.
* @param settings Client settings.
*/asyncfunctiongetLayerConfig(hrn, layerId, settings){const catalogClient =newCatalogClient(HRN.fromString(hrn), settings);const config =await catalogClient.getCatalog(newCatalogRequest());return config.layers.find(item=> item.id === layerId);}/**
* Fetch the layer config and return an instance of a layer client.
*
* @param layerType A layer type.
* @param hrn A catalog HRN.
* @param layerId A layer ID.
* @param settings Client settings.
*/functiongetLayerClient(layerType, hrn, layerId, settings){const hrnInstance =HRN.fromString(hrn);const layerClientParams ={catalogHrn: hrnInstance, layerId, settings };switch(layerType){case"versioned":returnnewVersionedLayerClient(layerClientParams);case"volatile":returnnewVolatileLayerClient(layerClientParams);default:thrownewError(`Layer type "${layerType}" is not supported yet.`);}}
// Get layer object, that will fetch GeoJSON data.const settings =newOlpClientSettings({environment: env,
getToken
});const layerConfig =awaitgetLayerConfig(hrn, layerId, settings);if(!layerConfig){thrownewError("Layer config was not found");}const layer =getLayerClient(layerConfig.layerType, hrn, layerId, settings);
If the layer data is Protobuf encoded, you need to provide a decoder to convert the encoded data to GeoJSON data. Usually, the decoder exists in a schema associated with the layer. That is why you have to load the schema and get the decoder from there:
/**
* Fetch and process schema archive to prepare a Protobuf decoder.
*
* @param layer Instance of a layer client.
*/asyncfunctiongetDecoder(hrn, settings){// Get schema with protobuf filesconst artifactClient =newArtifactClient(settings);const detailsRequest =newSchemaDetailsRequest().withSchema(HRN.fromString(hrn));const details =await artifactClient.getSchemaDetails(detailsRequest);if(details ===undefined|| details.variants ===undefined){return;}const variant = details.variants.find(item=> item.id ==="ds");if(variant ===undefined){return;}const request =newSchemaRequest().withVariant(variant);const archive =await artifactClient.getSchema(request);// Load schema as a ZIP archiveconst zip =newJSZip();await zip.loadAsync(archive);// Read all .proto file and parse them by Protobufconst protobufRoot =newprotobuf.Root();
Object.keys(zip.files).forEach(asyncfileName=>{if(!fileName.endsWith(".proto")){return;}const file =await zip.file(fileName).async("text");
protobuf.parse(file, protobufRoot,{keepCase:true})});// Extract the manifest data.const manifestFile =await zip.file("META-INF/layer.manifest.json").async("text");const manifest =JSON.parse(manifestFile);return protobufRoot.lookupType(manifest.main.message);}
if(layerConfig.schema ===undefined|| layerConfig.schema.hrn ===undefined){thrownewError("Layer schema HRN is not defined");}// Get a decoder from the schema.const decoder =awaitgetDecoder(layerConfig.schema.hrn, settings);if(!decoder){thrownewError("Decoder was not found.");}
Request partitions to visualize and add them to Leaflet. If the data is in the GeoJSON format, then simply use the Leaflet's geoJSON method to visualize the data:
// Get tile data and add to Leaflet.
partitions.forEach(asyncpartition=>{const request =newDataRequest().withPartitionId(`${partition}`);const response =await layer.getData(request);const data =await response.json();L.geoJSON(data).bindPopup(item=> item.feature.properties.tooltip).addTo(map);});
Encoded data must be first decoded, then the data can be converted into GeoJSON and visualized with the Leaflet's geoJSON method:
// Fetch, decode and visualize specific partitions.
partitions.forEach(asyncpartition=>{const request =newDataRequest().withPartitionId(`${partition}`);const response =await layer.getData(request);const data =await response.arrayBuffer();const decodedData =decode(data, decoder);const geojson = decodedData.segment.map(segment=>({type:"Feature",properties:{tooltip: segment.identifier
},geometry:{type:"LineString",coordinates: segment.geometry.point.map(point=>[point.longitude, point.latitude])}}));L.geoJSON(geojson).bindPopup(layer=> layer.feature.properties.tooltip).addTo(map);});
Visualize HERE OMV Plus Base Map
The code snippet below demonstrates how you can visualize the HERE OMV Plus base map with the harp.gl plugin for Leaflet: