[](https://www.npmjs.com/package/@googlemaps/three)  
!Build
!Release

!GitHub contributors



Add three.js objects to Google Maps Platform JS. The
library provides a ThreeJSOverlayView class extending google.maps.WebGLOverlayView
and utility functions for converting geo-coordinates (latitude/longitude) to
vectors in the coordinate system used by three.js.
Available via npm as the package @googlemaps/three.
```
npm i @googlemaps/three
Alternatively you can load the package directly to the html document using
unpkg or other CDNs. In this case, make sure to load three.js before loading
this library:
``
When adding via unpkg, the package can be accessed as
google.maps.plugins.three. A version can be specified by usinghttps://unpkg.com/@googlemaps/three@VERSION/dist/....
The third option to use it is via ES-Module imports, similar to how the
three.js examples work. For this, you first need to specify an
importmap
(example using unpkg.com, but it works the same way with any other CDN
or self-hosted files):
`html`
In order to support browsers that don't yet implement importmap, you can
use the es-module-shims package.
After that, you can use three.js and the ThreeJSOverlayView like you would when
using a bundler.
`html`
Checkout the reference documentation.
The coordinate system within the three.js scene (so-called 'world
coordinates') is a right-handed coordinate system in z-up orientation.
The y-axis is pointing true north, and the x-axis is pointing east. The
units are meters. So the point new Vector3(0, 50, 10) is 10 meters
above ground and 50 meters east of the specified anchor point.
This anchor-point and orientation can be set in the constructor, or by using the
setAnchor() and setUpAxis()-methods (be aware that all object-positions in
your scene depend on the anchor-point and orientation, so they have to be
recomputed when either of them is changed):
`typescript
import { ThreeJSOverlayView } from "@googlemaps/three";
const overlay = new ThreeJSOverlayView({
anchor: { lat: 37.7793, lng: -122.4192, altitude: 0 },
upAxis: "Y",
});
overlay.setAnchor({ lat: 35.680432, lng: 139.769013, altitude: 0 });
overlay.setUpAxis("Z");
// can also be specified as Vector3:
overlay.setUpAxis(new Vector3(0, 0, 1));
`
> The default up-axis used in this library is the z-axis (+x is east
> and +y is north), which is different from the y-up orientation normally
> used in three.
All computations on the GPU related to the position use float32 numbers,
which limits the possible precision to about 7 decimal digits. Because
of this, we cannot use a global reference system and still have the
precision to show details in the meters to centimeters range.
This is where the anchor point is important. The anchor specifies the
geo-coordinates (lat/lng/altitude) where the origin of the world-space
coordinate system is, and you should always define it close to where the
objects are placed in the scene - unless of course you are only working with
large-scale (city-sized) objects distributed globally.
Another reason why setting the anchor close to the objects in the scene
is generally a good idea: In the mercator map-projection used in Google Maps,
the scaling of meters is only accurate in regions close to the equator. This
can be compensated for by applying a scale factor that depends on the
latitude of the anchor. This scale factor is factored into the coordinate
calculations in WebGlOverlayView based on the latitude of the anchor.
#### Converting coordinates
When you need more than just a single georeferenced object in your scene,
you need to compute the world-space position for those coordinates. The
ThreeJSOverlayView class provides a helper function for this conversion that
takes the current anchor and upAxis into account:
`typescript
const coordinates = { lat: 12.34, lng: 56.78 };
const position: Vector3 = overlay.latLngAltitudeToVector3(coordinates);
// alternative: pass the Vector3 to write the position
// to as the second parameter, so to set the position of a mesh:
overlay.latLngAltitudeToVector3(coordinates, mesh.position);
`
If you want to add interactivity to any three.js content, you typically
have to implement raycasting. We took care of that for you, and the
ThreeJSOverlayView provides a method overlay.raycast() for this. To make
use of it, you first have to keep track of mouse movements on the map:
`js
import { Vector2 } from "three";
// ...
const mapDiv = map.getDiv();
const mousePosition = new Vector2();
map.addListener("mousemove", (ev) => {
const { domEvent } = ev;
const { left, top, width, height } = mapDiv.getBoundingClientRect();
const x = domEvent.clientX - left;
const y = domEvent.clientY - top;
mousePosition.x = 2 * (x / width) - 1;
mousePosition.y = 1 - 2 * (y / height);
// since the actual raycasting is performed when the next frame is
// rendered, we have to make sure that it will be called for the next frame.
overlay.requestRedraw();
});
`
With the mouse position being always up to date, you can then use the
raycast() function in the onBeforeDraw callback.
In this example, we change the color of the object under the cursor:
`js
const DEFAULT_COLOR = 0xffffff;
const HIGHLIGHT_COLOR = 0xff0000;
let highlightedObject = null;
overlay.onBeforeDraw = () => {
const intersections = overlay.raycast(mousePosition);
if (highlightedObject) {
highlightedObject.material.color.setHex(DEFAULT_COLOR);
}
if (intersections.length === 0) return;
highlightedObject = intersections[0].object;
highlightedObject.material.color.setHex(HIGHLIGHT_COLOR);
};
`
The full examples can be found in ./examples/raycasting.ts.
The following example provides a skeleton for adding objects to the map with this library.
`js
import * as THREE from "three";
import { ThreeJSOverlayView, latLngToVector3 } from "@googlemaps/three";
// when loading via UMD, remove the imports and use this instead:
// const { ThreeJSOverlayView, latLngToVector3 } = google.maps.plugins.three;
const map = new google.maps.Map(document.getElementById("map"), mapOptions);
const overlay = new ThreeJSOverlayView({
map,
upAxis: "Y",
anchor: mapOptions.center,
});
// create a box mesh
const box = new THREE.Mesh(
new THREE.BoxGeometry(10, 50, 10),
new THREE.MeshMatcapMaterial()
);
// move the box up so the origin of the box is at the bottom
box.geometry.translateY(25);
// set position at center of map
box.position.copy(overlay.latLngAltitudeToVector3(mapOptions.center));
// add box mesh to the scene
overlay.scene.add(box);
// rotate the box using requestAnimationFrame
const animate = () => {
box.rotateY(THREE.MathUtils.degToRad(0.1));
requestAnimationFrame(animate);
};
// start animation loop
requestAnimationFrame(animate);
``
This adds a box to the map.

View the package in action: