Search code examples
here-api

How to use a Personalized Map Style with Here API


I would like to customize the map style and found the Map Style Editor.

Therefore, I would like to build on the normal.day.grey map scheme and just tweak a few styles. The Map Style Editor provides the normal.day scheme as yaml.

  1. Is there a possibility to access the normal.day.grey scheme as yaml so I can load it into the editor and start from there?
  2. What would I do with the result? As far as I understand from the docs there is a predefined set of schemes and styles which can be combinated together. How would I use my custom style in there?

Solution

  • Please distinguish between vector map tiles and raster

    In the documentation is described about raster Map Tile API - this is prerendered images (with some style) of map. You can't combine them in map view. Except only if some map image tile are partially transparent e.g. 'truck only' or 'traffic flow'. Then you can add two or more layers on the map.

    Vector tiles (https://developer.here.com/documentation/vector-tiles-api/dev_guide/index.html):

    Yes you can customize the vector map style utilize the Map Style Editor

    vector style 'normal.day.grey' doesn't exist but you can start with this example on https://demo.support.here.com/examples/v3.1/changing_the_map_style - select there 'Reduced day' and download it.

    In this example you can find dark style: https://jsfiddle.net/zmeatyxv/1/

    Also you can mix a raster tiles and vector tiles adding layers in JS API:

    http://jsfiddle.net/uycv9m8x/ - terrain map at the bottom and vector at the top, see code below:

    /**
     * The function add the "change" event listener to the map's style
     * and modifies colors of the map features within that listener.
     * @param  {H.Map} map      A HERE Map instance within the application
     */
    function changeFeatureStyle(map){
      // get the vector provider from the vector layer
      var provider = map.getLayers().get(1).getProvider(); //get provider from vector layer
    
      // get the style object for the vector layer
      var vStyle = provider.getStyle();
    
      var changeListener = (evt) => {
        if (vStyle.getState() === H.map.Style.State.READY) {
          vStyle.removeEventListener('change', changeListener);
    
          // query the sub-section of the style configuration
          // the call removes the subsection from the original configuration
          var vConfig = vStyle.extractConfig([
                                'earth',
                       'landuse.wood',
                       'landuse.forest',
                       'landuse.park',
                       'landuse.builtup',
                       'landuse.national_park',
                       'landuse.nature_reserve',
                       'landuse.green-areas',
                       'landuse.other',
                       'water.small_water',
                       'water.deep_water',
                       'water.river'
                    ]);
        }
      };
    
      vStyle.addEventListener('change', changeListener);
    }
    
    /**
     * Boilerplate map initialization code starts below:
     */
    
    //Step 1: initialize communication with the platform
    // In your own code, replace variable window.apikey with your own apikey
    
    var platform = new H.service.Platform({
      apikey: window.apikey
    });
    var defaultLayers = platform.createDefaultLayers();
    
    //Step 2: initialize a map
    var map = new H.Map(document.getElementById('map'),
      defaultLayers.raster.terrain.xbase/*set terain xbase as base layer*/, {
      center: {lat: 47.60586, lng: 14.27161},
      zoom: 9,
      pixelRatio: window.devicePixelRatio || 1
    });
    map.addLayer(defaultLayers.vector.normal.map);//add vector layer on the top
    // add a resize listener to make sure that the map occupies the whole container
    window.addEventListener('resize', () => map.getViewPort().resize());
    
    //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);
    
    // Now use the map as required...
    changeFeatureStyle(map);
    

    http://jsfiddle.net/80jtLv16/1/ - raster mobile labels at the bottom and vector tile at the top, see code below:

    function setStyle(map){
      // get the vector provider from the vector layer
      var provider = map.getLayers().get(1).getProvider(); //get provider from vector layer
      
      // Create the style object from the YAML configuration.
      // First argument is the style path and the second is the base URL to use for
      // resolving relative URLs in the style like textures, fonts.
      // all referenced resources relative to the base path https://js.api.here.com/v3/3.1/styles/omv.
      var style = new H.map.Style('https://heremaps.github.io/maps-api-for-javascript-examples/change-style-at-load/data/dark.yaml',
        'https://js.api.here.com/v3/3.1/styles/omv/');
      // set the style on the existing layer
      provider.setStyle(style);
    }
    
    
    
    /**
     * The function add the "change" event listener to the map's style
     * and modifies colors of the map features within that listener.
     * @param  {H.Map} map      A HERE Map instance within the application
     */
    function changeFeatureStyle(map){
      // get the vector provider from the vector layer
      var provider = map.getLayers().get(1).getProvider(); //get provider from vector layer
    
      // get the style object for the vector layer
      var vStyle = provider.getStyle();
    
      var changeListener = (evt) => {
        if (vStyle.getState() === H.map.Style.State.READY) {
          vStyle.removeEventListener('change', changeListener);
    
          // query the sub-section of the style configuration
          // the call removes the subsection from the original configuration
          var vConfig = vStyle.extractConfig([
                                'earth',
                      'continent_label',
                      'road_labels',
                      'places',
                      'buildings.address-labels',
                      'roads.shields',
                       //'landuse.wood',
                       //'landuse.forest',
                       //'landuse.park',
                       'landuse.builtup',
                       'landuse.national_park',
                       'landuse.nature_reserve',
                       'landuse.green-areas',
                       'landuse.other',
                       'water.small_water',
                       'water.deep_water',
                       'water.river'
                    ]);
        }
      };
    
      vStyle.addEventListener('change', changeListener);
    }
    
    /**
     * Boilerplate map initialization code starts below:
     */
    
    //Step 1: initialize communication with the platform
    // In your own code, replace variable window.apikey with your own apikey
    
    var platform = new H.service.Platform({
      apikey: window.apikey
    });
    var defaultLayers = platform.createDefaultLayers();
    var mTileServ = platform.getMapTileService({'type': 'base'});
    console.log("mTileServ:", mTileServ);
    var mobileLayer = mTileServ.createTileLayer('labeltile', 'normal.day.mobile', 512, 'png8', {lg: 'eng', lg2: 'eng'});
    
    //Step 2: initialize a map
    var map = new H.Map(document.getElementById('map'),
      mobileLayer/*set mobile layer as base layer*/, {
      center: {lat: 47.60586, lng: 14.27161},
      zoom: 9,
      pixelRatio: window.devicePixelRatio || 1
    });
    map.addLayer(defaultLayers.vector.normal.map);//add vector layer on the top
    map.getLayers().add(mobileLayer); //set base layer on top - it depends what you want to achieve
    //map.getLayers().add(defaultLayers.vector.normal.map); //here example how to reshuffle the layers
    
    // add a resize listener to make sure that the map occupies the whole container
    window.addEventListener('resize', () => map.getViewPort().resize());
    
    //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);
    
    // Now use the map as required...
    setStyle(map);
    changeFeatureStyle(map);