DEV Community

Cover image for 3D Map, React.js and Typescript
Roberto B.
Roberto B.

Posted on • Updated on

3D Map, React.js and Typescript

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
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.

npx create-react-app map-here-ts --template typescript
cd map-here-ts
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Alt Text

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"
Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

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 ;
  • 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:

.map {
  height: 100vh;
  background: #f0e68c;
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

Run the project

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

npm run start
Enter fullscreen mode Exit fullscreen mode

Alt Text

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

Top comments (7)

Collapse
 
codingfer profile image
Carlos Fernando Rojas Barja

The maps 3D only function in Europe, do you know service for South America??) 😅

Collapse
 
robertobutti profile image
Roberto B.

Hi, it depends on the town, the buildings and the zoom level. For example, I'm testing now with Rio de Janeiro for you, and I see that buldings are extruded.

Collapse
 
codingfer profile image
Carlos Fernando Rojas Barja

I live in Bolivia and here the map it´s only 2d
I suppose my country was no trated :c

Thread Thread
 
codingfer profile image
Carlos Fernando Rojas Barja
Thread Thread
 
robertobutti profile image
Roberto B.

Please, provide me the lat and lng of that place.

Thread Thread
 
robertobutti profile image
Roberto B.

I see:

  {
    lat: -17.39237,
    lng: -66.14566,
    name: "Universidad Mayor de San Simón"
  },
Thread Thread
 
codingfer profile image
Carlos Fernando Rojas Barja

It is the last one, I tried many suppliers and librarys, and nothing have map 3D of Bolivia :C