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.
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
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 ;
- 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;
}
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.
Top comments (8)
The maps 3D only function in Europe, do you know service for South America??) ๐
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.
I live in Bolivia and here the map itยดs only 2d
I suppose my country was no trated :c
thepracticaldev.s3.amazonaws.com/i...
Please, provide me the lat and lng of that place.
I see:
It is the last one, I tried many suppliers and librarys, and nothing have map 3D of Bolivia :C
Followed all the steps but map is not appearing, generates below error
Script error.
at handleError (localhost:3000/static/js/bundle.js...)