Skip to content

Commit 10efe94

Browse files
fix(core): address globe zoom review feedback
1 parent c9a70ad commit 10efe94

7 files changed

Lines changed: 251 additions & 128 deletions

File tree

examples/get-started/pure-js/globe/app.js

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// SPDX-License-Identifier: MIT
33
// Copyright (c) vis.gl contributors
44

5-
/* global document, localStorage */
6-
75
import {Deck, _GlobeView as GlobeView} from '@deck.gl/core';
86
import {SolidPolygonLayer, GeoJsonLayer, ArcLayer} from '@deck.gl/layers';
97

@@ -19,27 +17,10 @@ const INITIAL_VIEW_STATE = {
1917
zoom: 0
2018
};
2119

22-
const ZOOM_AROUND_STORAGE_KEY = 'deckgl-example-globe-zoom-around';
23-
24-
function isZoomAroundMode(value) {
25-
return value === 'center' || value === 'pointer';
26-
}
27-
28-
function getInitialZoomAround() {
29-
try {
30-
const storedZoomAround = localStorage.getItem(ZOOM_AROUND_STORAGE_KEY);
31-
return isZoomAroundMode(storedZoomAround) ? storedZoomAround : 'center';
32-
} catch {
33-
return 'center';
34-
}
35-
}
36-
37-
let zoomAround = getInitialZoomAround();
38-
39-
const deckgl = new Deck({
20+
new Deck({
4021
views: new GlobeView(),
4122
initialViewState: INITIAL_VIEW_STATE,
42-
controller: {zoomAround},
23+
controller: true,
4324
layers: [
4425
// A GeoJSON polygon that covers the entire earth
4526
// See /docs/api-reference/globe-view.md#remarks
@@ -95,29 +76,3 @@ const deckgl = new Deck({
9576
})
9677
]
9778
});
98-
99-
function setZoomAround(nextZoomAround) {
100-
if (!isZoomAroundMode(nextZoomAround)) {
101-
return;
102-
}
103-
zoomAround = nextZoomAround;
104-
deckgl.setProps({controller: {zoomAround}});
105-
try {
106-
localStorage.setItem(ZOOM_AROUND_STORAGE_KEY, zoomAround);
107-
} catch {
108-
// Ignore storage failures in sandboxed examples.
109-
}
110-
syncZoomButtons();
111-
}
112-
113-
function syncZoomButtons() {
114-
for (const button of zoomButtons) {
115-
button.setAttribute('aria-pressed', String(button.dataset.zoomAround === zoomAround));
116-
}
117-
}
118-
119-
const zoomButtons = document.querySelectorAll('[data-zoom-around]');
120-
for (const button of zoomButtons) {
121-
button.addEventListener('click', () => setZoomAround(button.dataset.zoomAround));
122-
}
123-
syncZoomButtons();
Lines changed: 10 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,13 @@
11
<!doctype html>
22
<html lang="en">
3-
<head>
4-
<meta charset="utf-8" />
5-
<title>deck.gl Example</title>
6-
<style>
7-
body {
8-
margin: 0;
9-
width: 100vw;
10-
height: 100vh;
11-
overflow: hidden;
12-
background: #111;
13-
}
14-
.zoom-control {
15-
position: absolute;
16-
z-index: 1;
17-
top: 24px;
18-
right: 24px;
19-
padding: 12px;
20-
border: 1px solid rgba(255, 255, 255, 0.22);
21-
border-radius: 6px;
22-
background: rgba(8, 14, 24, 0.78);
23-
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.28);
24-
color: #fff;
25-
font-family: Helvetica, Arial, sans-serif;
26-
}
27-
.zoom-control-label {
28-
margin-bottom: 8px;
29-
color: rgba(255, 255, 255, 0.82);
30-
font-size: 12px;
31-
font-weight: 600;
32-
line-height: 1;
33-
}
34-
.zoom-button-group {
35-
display: flex;
36-
}
37-
.zoom-button-group button {
38-
min-width: 70px;
39-
padding: 8px 10px;
40-
border: 1px solid rgba(122, 136, 255, 0.64);
41-
background: rgba(12, 18, 34, 0.72);
42-
color: rgba(205, 213, 255, 0.9);
43-
cursor: pointer;
44-
font-size: 12px;
45-
font-weight: 700;
46-
line-height: 1;
47-
}
48-
.zoom-button-group button:first-child {
49-
border-radius: 4px 0 0 4px;
50-
}
51-
.zoom-button-group button:last-child {
52-
margin-left: -1px;
53-
border-radius: 0 4px 4px 0;
54-
}
55-
.zoom-button-group button[aria-pressed='true'] {
56-
background: #5262df;
57-
color: #fff;
58-
}
59-
</style>
60-
</head>
61-
<body>
62-
<div class="zoom-control">
63-
<div class="zoom-control-label">Zoom anchor</div>
64-
<div class="zoom-button-group" role="group" aria-label="Zoom anchor">
65-
<button type="button" data-zoom-around="center" aria-pressed="true">Center</button>
66-
<button type="button" data-zoom-around="pointer" aria-pressed="false">Pointer</button>
67-
</div>
68-
</div>
69-
</body>
70-
<script type="module" src="app.js"></script>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>deck.gl Example</title>
6+
<style>
7+
body {margin: 0; width: 100vw; height: 100vh; overflow: hidden;}
8+
</style>
9+
</head>
10+
<body>
11+
</body>
12+
<script type="module" src="app.js"></script>
7113
</html>

modules/core/src/controllers/globe-controller.ts

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {MapState, MapStateProps} from './map-controller';
99
import type {MapStateInternal} from './map-controller';
1010
import {mod} from '../utils/math-utils';
1111
import LinearInterpolator from '../transitions/linear-interpolator';
12+
import type Viewport from '../viewports/viewport';
1213
import GlobeViewport, {
1314
zoomAdjust,
1415
GLOBE_RADIUS,
@@ -154,7 +155,7 @@ class GlobeState extends MapState {
154155

155156
zoomStart({pos}: {pos: [number, number]}): GlobeState {
156157
const startZoomLngLat = this._shouldZoomAroundPointer()
157-
? this._unprojectOnGlobe(pos)
158+
? this._unprojectZoomAnchor(pos)
158159
: undefined;
159160

160161
return this._getUpdatedState({
@@ -184,17 +185,17 @@ class GlobeState extends MapState {
184185
}
185186

186187
if (!startZoomLngLat && !hasZoomStart) {
187-
startZoomLngLat = this._unprojectOnGlobe(startPos) || this._unprojectOnGlobe(pos);
188+
startZoomLngLat = this._unprojectZoomAnchor(startPos) || this._unprojectZoomAnchor(pos);
188189
}
189190

190191
if (!startZoomLngLat) {
191192
return this._getUpdatedState({zoom});
192193
}
193194

194-
const zoomedViewport = this.makeViewport({...this.getViewportProps(), zoom}) as GlobeViewport;
195+
const zoomedViewport = this.makeViewport({...this.getViewportProps(), zoom});
195196
return this._getUpdatedState({
196197
zoom,
197-
...zoomedViewport.panByGlobeAnchor(startZoomLngLat, pos)
198+
...this._panByZoomAnchor(zoomedViewport, startZoomLngLat, pos)
198199
});
199200
}
200201

@@ -300,20 +301,33 @@ class GlobeState extends MapState {
300301
return clamp(zoom, minZoom + zoomAdjustment, maxZoom + zoomAdjustment);
301302
}
302303

303-
private _unprojectOnGlobe(pos?: [number, number]): [number, number] | undefined {
304+
private _unprojectZoomAnchor(pos?: [number, number]): [number, number] | undefined {
304305
if (!pos) {
305306
return undefined;
306307
}
307308

308-
const viewport = this.makeViewport(this.getViewportProps()) as GlobeViewport;
309-
if (!viewport.isPointOnGlobe(pos, {maxDistanceRatio: GLOBE_ZOOM_ANCHOR_MAX_DISTANCE_RATIO})) {
309+
const viewport = this.makeViewport(this.getViewportProps());
310+
if (
311+
viewport instanceof GlobeViewport &&
312+
!viewport.isPointOnGlobe(pos, {maxDistanceRatio: GLOBE_ZOOM_ANCHOR_MAX_DISTANCE_RATIO})
313+
) {
310314
return undefined;
311315
}
312316

313317
const lngLat = viewport.unproject(pos);
314318
return [lngLat[0], lngLat[1]];
315319
}
316320

321+
private _panByZoomAnchor(
322+
viewport: Viewport,
323+
anchorLngLat: [number, number],
324+
pixel: [number, number]
325+
): Record<string, any> {
326+
return viewport instanceof GlobeViewport
327+
? viewport.panByGlobeAnchor(anchorLngLat, pixel)
328+
: viewport.panByPosition(anchorLngLat, pixel);
329+
}
330+
317331
private _shouldZoomAroundPointer(): boolean {
318332
return (this.getState() as GlobeStateInternal).zoomAround === 'pointer';
319333
}
@@ -337,6 +351,15 @@ export default class GlobeController extends Controller<MapState> {
337351
// Ring buffer tracking globe position during pan for inertia velocity
338352
private _panHistory: Array<{longitude: number; latitude: number; timestamp: number}> = [];
339353

354+
protected _getTransitionProps(opts?: any) {
355+
if (opts?.around && this.props.zoomAround !== 'pointer') {
356+
const centerZoomOpts = {...opts};
357+
delete centerZoomOpts.around;
358+
return super._getTransitionProps(centerZoomOpts);
359+
}
360+
return super._getTransitionProps(opts);
361+
}
362+
340363
protected _onPanStart(event: MjolnirGestureEvent): boolean {
341364
this._panHistory = [];
342365
return super._onPanStart(event);

modules/core/src/transitions/linear-interpolator.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ export default class LinearInterpolator extends TransitionInterpolator {
138138
propsInTransition,
139139
viewport.panByGlobeAnchor(endProps.aroundLngLat, anchorScreen)
140140
);
141+
} else if (endProps.aroundLngLat) {
142+
Object.assign(
143+
propsInTransition,
144+
viewport.panByPosition(endProps.aroundLngLat, anchorScreen)
145+
);
141146
} else if (endProps.aroundPosition) {
142147
Object.assign(
143148
propsInTransition,

0 commit comments

Comments
 (0)