• Stars
    star
    134
  • Rank 261,363 (Top 6 %)
  • Language
    TypeScript
  • License
    Apache License 2.0
  • Created almost 3 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Add ThreeJS objects to Google Maps.

Google Maps ThreeJS Overlay View and Utilities

npm Build Release codecov GitHub contributors semantic-release Discord

Description

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.

Install

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:

<script src="https://unpkg.com/three/build/three.min.js"></script>
<script src="https://unpkg.com/@googlemaps/three/dist/index.min.js"></script>

When adding via unpkg, the package can be accessed as google.maps.plugins.three. A version can be specified by using https://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):

<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three/build/three.module.js",
      "@googlemaps/three": "https://unpkg.com/@googlemaps/three/dist/index.esm.js"
    }
  }
</script>

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.

<script type="module">
  import * as THREE from "three";
  import { ThreeJSOverlayView } from "@googlemaps/three";

  // ...
</script>

Documentation

Checkout the reference documentation.

Coordinates, Projection and Anchor-Points

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):

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:

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);

Raycasting and Interactions

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:

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:

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.

Example

The following example provides a skeleton for adding objects to the map with this library.

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.

threejs box on map

Demos

View the package in action:

More Repositories

1

google-maps-services-python

Python client library for Google Maps API Web Services
Python
4,327
star
2

android-maps-utils

Maps SDK for Android Utility Library
Java
3,519
star
3

google-maps-services-js

Node.js client library for Google Maps API Web Services
TypeScript
2,807
star
4

android-samples

Samples demonstrating how to use Maps SDK for Android
Java
2,351
star
5

google-maps-services-java

Java client library for Google Maps API Web Services
Java
1,675
star
6

v3-utility-library

Utility libraries for Google Maps JavaScript API v3
JavaScript
1,094
star
7

android-maps-compose

Jetpack Compose composables for the Maps SDK for Android
Kotlin
1,055
star
8

js-samples

Samples for the Google Maps JavaScript v3 API
TypeScript
701
star
9

google-maps-ios-utils

Google Maps SDK for iOS Utility Library
Objective-C
699
star
10

google-maps-services-go

Go client library for Google Maps API Web Services
Go
695
star
11

transport-tracker

Applications for tracking moving assets on a live map
JavaScript
565
star
12

react-wrapper

Wrap React components with this libary to load the Google Maps JavaScript API.
TypeScript
344
star
13

android-maps-ktx

Kotlin extensions (KTX) for the Maps SDK and Utility Library for Android
Kotlin
314
star
14

js-api-loader

Load the Google Maps JavaScript API script dynamically.
TypeScript
306
star
15

maps-sdk-for-ios-samples

Samples for the Google Maps and Places SDKs for iOS
Objective-C
259
star
16

android-places-demos

Google Places SDK Demos for Android
Java
167
star
17

js-markerclusterer

Create and manage clusters for large amounts of markers
TypeScript
166
star
18

roads-api-samples

Sample Android app demonstrating usage of the GMP Roads API
Java
116
star
19

openapi-specification

OpenAPI specification for Google Maps Platform API
TypeScript
99
star
20

js-markerclustererplus

TypeScript
97
star
21

android-places-ktx

Kotlin extensions (KTX) for the Places SDK for Android
Kotlin
96
star
22

extended-component-library

A set of Web Components from Google Maps Platform
TypeScript
95
star
23

property-finder

A turnkey solution for a fictitious real estate business
Python
75
star
24

js-markerwithlabel

Google Maps Marker with Label
TypeScript
70
star
25

deck.gl-demos

Examples showing how to use Google Maps Platform with deck.gl
JavaScript
69
star
26

last-mile-fleet-solution-samples

Java
54
star
27

js-polyline-codec

Polyline encoding and decoding.
TypeScript
51
star
28

url-signing

Samples in various languages that demonstrate how to sign URLs for Google Maps Platform Web Services APIs
HTML
42
star
29

nyc-subway-station-locator

NYC Subway Station Locator Solution
Go
31
star
30

js-jest-mocks

Jest mocks for Google Maps Platform
TypeScript
29
star
31

ios-maps-sdk

Google Maps SDK for iOS
Swift
28
star
32

python-high-volume-address-validation-library

Python
27
star
33

android-on-demand-rides-deliveries-samples

Kotlin
22
star
34

android-maps-rx

RxJava bindings for the Maps and Places SDKs for Android
Kotlin
21
star
35

gaming-services-samples

Example games that use Google Maps Platform gaming services.
C#
20
star
36

js-map-loader

A simple JavaScript/TypeScript utility for adding a Google Map to webpages programmatically.
TypeScript
18
star
37

js-typescript-guards

TypeScript guards for the Google Maps JavaScript API.
TypeScript
17
star
38

ios-on-demand-rides-deliveries-samples

Objective-C
17
star
39

fleet-debugger

JavaScript
16
star
40

js-markermanager

Marker manager is an interface between the map and the user, designed to manage adding and removing many points when the viewport changes.
TypeScript
15
star
41

on-demand-rides-deliveries-samples

14
star
42

ios-combine

Combine extensions for Maps and Places SDKs for iOS
Swift
14
star
43

js-ogc

Add a WmsMapType to Google Maps
TypeScript
12
star
44

java-on-demand-rides-deliveries-stub-provider

Java
11
star
45

android-v3-migration

Migration tool for V3 BETA Maps SDK to Google Play services Maps SDK
Kotlin
11
star
46

.github

Default configurations for googlemaps repositories
11
star
47

java-fleetengine-auth

Java
10
star
48

react-on-demand-rides-deliveries-samples

TypeScript
10
star
49

react-last-mile-fleet-solution-samples

TypeScript
10
star
50

react-routing-playground

JavaScript
9
star
51

go-routespreferred

Go idiomatic client for Google Maps Platform Routes API.
8
star
52

js-types

Automatically generated types for the Google Maps Platform JavaScript API
Starlark
7
star
53

angular-on-demand-rides-deliveries-samples

TypeScript
6
star
54

js-url-signature

Sign a URL for Google Maps Platform requests.
TypeScript
6
star
55

semantic-release-config

Shareable configuration for semantic release.
JavaScript
5
star
56

gmp-firebase-extensions

TypeScript
5
star
57

codelab-maps-platform-101-swift

Companion code for the Add a map to your iOS app (Swift) codelab
Swift
5
star
58

fleet-events-reference-solution

Java
5
star
59

js-adv-markers-utils

TypeScript
4
star
60

codelab-places-101-android-kotlin

Companion code for the Get started with the Places SDK for Android (Kotlin) codelab
Kotlin
4
star
61

playablelocations-proxy

A proxy implementation for the Playable Locations API.
Go
4
star
62

eslint-plugin-googlemaps

ESLint rules for Google Maps Platform.
TypeScript
4
star
63

js-region-lookup

TypeScript
4
star
64

ios-places-sdk

Swift
4
star
65

js-github-policy-bot

Enforce polices for repositories in the googlemaps organization.
TypeScript
2
star
66

go-routespreferred-samples

Routes Preferred Samples in Go
Go
2
star
67

googlemaps.github.io

A page listing Google maintained GMP libraries as well as external ones.
HTML
2
star
68

java-routespreferred-samples

Samples for Routes Preferred
Java
2
star
69

eslint-config-googlemaps

Shareable ESLint style configuration for Google Maps repositories.
TypeScript
1
star
70

ios-consumer-sdk

Swift
1
star
71

ios-navigation-sdk

Swift
1
star
72

java-routespreferred

Java idiomatic client for Google Maps Platform Routes Preferred API.
Java
1
star
73

.allstar

1
star