Skip to content

Commit 8a96a9c

Browse files
committed
feat: add map-3d-route example with 3D Map and custom route element
1 parent 55c7b97 commit 8a96a9c

12 files changed

Lines changed: 296 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/node_modules
22
/dist
3+
/.env*
34
/examples/**/package-lock.json
45
/examples/**/node_modules
56
/examples/**/dist

examples/map-3d-route/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# 3D Map Route Example
2+
3+
This is a standalone example demonstrating how to render a client-side 3D route using the modern `<gmp-route-3d>` custom element inside a client-side 3D Map (`<Map3D>`).
4+
5+
It showcases the seamless integration of the Maps JS API routes and maps3d libraries in React.
6+
7+
## Google Maps Platform API Key & Requirements
8+
9+
To run this example locally, you must satisfy the following platform requirements:
10+
11+
1. **Billing Enabled:** The Routes API and 3D Maps are premium Google Maps features and require a Google Cloud project with an **active billing account** linked to it.
12+
2. **Enabled APIs & Alpha Channel:** Ensure that both the **Routes API** and the **Maps JavaScript API** are explicitly enabled in your Google Cloud Console. **Note:** The `<gmp-route-3d>` custom element is currently only available in the **Alpha channel** (e.g., by setting `version="alpha"` on your `<APIProvider>`).
13+
3. **API Key Environment Variable:** The API key has to be provided via an environment variable `GOOGLE_MAPS_API_KEY`. This can be done by creating a file named `.env` in the example directory with the following content:
14+
15+
```shell title=".env"
16+
GOOGLE_MAPS_API_KEY="<YOUR API KEY HERE>"
17+
```
18+
19+
## WebGL2 Browser Compatibility
20+
21+
Photorealistic 3D Maps require WebGL2 support and hardware graphics acceleration. Please refer to the official **[Google Maps 3D Maps Browser Support Guide](https://developers.google.com/maps/documentation/javascript/3d-maps-support)** for detailed browser requirements and system compatibility guidelines.
22+
23+
*(Note: Virtual machine or remote desktop environments like Cloudtop do not support direct WebGL2 hardware rendering overlays by default. Please run the example locally on your physical host machine).*
24+
25+
## Development & How to Run
26+
27+
Go into the example directory:
28+
```shell
29+
cd examples/map-3d-route
30+
```
31+
32+
Install dependencies and start the development server:
33+
34+
```shell
35+
npm install
36+
npm run start-local
37+
```

examples/map-3d-route/index.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta
6+
name="viewport"
7+
content="width=device-width, initial-scale=1.0, user-scalable=no" />
8+
<title>Example: 3D Map Route</title>
9+
10+
<style>
11+
body {
12+
font-size: 16px;
13+
margin: 0;
14+
font-family: sans-serif;
15+
}
16+
#app {
17+
width: 100vw;
18+
height: 100vh;
19+
}
20+
</style>
21+
</head>
22+
<body>
23+
<div id="app"></div>
24+
<script type="module">
25+
import '@vis.gl/react-google-maps/examples.css';
26+
import '@vis.gl/react-google-maps/examples.js';
27+
import {renderToDom} from './src/app';
28+
29+
renderToDom(document.querySelector('#app'));
30+
</script>
31+
</body>
32+
</html>

examples/map-3d-route/package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"type": "module",
3+
"dependencies": {
4+
"@googlemaps/js-api-loader": "^2.0.2",
5+
"@vis.gl/react-google-maps": "latest",
6+
"fast-deep-equal": "^3.1.3",
7+
"react": "^19.0.0",
8+
"react-dom": "^19.0.0",
9+
"typescript": "^6.0.3",
10+
"vite": "^5.4.11"
11+
},
12+
"scripts": {
13+
"start": "vite",
14+
"start-local": "vite --config ../vite.config.local.js",
15+
"build-local": "vite build --config ../vite.config.local.js",
16+
"build": "vite build"
17+
}
18+
}

examples/map-3d-route/src/app.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/* Styles for 3D Map Route Example */
2+
html, body, #app {
3+
width: 100%;
4+
height: 100%;
5+
margin: 0;
6+
padding: 0;
7+
overflow: hidden;
8+
}

examples/map-3d-route/src/app.tsx

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React from 'react';
2+
import {createRoot} from 'react-dom/client';
3+
4+
import {
5+
APIProvider,
6+
Map3D,
7+
useMapsLibrary
8+
} from '@vis.gl/react-google-maps';
9+
import ControlPanel from './control-panel';
10+
11+
import './app.css';
12+
13+
const API_KEY =
14+
globalThis.GOOGLE_MAPS_API_KEY ?? (process.env.GOOGLE_MAPS_API_KEY as string);
15+
16+
// Tell TypeScript to allow the custom <gmp-route-3d> element
17+
declare global {
18+
namespace JSX {
19+
interface IntrinsicElements {
20+
'gmp-route-3d': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
21+
'autofits-camera'?: boolean;
22+
'departure-time'?: string;
23+
destination?: any;
24+
origin?: any;
25+
'routing-preference'?: string;
26+
'travel-mode'?: string;
27+
};
28+
}
29+
}
30+
}
31+
32+
const Map3DRouteExample = () => {
33+
// Make sure routes and maps3d libraries are loaded to register the custom elements
34+
useMapsLibrary('routes');
35+
useMapsLibrary('maps3d');
36+
37+
return (
38+
<>
39+
<Map3D
40+
defaultCenter={{lat: 43.67, lng: -79.40, altitude: 100}}
41+
defaultRange={12000}
42+
defaultHeading={0}
43+
defaultTilt={60}
44+
defaultRoll={0}
45+
defaultLabelsDisabled
46+
style={{width: '100vw', height: '100vh'}}>
47+
<gmp-route-3d
48+
origin={{lat: 43.65, lng: -79.38}}
49+
destination={{lat: 43.69, lng: -79.42}}
50+
travel-mode="DRIVING"
51+
/>
52+
</Map3D>
53+
</>
54+
);
55+
};
56+
57+
const App = () => {
58+
return (
59+
<APIProvider apiKey={API_KEY} version="alpha">
60+
<Map3DRouteExample />
61+
<ControlPanel />
62+
</APIProvider>
63+
);
64+
};
65+
export default App;
66+
67+
export function renderToDom(container: HTMLElement) {
68+
const root = createRoot(container);
69+
70+
root.render(
71+
<React.StrictMode>
72+
<App />
73+
</React.StrictMode>
74+
);
75+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.control-panel {
2+
position: absolute;
3+
top: 20px;
4+
right: 20px;
5+
background: rgba(255, 255, 255, 0.95);
6+
padding: 15px;
7+
border-radius: 8px;
8+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
9+
max-width: 300px;
10+
z-index: 10;
11+
font-family: sans-serif;
12+
}
13+
14+
.control-panel h3 {
15+
margin-top: 0;
16+
margin-bottom: 8px;
17+
font-size: 16px;
18+
}
19+
20+
.control-panel p {
21+
font-size: 12px;
22+
margin: 0 0 10px 0;
23+
color: #4a5568;
24+
}
25+
26+
.control-panel p.note {
27+
font-size: 11px;
28+
background: #edf2f7;
29+
padding: 6px;
30+
border-radius: 4px;
31+
}
32+
33+
.control-panel .links a {
34+
font-size: 12px;
35+
color: #3182ce;
36+
text-decoration: none;
37+
}
38+
39+
.control-panel p.note a {
40+
color: #3182ce;
41+
text-decoration: underline;
42+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import * as React from 'react';
2+
import './control-panel.css';
3+
4+
function ControlPanel() {
5+
return (
6+
<div className="control-panel">
7+
<h3>3D Map Routes</h3>
8+
<p>
9+
This example demonstrates how to render a client-side 3D route using the
10+
modern <code>&lt;gmp-route-3d&gt;</code> custom element inside a 3D Map.
11+
</p>
12+
13+
<p className={'note'}>
14+
<strong>Note:</strong> This utilizes custom 3D elements from the Maps JS API{' '}
15+
<a
16+
href="https://developers.google.com/maps/documentation/javascript/reference/routes-elements"
17+
target="_new">
18+
routes
19+
</a>{' '}
20+
and{' '}
21+
<a
22+
href="https://developers.google.com/maps/documentation/javascript/reference/3d-map"
23+
target="_new">
24+
maps3d
25+
</a>{' '}
26+
libraries.
27+
</p>
28+
29+
<div className="links">
30+
<a
31+
href="https://github.com/visgl/react-google-maps/tree/main/examples/map-3d-route"
32+
target="_new">
33+
View Code ↗
34+
</a>
35+
</div>
36+
</div>
37+
);
38+
}
39+
40+
export default React.memo(ControlPanel);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "../tsconfig.base.json",
3+
"compilerOptions": {
4+
"baseUrl": ".",
5+
"paths": {
6+
"website-examples/*": ["../*"]
7+
}
8+
}
9+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {defineConfig, loadEnv} from 'vite';
2+
import {resolve} from 'node:path';
3+
4+
export default defineConfig(({mode}) => {
5+
const {GOOGLE_MAPS_API_KEY = ''} = loadEnv(mode, resolve('../../'), '');
6+
7+
return {
8+
envDir: '../../',
9+
define: {
10+
'process.env.GOOGLE_MAPS_API_KEY': JSON.stringify(GOOGLE_MAPS_API_KEY)
11+
},
12+
resolve: {
13+
alias: {
14+
'@vis.gl/react-google-maps/examples.js': resolve(
15+
'../../website/static/scripts/examples.js'
16+
),
17+
'@vis.gl/react-google-maps/examples.css': resolve(
18+
'../../examples/examples.css'
19+
),
20+
'@vis.gl/react-google-maps': resolve('../../src/index.ts'),
21+
'@googlemaps/js-api-loader': resolve('./node_modules/@googlemaps/js-api-loader'),
22+
'fast-deep-equal': resolve('./node_modules/fast-deep-equal'),
23+
'react': resolve('./node_modules/react'),
24+
'react-dom': resolve('./node_modules/react-dom')
25+
}
26+
}
27+
};
28+
});

0 commit comments

Comments
 (0)