Skip to content

Commit

Permalink
[ts] GoogleMapsOverlay converted to Typescript. (visgl#6835)
Browse files Browse the repository at this point in the history
  • Loading branch information
zbigg authored Apr 22, 2022
1 parent e53c63b commit 3e7b633
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 33 deletions.
8 changes: 7 additions & 1 deletion modules/google-maps/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@
"build-bundle": "webpack --config ../../scripts/bundle.config.js",
"prepublishOnly": "npm run build-bundle && npm run build-bundle -- --env.dev"
},
"devDependencies": {
"@types/google.maps": "^3.48.6"
},
"peerDependencies": {
"@deck.gl/core": "^8.0.0"
"@deck.gl/core": "^8.0.0",
"@luma.gl/core": "^8.5.10",
"@luma.gl/constants": "^8.5.10",
"@math.gl/core": "^3.5.1"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getViewPropsFromOverlay,
getViewPropsFromCoordinateTransformer
} from './utils';
import {Deck} from '@deck.gl/core';

const HIDE_ALL_LAYERS = () => false;
const GL_STATE = {
Expand All @@ -17,27 +18,34 @@ const GL_STATE = {
blendEquation: GL.FUNC_ADD
};

// eslint-disable-next-line @typescript-eslint/no-empty-function
function noop() {}

const defaultProps = {
interleaved: true
};

// TODO: this should be alias to Deck Props.
export type GoogleMapsOverlayProps = Record<string, any>;
export default class GoogleMapsOverlay {
constructor(props) {
this.props = {};
this._map = null;
private props: GoogleMapsOverlayProps = {};
private _map: google.maps.Map | null = null;
private _deck: Deck | null = null;
private _overlay: google.maps.WebGLOverlayView | google.maps.OverlayView | null = null;

constructor(props: GoogleMapsOverlayProps) {
this.setProps({...defaultProps, ...props});
}

/* Public API */

setMap(map) {
/** Add/remove the overlay from a map. */
setMap(map: google.maps.Map | null): void {
if (map === this._map) {
return;
}
if (this._map) {
this._overlay.setMap(null);
this._overlay?.setMap(null);
this._map = null;
}
if (map) {
Expand All @@ -54,7 +62,10 @@ export default class GoogleMapsOverlay {
}
}

setProps(props) {
/**
* Update (partial) props.
*/
setProps(props: Partial<GoogleMapsOverlayProps>): void {
Object.assign(this.props, props);
if (this._deck) {
if (props.style) {
Expand All @@ -65,18 +76,22 @@ export default class GoogleMapsOverlay {
}
}

/** Equivalent of `deck.pickObject`. */
pickObject(params) {
return this._deck && this._deck.pickObject(params);
}

/** Equivalent of `deck.pickObjects`. */
pickMultipleObjects(params) {
return this._deck && this._deck.pickMultipleObjects(params);
}

/** Equivalent of `deck.pickMultipleObjects`. */
pickObjects(params) {
return this._deck && this._deck.pickObjects(params);
}

/** Remove the overlay and release all underlying resources. */
finalize() {
this.setMap(null);
if (this._deck) {
Expand All @@ -86,19 +101,19 @@ export default class GoogleMapsOverlay {
}

/* Private API */
_createOverlay(map) {
_createOverlay(map: google.maps.Map) {
const {interleaved} = this.props;
const {VECTOR, UNINITIALIZED} = google.maps.RenderingType;
const renderingType = map.getRenderingType();
if (renderingType === UNINITIALIZED) {
return;
}

const isVectorMap = renderingType === VECTOR && google.maps.WebGLOverlayView;
const OverlayView = isVectorMap ? google.maps.WebGLOverlayView : google.maps.OverlayView;
const overlay = new OverlayView();

// Lifecycle methods are different depending on map type
if (isVectorMap) {
if (overlay instanceof google.maps.WebGLOverlayView) {
if (interleaved) {
overlay.onAdd = noop;
overlay.onContextRestored = this._onContextRestored.bind(this);
Expand All @@ -120,12 +135,18 @@ export default class GoogleMapsOverlay {
}

_onAdd() {
// @ts-ignore (TS2345) map is defined at this stage
this._deck = createDeckInstance(this._map, this._overlay, this._deck, this.props);
}

_onContextRestored({gl}) {
if (!this._map || !this._overlay) {
return;
}
const _customRender = () => {
this._overlay.requestRedraw();
if (this._overlay) {
(this._overlay as google.maps.WebGLOverlayView).requestRedraw();
}
};
const deck = createDeckInstance(this._map, this._overlay, this._deck, {
gl,
Expand Down Expand Up @@ -155,13 +176,19 @@ export default class GoogleMapsOverlay {
}

_onRemove() {
// Clear deck canvas
this._deck.setProps({layerFilter: HIDE_ALL_LAYERS});
this._deck?.setProps({layerFilter: HIDE_ALL_LAYERS});
}

_onDrawRaster() {
if (!this._deck || !this._map) {
return;
}
const deck = this._deck;
const {width, height, left, top, ...rest} = getViewPropsFromOverlay(this._map, this._overlay);

const {width, height, left, top, ...rest} = getViewPropsFromOverlay(
this._map,
this._overlay as google.maps.OverlayView
);

const parentStyle = deck.canvas.parentElement.style;
parentStyle.left = `${left}px`;
Expand Down Expand Up @@ -220,12 +247,13 @@ export default class GoogleMapsOverlay {
}
}

_onDrawVectorOverlay({gl, transformer}) {
_onDrawVectorOverlay({transformer}) {
if (!this._deck || !this._map) {
return;
}

const deck = this._deck;

deck.setProps({
...getViewPropsFromCoordinateTransformer(this._map, transformer)
});
Expand Down
1 change: 1 addition & 0 deletions modules/google-maps/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export {default as GoogleMapsOverlay} from './google-maps-overlay';
export type {GoogleMapsOverlayProps} from './google-maps-overlay';
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ const MAX_LATITUDE = 85.05113;
* @param overlay (google.maps.OverlayView) - A maps Overlay instance
* @param [deck] (Deck) - a previously created instances
*/
export function createDeckInstance(map, overlay, deck, props) {
export function createDeckInstance(
map: google.maps.Map,
overlay: google.maps.OverlayView | google.maps.WebGLOverlayView,
deck: Deck | null | undefined,
props
): Deck {
if (deck) {
if (deck.props.userData._googleMap === map) {
return deck;
Expand All @@ -27,7 +32,7 @@ export function createDeckInstance(map, overlay, deck, props) {
mouseout: null
};

deck = new Deck({
const newDeck = new Deck({
...props,
style: props.interleaved ? null : {pointerEvents: 'none'},
parent: getContainer(overlay, props.style),
Expand All @@ -46,25 +51,28 @@ export function createDeckInstance(map, overlay, deck, props) {
// Register event listeners
for (const eventType in eventListeners) {
eventListeners[eventType] = map.addListener(eventType, evt =>
handleMouseEvent(deck, eventType, evt)
handleMouseEvent(newDeck, eventType, evt)
);
}

return deck;
return newDeck;
}

// Create a container that will host the deck canvas and tooltip
function getContainer(overlay, style) {
function getContainer(
overlay: google.maps.OverlayView | google.maps.WebGLOverlayView,
style?: Partial<CSSStyleDeclaration>
): HTMLElement {
const container = document.createElement('div');
container.style.position = 'absolute';
Object.assign(container.style, style);

// The DOM structure has a different structure depending on whether
// the Google map is rendered as vector or raster
if (overlay.getPanes) {
overlay.getPanes().overlayLayer.appendChild(container);
if ('getPanes' in overlay) {
overlay.getPanes()?.overlayLayer.appendChild(container);
} else {
overlay.getMap().getDiv().appendChild(container);
overlay.getMap()?.getDiv().appendChild(container);
}
return container;
}
Expand All @@ -73,7 +81,7 @@ function getContainer(overlay, style) {
* Safely remove a deck instance
* @param deck (Deck) - a previously created instances
*/
export function destroyDeckInstance(deck) {
export function destroyDeckInstance(deck: Deck) {
const {_eventListeners: eventListeners} = deck.props.userData;

// Unregister event listeners
Expand All @@ -90,7 +98,8 @@ export function destroyDeckInstance(deck) {
* @param map (google.maps.Map) - The parent Map instance
* @param overlay (google.maps.OverlayView) - A maps Overlay instance
*/
export function getViewPropsFromOverlay(map, overlay) {
// eslint-disable-next-line complexity
export function getViewPropsFromOverlay(map: google.maps.Map, overlay: google.maps.OverlayView) {
const {width, height} = getMapSize(map);

// Canvas position relative to draggable map's container depends on
Expand All @@ -99,6 +108,10 @@ export function getViewPropsFromOverlay(map, overlay) {
const projection = overlay.getProjection();

const bounds = map.getBounds();
if (!bounds) {
return {width, height, left: 0, top: 0};
}

const ne = bounds.getNorthEast();
const sw = bounds.getSouthWest();
const topRight = projection.fromLatLngToDivPixel(ne);
Expand All @@ -110,6 +123,11 @@ export function getViewPropsFromOverlay(map, overlay) {
const nwContainerPx = new google.maps.Point(0, 0);
const nw = projection.fromContainerPixelToLatLng(nwContainerPx);
const nwDivPx = projection.fromLatLngToDivPixel(nw);

if (!topRight || !bottomLeft || !nwDivPx) {
return {width, height, left: 0, top: 0};
}

let leftOffset = nwDivPx.x;
let topOffset = nwDivPx.y;

Expand All @@ -131,6 +149,7 @@ export function getViewPropsFromOverlay(map, overlay) {
latitude = latitude > 0 ? MAX_LATITUDE : -MAX_LATITUDE;
const center = new google.maps.LatLng(latitude, longitude);
const centerPx = projection.fromLatLngToContainerPixel(center);
// @ts-ignore (TS2531) Object is possibly 'null'
topOffset += centerPx.y - height / 2;
}

Expand All @@ -142,7 +161,8 @@ export function getViewPropsFromOverlay(map, overlay) {
// Maps sometimes returns undefined instead of 0
const heading = map.getHeading() || 0;

let zoom = map.getZoom() - 1;
let zoom = (map.getZoom() as number) - 1;

let scale;

if (bearing === 0) {
Expand Down Expand Up @@ -182,7 +202,10 @@ export function getViewPropsFromOverlay(map, overlay) {
* @param map (google.maps.Map) - The parent Map instance
* @param transformer (google.maps.CoordinateTransformer) - A CoordinateTransformer instance
*/
export function getViewPropsFromCoordinateTransformer(map, transformer) {
export function getViewPropsFromCoordinateTransformer(
map: google.maps.Map,
transformer: google.maps.CoordinateTransformer
) {
const {width, height} = getMapSize(map);
const {center, heading: bearing, tilt: pitch, zoom} = transformer.getCameraParams();

Expand Down Expand Up @@ -219,23 +242,30 @@ export function getViewPropsFromCoordinateTransformer(map, transformer) {
};
}

function getMapSize(map) {
function getMapSize(map: google.maps.Map): {width: number; height: number} {
// The map fills the container div unless it's in fullscreen mode
// at which point the first child of the container is promoted
const container = map.getDiv().firstChild;
const container = map.getDiv().firstChild as HTMLElement | null;
return {
// @ts-ignore (TS2531) Object is possibly 'null'
width: container.offsetWidth,
// @ts-ignore (TS2531) Object is possibly 'null'
height: container.offsetHeight
};
}

function pixelToLngLat(projection, x, y) {
function pixelToLngLat(
projection: google.maps.MapCanvasProjection,
x: number,
y: number
): [longitude: number, latitude: number] {
const point = new google.maps.Point(x, y);
const latLng = projection.fromContainerPixelToLatLng(point);
// @ts-ignore (TS2531) Object is possibly 'null'
return [latLng.lng(), latLng.lat()];
}

function getEventPixel(event, deck) {
function getEventPixel(event, deck: Deck): {x: number; y: number} {
if (event.pixel) {
return event.pixel;
}
Expand All @@ -249,8 +279,8 @@ function getEventPixel(event, deck) {
}

// Triggers picking on a mouse event
function handleMouseEvent(deck, type, event) {
const mockEvent = {
function handleMouseEvent(deck: Deck, type: string, event) {
const mockEvent: Record<string, any> = {
type,
offsetCenter: getEventPixel(event, deck),
srcEvent: event
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2952,6 +2952,11 @@
"@types/minimatch" "*"
"@types/node" "*"

"@types/google.maps@^3.48.6":
version "3.48.6"
resolved "https://registry.yarnpkg.com/@types/google.maps/-/google.maps-3.48.6.tgz#5125eb8257beb031b547acb5a690c24c3cabbf59"
integrity sha512-ZSx2J50Q9qyHhYVO4UdTvt5sHILzenSCiMbr7bjYNCMBkW/sagHMEDPI3Vjlr9i2tlMHIGoLk6DthWJnqFun/A==

"@types/hammerjs@^2.0.41":
version "2.0.41"
resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.41.tgz#f6ecf57d1b12d2befcce00e928a6a097c22980aa"
Expand Down

0 comments on commit 3e7b633

Please sign in to comment.