You will learn how a basic Vector Map with React is implemented. We will display a beautiful vector map with minimal configuration effort. Tutorial illustrates the use of the PTV Developer Vector Maps API.
Prerequisites
- Basic knowledge of JavaScript, React and npm.
- Helpful: Basic knowledge of (React) Mapbox GL JS.
Getting started
- Read up on the PTV Developer API Documentation. Pages useful for this tutorial:
- Request an API key:
- Register and login at myptv.com
- Activate PTV Developer
- Create your API key
- Install Node.js and npm
Setting up a React App with CRA
We'll use the official create-react-app (CRA) template as a starting point. Open a terminal at the target location of your project and run the command
npx create-react-app ptv-vector-map-react-app
If this does not work, e.g. because your npm version is older than 5.2.0
, you can alternatively run
npm i -g create-react-app
create-react-app ptv-vector-map-react-app
This will create the basic structure of a runnable React App with the name ptv-vector-map-react-app. You can switch into the project folder and run the npm start
script to run the app. For now, it will show a rotating React icon.
Writing a Vector Map Component
In this tutorial, we'll use React MapGL to render the vector map. Install the npm package with this command:
npm i react-map-gl@5
We'll use version 5
of the package because newer versions use Mapbox GL JS v2, requiring a Mapbox access token.
In the /src
folder, create a JavaScript file called VectorMap.js. Our vector map component may look like this:
// VectorMap.js
import { useCallback } from "react";
import "mapbox-gl/dist/mapbox-gl.css";
import ReactMapGL from "react-map-gl";
// use the standard map style provided by PTV
const MAP_STYLE_URL = "https://vectormaps-resources.myptv.com/styles/latest/standard.json";
export const VectorMap = ({ apiKey, ...props }) => {
const transformRequest = useCallback(
(url, resourceType) => (
{ url: url, headers: resourceType === "Tile" ? { ApiKey: " " + apiKey } : {} }),
[apiKey]
);
return <ReactMapGL
height="100%"
width="100%"
mapStyle={MAP_STYLE_URL}
transformRequest={transformRequest}
/>;
};
The VectorMap
component wraps the ReactMapGL
component and sets the MAP_STYLE_URL
provided by PTV (Read more on styling the map in the concept). Also, it appends the API key passed to VectorMap
to the tile requests via transformRequest
.
Let's see what this looks like! Replace the contents of the App.js file with this to use the component:
// App.js
import { VectorMap } from "./VectorMap";
// Please enter your API key here
const API_KEY = "YOUR_API_KEY";
const wrapperStyle = {
position: "absolute",
gridArea: "map",
height: "100%",
width: "100%",
zIndex: 0
};
const App = () => (
<div style={wrapperStyle} >
<VectorMap apiKey={API_KEY}/>
</div>
);
export default App;
Paste your API key in the designated variable. In a productive app, never hard-code or check-in your API key! You should now see the PTV Vector Map.
Make it interactive
Ok, we see a map, but we can neither zoom nor pan! That's because we are not yet handling the viewport
.
Let's adapt our component:
// VectorMap.js
export const VectorMap = ({ apiKey, ...props }) => {
const [viewport, setViewport] = useState(props.viewport);
// const transformRequest = ...
return <ReactMapGL
// other props
{...viewport}
onViewportChange={setViewport}
/>;
};
By keeping the viewport
in our component's state, we now can scroll and pan in the map.
Set initial viewport
Most of the time, we would not want the map to initialize on the minimal zoom level (the "world map"), but on some specific position, right? This implementation already sets a viewport
you pass to the VectorMap
as the initial state passed to the map. Let's set an initial viewport in App.js:
// App.js
// Initializes to Karlsruhe
export const initViewport = {
longitude: 8.4055677,
latitude: 49.0070036,
zoom: 10,
pitch: 0,
bearing: 0,
};
const App = () => (
<div style={wrapperStyle}>
<VectorMap apiKey={API_KEY} viewport={initViewport}/>
</div>
);
And just like that, we initialize our map to Karlsruhe, where PTV Headquarters are located.
Adding controls
Now you can go and extend the map component to match your needs. For instance, let's add a NavigationControl from Mapbox to the top-right corner of our map:
// VectorMap.js
const navControlStyle = {
right: 10,
top: 10
};
export const VectorMap = ({ apiKey, ...props }) => {
return <ReactMapGL
// map props
>
<NavigationControl style={navControlStyle} />
</ReactMapGL>;
};
Now it's your turn! Extend and integrate the PTV Vector Map in your React projects.