Using the HERE Maps JavaScript API to implement custom styles from a JSON file

TLDR: How can I change the map style using a .json file from HERE maps editor?

After creating a "custom" style in the new HERE map style editor and exporting it as a single .json file, I encountered difficulties applying this styling due to lack of clear information in the introduction docs.

#1 Setting up the map

const defaultLayers = this.platform.createDefaultLayers();
const map = new H.Map(document.getElementById('map'), defaultLayers.vector.normal.map, {
      zoom: 10,
      center: { lat: 0, lng: 0 }
    });
new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
H.ui.UI.createDefault(map, defaultLayers, "de-DE");

#2.1 Attempting to apply the style with default rendering engine

Change style at load

const provider = map.getBaseLayer()?.getProvider();
const style = new H.map.Style(require('pathToMyStyle.json'))
provider?.setStyleInternal(style);

The method provider.setStyle(); does not exist as mentioned in the documentation. This is because it requires both an URL and a .yaml file which are not provided by the HERE editor. So...

#2.2 Trying to apply the style with HARP rendering engine

Change HARP style at load

const engineType = H.Map.EngineType["HARP"];
const style = new H.map.render.harp.Style(require('pathToMyStyle.json'));
const vectorLayer = this.platform
      .getOMVService()
      .createLayer(style, { engineType });

const map = new H.Map(document.getElementById('map'), vectorLayer, {
  engineType,
  zoom: 10,
  center: { lat: 0, lng: 0 }
});
//... continues from #1 setup

Despite following the example, this approach resulted in an error:

InvalidArgumentError: H.service.omv.Provider (Argument #1 [object Object])
.

Answer №1

Going with #2.2 seems to be the right choice, and I've had success testing it out. Are you having any issues getting the sample to work as expected? It could potentially be related to the file path.

Answer №2

#1 If you're using the default WebGL engine, your only option for a style editor is the HERE Map Style Editor

Check out this Example or try this: Road Labels Demo

#2 Using HARP? Try the HARP Style Editor

See an Example - Don't forget to include

<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-harp.js"></script>

in the head section of your HTML!

/**
 * Adds a polyline between Dublin, London, Paris and Berlin to the map
 *
 * @param  {H.Map} map      A HERE Map instance within the application
 */
function addPolylineToMap(map) {
  var lineString = new H.geo.LineString();

  lineString.pushPoint({lat: 58.906905, lng: 6.054719});
  lineString.pushPoint({lat:51.026163, lng:1.590833});
  lineString.pushPoint({lat:49.376177, lng:-5.16166});
  lineString.pushPoint({lat:25.767796, lng:-160.836078});
  lineString.pushPoint({lat:7.068211, lng:157.826714});

  map.addObject(new H.map.Polyline(
    lineString, { style: { lineWidth: 4 }}
  ));
}

/**
 * Boilerplate map initialization code starts below:
 */

//Step 1: initialize communication with the platform
// Replace window.apikey with your own apikey in your code
var platform = new H.service.Platform({
  apikey: window.apikey
});

var defaultLayers = platform.createDefaultLayers();
var engineType = H.Map.EngineType['HARP'];

// Create a layer with the exported style configuration from the HERE Style Editor
var style = new H.map.render.harp.Style('https://alexisad.github.io/vector-styles/harp/normal-day.json');

// Create a layer with the style object
var vectorLayer = platform.getOMVService().createLayer(style, { engineType });

//Step 2: initialize a map centered over Europe
var map = new H.Map(document.getElementById('map'),
  vectorLayer,{
  engineType: engineType,
  center: {lat:52, lng:5},
  zoom: 5,
  pixelRatio: window.devicePixelRatio || 1
});

window.addEventListener('resize', () => map.getViewPort().resize());

var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
var ui = H.ui.UI.createDefault(map, defaultLayers);

ui.removeControl("mapsettings");
var ms = new H.ui.MapSettingsControl( {
    baseLayers : [ { 
      label:"normal",layer:defaultLayers.raster.normal.map
    },{
      label:"satellite",layer:defaultLayers.raster.satellite.map
    }, {
      label:"terrain",layer:defaultLayers.raster.terrain.map
    }
    ],
  layers : [{
        label: "layer.traffic", layer: defaultLayers.vector.normal.traffic
    },
    {
        label: "layer.incidents", layer: defaultLayers.vector.normal.trafficincidents
    }
]
  });
ui.addControl("customized",ms);

addPolylineToMap(map);

Answer №3

When faced with this issue, here is the approach that helped me solve it. I tackled it using React and Typescript.

The bundle including the harp engine contains all the components found in the default bundle.

I've experimented with loading the style from a local file, but it also works when loaded from a URL.

  1. Importing the bundled Harp engine directly from the package (Referenced in Map.js at the beginning)
  2. Crafting a custom type definition for the harp bundle
  3. Ensuring the harp dependency is added in index.html

Map.js

import H from "@here/maps-api-for-javascript/bin/mapsjs.bundle.harp" // Crucial
import jsonStyle from "./assets/map_style.json"

const engineType = H.Map.EngineType.HARP
const style = new H.map.render.harp.Style(jsonStyle)
const vectorLayer = platform.getOMVService().createLayer(style, { engineType })
const layers: any = platform.createDefaultLayers({
  engineType: engineType
})

const hereMap: H.Map = new H.Map(
  mapRef.current,
  vectorLayer,
  {
    zoom: zoom,
    center: { 0, 0 },
    engineType: engineType
  }
)

Custom.d.ts

declare module "@here/maps-api-for-javascript/bin/mapsjs.bundle.harp" {
  export = H
}

index.html

...
<script src="https://js.api.here.com/v3/3.1/mapsjs-harp.js" type="text/javascript"></script>
...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Definition in Typescript: The term "value is" refers to a function that takes in any number of arguments of

export function isFunction(value: any): value is (...args: any[]) => any { return typeof value === 'function'; } What is the reason behind using value is (...args: any[]) => any instead of boolean ? ...

Unable to employ the inequality operator while querying a collection in AngularFire

I'm facing a challenge with pulling a collection from Firebase that is not linked to the user. While I've managed to query the user's collection successfully, I am struggling to retrieve the collection that does not belong to the user using ...

brings fulfillment except for categories

The new satisfies operator in TypeScript 4.9 is incredibly useful for creating narrowly typed values that still align with broader definitions. type WideType = Record<string, number>; const narrowValues = { hello: number, world: number, } sa ...

Encountering an Object Type Unknown error while working with Typescript and React

I am currently working on building a chatbox in React using TypeScript and Firebase. Below is the code for my Room and Message components: function ChatRoom() { const messagesRef = firestore.collection('messages'); const query = messagesRef.o ...

Tips for maintaining tab state using Angular Material

In my Angular 8 application with Angular Material, I have implemented four tabs where each tab allows editing. However, when going back from the edit mode to the tabs, I want the last selected tab to remain selected. My approach so far is as follows: exp ...

TS7030: In Angular13, ensure that all code paths within the guard and canActivate methods return a value

Having trouble using guards for an unlogged user and constantly facing errors. Error: TS7030 - Not all code paths return a value. Below is my auth.guard.ts file: import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from &a ...

Docz: Utilizing Typescript definitions for props rendering beyond just interfaces

We are currently using Docz to document our type definitions. While it works well for interfaces, we've run into an issue where rendering anything other than interfaces as props in Docz components doesn't seem to display properly. I'm seeki ...

Navigate to a different page using Angular with a simple click

How can I implement a redirect from clicking on the "Firms" word to another component page in Angular? I have tried using routerLink="/", [routerLink]="['/']". I have imported Routes in the app.module. I have also attempted this approach: import ...

"I am looking to retrieve the properties of an object that belongs to the EChartsOption type in TypeScript when working with Angular and ECharts. How

Currently, I am exploring how to access a property of an EChartOptions object in Angular 16.0.2, which may be undefined as I am still new to TypeScript. List of npm packages: eapp/src$ npm list <a href="/cdn-cgi/l/email-protection" class="__cf_email__" ...

There has been an error of type TypeError, as the property 'replace' cannot be read from a null value

I encountered a TypeError message, even though my application seems to be functioning properly. "ERROR TypeError: Cannot read property 'replace' of null" I'm struggling to understand how to fix this issue. Can someone provide me ...

Comparing TypeScript and C++ in terms of defining class reference member variables

class B; class A { A(B b_) : b{b_} {} B &b; }; In C++, it is possible to have a reference member variable like 'b' in class A. Can the same be achieved in TypeScript? Alternatively, is there a specific method to accomplish this in ...

Troubleshooting a Custom Pipe Problem in Angular Material Drag and Drop

Currently, I am working on a project involving Angular Material Drag And Drop functionality. I have created a simplified example on StackBlitz which you can access through this link: here The project involves two lists - one containing pets and the other ...

What methods does TypeScript use to verify primitive types during runtime?

Is it true that Typescript removes any type or interface at compile time? If so, how is it possible to determine an object's primitive type using the typeof keyword? Are custom interfaces handled differently than primitive types? const a = "strin ...

Obtain the user's ID in string format from the clerk

I'm trying to retrieve the clerk ID to cross-reference with the backend. The issue is that the clerk is using a hook which isn't compatible with this function type. export const getServerSideProps = async ({ req }) => { const { isLoaded, is ...

Unexpected INTERNAL error encountered with Firebase's Cloud Function update

Currently, I am immersed in a project involving Vue.js 3, Typescript, and Firebase. However, while attempting to integrate new cloud functions, I came across an unexpected issue: Failed to load resource: the server responded with a status of 500 () Un ...

Acquire XML documentation for overloaded functions in Typescript

Is it possible for an overloaded function in a subclass to automatically inherit the XML documentation from its base class? When hovering over myFunc I want to be able to see the documentation from the base class when I hover over myFunc, rather than ju ...

Tips for showcasing an item with the chosen value in a dropdown menu

Below is the object I created: export default { data() { return { language: { "en": { welcomeMsg: "Welcome to New York City" }, "de": { ...

Prisma Remix is throwing a TypeError: "The function (0, import_prisma.createNote) is not defined as a function."

In my project, I wrote a function using the prisma client which is being called from the notes.tsx route in remix. export async function createNote(entity: { title: string, description: string }) { const note = await prisma.note.create({ data: ...

TypeScript version 3.7 has implemented a new feature where it will now display errors for each individual invalid prop instead of grouping them together as it

Scenario using TypeScript 3.5.3 https://i.stack.imgur.com/wykd6.png link to interactive playground - TS 3.5.3 demo running successfully Example with TypeScript 3.7.2 https://i.stack.imgur.com/BPckB.png link to demo - TS 3.7.2 demo not functioning correctl ...

Exploring the Power of Nuxt's asyncData Feature for Handling Multiple Requests

Within my application, there is a seller page showcasing products listed by the specific seller. Utilizing asyncData to retrieve all necessary data for this page has been beneficial in terms of SEO. asyncData ({params, app, error }) { return app.$axi ...