3D Map, React and Typescript

In the lasts weeks I worked with Maps and React, I learnt Typescript, and I took a look in the latest version of HERE Maps Javascript (3.1).

So, I decided to mix all together, write a small side project and write some notes about my experiment about mixing 3D map, React, Typescript.

3D Map, React, Typescript

The goal is to highlight some not obvious steps when you need to mix together all these things.
The steps will be:

  • Create a empty project with “Create React App” with Typescript enabled;
  • Creating a React Component for the Map;
  • Storing and using the API KEY for the Map;
  • Adding HERE Map JS and CSS to HTML;
  • Loading HERE Map in React Component;

Create an empty project

When I need to create some prototypes with ReactJS, I used to create the project with Create React App.


npx create-react-app map-here-ts --template typescript
cd map-here-ts

In order to use the Typescript you need to use template option.
This tool help you to create your project with all things. At the end of the execution of that command you will have your map-here-ts directory with package.json created and all node modules installed.

Create Map Component

In the src/ directory you need to create src/components/Map directory.
In src/components/Map, you need to create Map.tsx and Map.css file.


mkdir -p src/components/Map
touch src/components/Map/Map.tsx
touch src/components/Map/Map.css

Exactly, tsx is the right extension, you are using jsx with Typescript so tsx.

Store the API KEY in environment file

We will use the Map and Services provided by HERE Technologies. They provide a good free plan, very useful for developers that want to play with location services. In order to use the Map and the services you need to go to Developer portal, sign up, create a new project with a Freemium Plan and create a new API KEY. The URL to create a new project is: https://developer.here.com/projects.

Once you have your API KEY, you can create your .env.local file and create a new parameter:


REACT_APP_HERE_APIKEY="your-here-API Key"

Remember to replace “your-here-API Key” with your Api Key.

Implement Map Component

In the src/components/Map/Map.tsx component created before (as empty file) you can fill it as suggested:


import React, { Component } from "react";
// 001 - Importing CSS
import "./Map.css";
// 002 - Adding H declaration in Window
declare global {
interface Window {
H: any;
}
}
// 003 - Defining IProps Interface with debug prop
interface IProps {
debug?: boolean;
}
// 004 - Defining IState interface with all attributes we need
interface IState {
lat: number;
lng: number;
zoom: number;
}
// 005 - Defining component with Typescript Generic
class Map extends Component<IProps, IState> {
constructor(props: IProps) {
super(props);
// 006 - Setting some Default (Colosseum - Rome)
this.state = {
lat: 41.890251,
lng: 12.492373,
zoom: 18
};
}
// 007 - Implementing componentDidMount in order to load map once the component is mounted
componentDidMount() {
// 008 - Using H (a Class exported by HERE Map Javascript)
let H = (window as any).H;
// 009 - Instancing Map Platform
var platform = new H.service.Platform({
// 010 - Using the parameter defined in .env.local
apikey: process.env.REACT_APP_HERE_APIKEY
});
// 011 - Defining default Layers to apply on map
var defaultLayers = platform.createDefaultLayers();
// 012 - initialize the map
var map = new H.Map(
document.getElementById("map"),
defaultLayers.vector.normal.map,
{
// 013 - using state for lat, lng and zoom
center: { lat: this.state.lat, lng: this.state.lng },
zoom: this.state.zoom,
pixelRatio: window.devicePixelRatio || 1
}
);
// 014 - incline the Map
map.getViewModel().setLookAtData({ tilt: 45, heading: 0 });
// 015 - add a resize listener to make sure that the map occupies the whole container
window.addEventListener("resize", () => map.getViewPort().resize());
new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// 016 - Create the default UI components
H.ui.UI.createDefault(map, defaultLayers);
}
render() {
// 017 - implement render function
return (
<div className="mapWrapper">
<div className="map" id="map"></div>
</div>
);
}
}
export default Map;

Copy and paste of the previous code “will be your friend”, but let me walk through the code (take a look in the comments):

  • 001: import CSS file, where you can define the style;
  • 002: in order to use the H class exported by the HERE Maps Javascript in Typescript, we need to define an interface for Window that includes also H;
  • 003: thanks to Typescript we need to declare props interface with all props that we are going to use in the component. In this case a not mandatory (question mark) debug prop is defined with boolean type;
  • 004: thanks to Typescript we need to declare state interface with all attributes that we are going to use in the component. In this case: lat, lng, zoom as number;
  • 005: define the Component with Typescrpt Generic <IProps, IState>;
  • 006: set the default center and zoom as state;
  • 007: implement componentDidMount function in order to load map once the component is mounted;
  • 008: Use H (a Class exported by HERE Map Javascript);
  • 009: instance Map Platform
  • 010: use the api key previously stored in .env.local file;
  • 011: define default Layers to apply on map;
  • 012: initialize the map;
  • 013: use state for lat, lng and zoom, via this.state;
  • 014: let’s rotate the map via setLookAtData method and the tilt and heading attributes;
  • 015: add a resize listener to make sure that the map occupies the whole container;
  • 016: Create the default UI components.

Define some CSS for the Map container

In the Map.css CSS file (imported in the Map.tsx) set the height of the map container:


.map {
height: 100vh;
background: #f0e68c;
}

Include HERE Map Javascript

In the public/index.html file, include in the HEAD section the right CSS and JS files from HERE Map JS:

<link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>

Load Map Component

In the src/App.tsx replace the sample code created by Create React App with:

import React from 'react';
import Map from './components/Map/Map'
const App: React.FC = () => {
return (
<div className="App">
<Map></Map>
</div>
);
}
export default App;

Run the project

Back to the console in the directory of your new project execute:


npm run start

Thats all!
Feel free to drop any feedbacks in the comments.

I’m technophile. Vuejs and Laravel enthusiast! #vuejs #laravel. I love #coding