Hands On

Custom Locations with the HERE Fleet Telematics APIs- Part I

By Shruti Kuber | 19 June 2019

Businesses often rent warehouses for temporary use. They may also have private offices and locations which they want to see only on their map. In this post we are going to find out how to do exactly that. After discussing Truck routing in the previous blog, let us explore the Custom Location API, one of the HERE Fleet Telematics APIs.

What are custom locations?

Any locations that you want visible only on your private edition of the map, can be a custom location. These locations can be in the form of points- exact location of a place, polyline- a private road or polygons- shape of an area like a parking lot. In this example, I am considering exact locations of warehouses (Points) that your trucks will be delivering goods to.

How do these locations get added to the map?

These locations are added to the map in the form of a layer on top of the basic map. You can then retrieve this layer by making it visible on your map and by making HTTP REST requests to search for locations within this layer with respect to your location. Let's begin the fun part!

Adding custom locations

Custom locations can be added to your map in 2 ways:

  1. Upload CSV files through a web portal:If you have a list of places with incomplete or full addresses, this list can be geocoded using the web portal. Log in to the portal using the app_id and app_code you will be using for building the application. Remember that a custom layer is bound to the credentials using for logging in unless linked to more credentials. If you don't have an app_id and app_code yet, get them for free by signing up at the Developer Portal. Now, after you have logged in to the portal using your credentials, you will be able to see all the added layers on your layer manager. You can upload a layer here by clicking on Geocode layer enterprise_portal Upload a csv where you have saved the list of addresses. Enter the names of columns that match those given on the page and click on Geocode. Provide a name to this layer. Note that this will be the layer_id used to identify the layer. You can also directly add the 'Latitude' and 'Longitude' columns if you have that data instead.
  2. Upload WKT files using REST call

    WKT or Well-Known Text is a markup format used to represent vector geometry objects on a map. To add custom locations using the RESTful API, you will have to convert your data in a WKT file. A WKT file has the extension 'wkt' and has a column named WKT in it which contains the location geometry. You can either add 'POINT' geometry, 'POLYGON' or 'POLYLINE' geometries. Note that one file can contain only one geometry type. Below is an example of a WKT file.

    	NAME	STREET	DISTRICT	POSTALCODE	CITY	COUNTRY	MATCH_LEVEL	GEOMETRY_ID	WKT
        Lemke	Luisenplatz 1	Charlottenburg	10585	Berlin	Germany	houseNumber	32	POINT(13.2998139 52.520075)
        Adonis	Torstraße 132	Mitte	10119	Berlin	Germany	houseNumber	31	POINT(13.40015 52.5294)

    To upload this layer, use the following REST call with the post body as the wkt file.

    var url = "https://cle.api.here.com/2/layers/upload.json";
    url= addURLParam(url, "app_id", my_app_id);
    url= addURLParam(url, "app_code", my_app_code);
    url= addURLParam(url, "layer_id", "WAREHOUSES_DIST_3");
    
    function init(){
      document.getElementById('upload').addEventListener('click', upload);
    }
    
    function upload(event){
      event.preventDefault();    //stop the form submitting
    
      //header for accepted response
      let h = new Headers();
      h.append('Accept', 'application/json');
      let fileupload = new FormData();
      let myFile = document.getElementById('fileUpload').files[0];
      // The key in this case can be anything. I have named it layer
      fileupload.append('layer', myFile, "layer.wkt");
     
      let uploadRequest = new Request(url, {
          method: 'POST',
          headers: h,
          mode: 'no-cors',
          body: fileupload
      });
    
      fetch(uploadRequest)
      .then(response => {
        document.getElementById('map').innerHTML = "File uploaded";
    })
      .catch(error => console.error('Error:', error));
    }
    
    function addURLParam(url, name, value){
      url += (url.indexOf("?") == -1 ? "?" : "&");
      url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
      return url; 
    }

Displaying the custom location layer

Now that you have added the layer, you can display it as a separate layer on top of your map.

    // set up containers for the map  + panel
    var mapContainer = document.getElementById('map');
        // routeInstructionsContainer = document.getElementById('panel');
    
    //Step 1: initialize communication with the platform
    let M = {
        'Init': { // developer.here.com for app_id and app_code
            "app_id":   my_app_id,
            "app_code": my_app_code,
            "useHTTPS": true
        }
    };
    
    var platform = new H.service.Platform(M.Init);
    
    var defaultLayers = platform.createDefaultLayers();
    // Set center of the map
    var mapcenter= {lat:52.51607, lng:13.37698};
    
    //Step 2: initialize a map - this map is centered over Berlin
    var map = new H.Map(mapContainer,
        defaultLayers.normal.map,{
        center: mapcenter,
        zoom: 13
    });
    //Step 3: make the map interactive
    // MapEvents enables the event system
    // Behavior implements default interactions for pan/zoom (also on mobile touch environments)
    var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
    
    // Create the default UI components
    var ui = H.ui.UI.createDefault(map, defaultLayers);
    
    var getCustomLocationService = platform.getCustomLocationService();
    //Display layer as a Tile 
    // create tile provider and layer that displays CLE layer
    var layer_provider = new mapsjs.service.extension.customLocation.TileProvider(getCustomLocationService, 
        {
        layerId: 'WAREHOUSES_DIST_3'
        }, 
        {
        resultType: mapsjs.service.extension.TileProvider.ResultType.MARKER 
        });
    var rest_LAYER = new mapsjs.map.layer.MarkerTileLayer(layer_provider);
        map.addLayer(rest_LAYER);

Note that the app_id and app_code used are the same as the ones associated with the uploaded layer. The layer name also has to be the same one as the uploaded layer name.

Modifying the custom location layer

If you need to add more geometries to this layer, you can do so with the call below.

https://cle.api.here.com/2/layers/modify.json?app_id={{app_id}}&app_code={{app_code}}&action=update&layer_id=WAREHOUSES_DIST_3

Similar to the POST request for uploading a layer, this request also requires the layer id and credentials as the previously uploaded layer. The post body is of the type form-data and the uploaded file is of the same format as the .wkt file used while uploading a layer. To change an entry in an existing layer partially, you need to know the geometry id of the entry you wish to change. You can get this id by logging on to the portal mentioned above or by listing the layer info. Once you have this information, you can make the following request to change details in the layer.

https://cle.api.here.com/2/layers/modify.json?app_id={{app_id}}&app_code={{app_code}}&action=update&layer_id=WAREHOUSES_DIST_3&geometry_id=35

The body will be same as above and the .wkt file will contain all the fields of the entry in the layer including the content to be changed. For deleting an entry in a layer, you will need the geometry id and running the following command with the body as the .wkt file containing all the fields in that entry will do the work.

https://cle.api.here.com/2/layers/modify.json?app_id={{app_id}}&app_code={{app_code}}&action=delete&layer_id=WAREHOUSES_DIST_3&geometry_id=38

What next?

In the next blog post, we will discuss how to use these layers to find places in your custom layer inside a given radius, in a bounding box and along a route. Meanwhile, happy coding!