3D Map, React.js and Typescript
Tags: react, typescript, 3dmap, tutorial
Published: 2019-12-24 15:51:23

I was playing with 3D Map, React.js and Typescript, so I decided to mix all together, write a small side project and write some notes about my experiment about that.
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/yaf84m2s9ivx5sadmh7u.png)
The goal is show you some steps in order to build a 3D Map with React and Typescript.
My suggestion is to use "Create React App", an environment that will help you to start quickly with the creation of the React single page application. 
The steps:
- 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](https://reactjs.org/docs/create-a-new-react-app.html#create-react-app).
```sh
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. 

```sh
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](https://developer.here.com/projects).

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/11v7ycarb0ehl43ndbws.png)

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:

```js
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
- 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:

```css
.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:

```html
<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:

```js
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:
```sh
npm run start
```

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/583gbtwxa2qn57kpncay.png)

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