@deck.gl/widgets 9.4.0-beta.3 → 9.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  var __defProp = Object.defineProperty;
3
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -15,7 +14,7 @@ var __copyProps = (to, from, except, desc) => {
15
14
  }
16
15
  return to;
17
16
  };
18
- var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
18
 
20
19
  // dist/index.js
21
20
  var index_exports = {};
@@ -61,3155 +60,7 @@ module.exports = __toCommonJS(index_exports);
61
60
 
62
61
  // dist/zoom-widget.js
63
62
  var import_jsx_runtime4 = require("preact/jsx-runtime");
64
-
65
- // ../core/src/utils/log.ts
66
- var import_log = require("@probe.gl/log");
67
- var defaultLogger = new import_log.Log({ id: "deck" });
68
- var log_default = defaultLogger;
69
-
70
- // ../core/src/lib/constants.ts
71
- var import_mjolnir = require("mjolnir.js");
72
- var COORDINATE_SYSTEM = {
73
- /**
74
- * `LNGLAT` if rendering into a geospatial viewport, `CARTESIAN` otherwise
75
- */
76
- DEFAULT: "default",
77
- /**
78
- * Positions are interpreted as [longitude, latitude, elevation]
79
- * longitude/latitude are in degrees, elevation is in meters.
80
- * Dimensions are in meters.
81
- */
82
- LNGLAT: "lnglat",
83
- /**
84
- * Positions are interpreted as [x, y, z] in meter offsets from the coordinate origin.
85
- * Dimensions are in meters.
86
- */
87
- METER_OFFSETS: "meter-offsets",
88
- /**
89
- * Positions are interpreted as [deltaLng, deltaLat, elevation] from the coordinate origin.
90
- * deltaLng/deltaLat are in degrees, elevation is in meters.
91
- * Dimensions are in meters.
92
- */
93
- LNGLAT_OFFSETS: "lnglat-offsets",
94
- /**
95
- * Positions and dimensions are in the common units of the viewport.
96
- */
97
- CARTESIAN: "cartesian"
98
- };
99
- Object.defineProperty(COORDINATE_SYSTEM, "IDENTITY", {
100
- get: () => {
101
- log_default.deprecated("COORDINATE_SYSTEM.IDENTITY", "COORDINATE_SYSTEM.CARTESIAN")();
102
- return COORDINATE_SYSTEM.CARTESIAN;
103
- }
104
- });
105
- var PROJECTION_MODE = {
106
- /**
107
- * Render geospatial data in Web Mercator projection
108
- */
109
- WEB_MERCATOR: 1,
110
- /**
111
- * Render geospatial data as a 3D globe
112
- */
113
- GLOBE: 2,
114
- /**
115
- * (Internal use only) Web Mercator projection at high zoom
116
- */
117
- WEB_MERCATOR_AUTO_OFFSET: 4,
118
- /**
119
- * No transformation
120
- */
121
- IDENTITY: 0
122
- };
123
-
124
- // ../core/src/utils/math-utils.ts
125
- var import_core = require("@math.gl/core");
126
- function createMat4() {
127
- return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
128
- }
129
- function mod(value, divisor) {
130
- const modulus = value % divisor;
131
- return modulus < 0 ? divisor + modulus : modulus;
132
- }
133
- function getCameraPosition(viewMatrixInverse) {
134
- return [viewMatrixInverse[12], viewMatrixInverse[13], viewMatrixInverse[14]];
135
- }
136
- function getFrustumPlanes(viewProjectionMatrix) {
137
- return {
138
- left: getFrustumPlane(
139
- viewProjectionMatrix[3] + viewProjectionMatrix[0],
140
- viewProjectionMatrix[7] + viewProjectionMatrix[4],
141
- viewProjectionMatrix[11] + viewProjectionMatrix[8],
142
- viewProjectionMatrix[15] + viewProjectionMatrix[12]
143
- ),
144
- right: getFrustumPlane(
145
- viewProjectionMatrix[3] - viewProjectionMatrix[0],
146
- viewProjectionMatrix[7] - viewProjectionMatrix[4],
147
- viewProjectionMatrix[11] - viewProjectionMatrix[8],
148
- viewProjectionMatrix[15] - viewProjectionMatrix[12]
149
- ),
150
- bottom: getFrustumPlane(
151
- viewProjectionMatrix[3] + viewProjectionMatrix[1],
152
- viewProjectionMatrix[7] + viewProjectionMatrix[5],
153
- viewProjectionMatrix[11] + viewProjectionMatrix[9],
154
- viewProjectionMatrix[15] + viewProjectionMatrix[13]
155
- ),
156
- top: getFrustumPlane(
157
- viewProjectionMatrix[3] - viewProjectionMatrix[1],
158
- viewProjectionMatrix[7] - viewProjectionMatrix[5],
159
- viewProjectionMatrix[11] - viewProjectionMatrix[9],
160
- viewProjectionMatrix[15] - viewProjectionMatrix[13]
161
- ),
162
- near: getFrustumPlane(
163
- viewProjectionMatrix[3] + viewProjectionMatrix[2],
164
- viewProjectionMatrix[7] + viewProjectionMatrix[6],
165
- viewProjectionMatrix[11] + viewProjectionMatrix[10],
166
- viewProjectionMatrix[15] + viewProjectionMatrix[14]
167
- ),
168
- far: getFrustumPlane(
169
- viewProjectionMatrix[3] - viewProjectionMatrix[2],
170
- viewProjectionMatrix[7] - viewProjectionMatrix[6],
171
- viewProjectionMatrix[11] - viewProjectionMatrix[10],
172
- viewProjectionMatrix[15] - viewProjectionMatrix[14]
173
- )
174
- };
175
- }
176
- var scratchVector = new import_core.Vector3();
177
- function getFrustumPlane(a, b, c, d) {
178
- scratchVector.set(a, b, c);
179
- const L = scratchVector.len();
180
- return { distance: d / L, normal: new import_core.Vector3(-a / L, -b / L, -c / L) };
181
- }
182
-
183
- // ../core/src/viewports/viewport.ts
184
- var import_core2 = require("@math.gl/core");
185
- var import_web_mercator = require("@math.gl/web-mercator");
186
- var DEGREES_TO_RADIANS = Math.PI / 180;
187
- var IDENTITY = createMat4();
188
- var ZERO_VECTOR = [0, 0, 0];
189
- var DEFAULT_DISTANCE_SCALES = {
190
- unitsPerMeter: [1, 1, 1],
191
- metersPerUnit: [1, 1, 1]
192
- };
193
- function createProjectionMatrix({
194
- width,
195
- height,
196
- orthographic,
197
- fovyRadians,
198
- focalDistance,
199
- padding,
200
- near,
201
- far
202
- }) {
203
- const aspect = width / height;
204
- const matrix = orthographic ? new import_core2.Matrix4().orthographic({ fovy: fovyRadians, aspect, focalDistance, near, far }) : new import_core2.Matrix4().perspective({ fovy: fovyRadians, aspect, near, far });
205
- if (padding) {
206
- const { left = 0, right = 0, top = 0, bottom = 0 } = padding;
207
- const offsetX = (0, import_core2.clamp)((left + width - right) / 2, 0, width) - width / 2;
208
- const offsetY = (0, import_core2.clamp)((top + height - bottom) / 2, 0, height) - height / 2;
209
- matrix[8] -= offsetX * 2 / width;
210
- matrix[9] += offsetY * 2 / height;
211
- }
212
- return matrix;
213
- }
214
- var _Viewport = class _Viewport {
215
- // eslint-disable-next-line complexity
216
- constructor(opts = {}) {
217
- this._frustumPlanes = {};
218
- this.id = opts.id || this.constructor.displayName || "viewport";
219
- this.x = opts.x || 0;
220
- this.y = opts.y || 0;
221
- this.width = opts.width || 1;
222
- this.height = opts.height || 1;
223
- this.zoom = opts.zoom || 0;
224
- this.padding = opts.padding;
225
- this.distanceScales = opts.distanceScales || DEFAULT_DISTANCE_SCALES;
226
- this.focalDistance = opts.focalDistance || 1;
227
- this.position = opts.position || ZERO_VECTOR;
228
- this.modelMatrix = opts.modelMatrix || null;
229
- const { longitude, latitude } = opts;
230
- this.isGeospatial = Number.isFinite(latitude) && Number.isFinite(longitude);
231
- this._initProps(opts);
232
- this._initMatrices(opts);
233
- this.equals = this.equals.bind(this);
234
- this.project = this.project.bind(this);
235
- this.unproject = this.unproject.bind(this);
236
- this.projectPosition = this.projectPosition.bind(this);
237
- this.unprojectPosition = this.unprojectPosition.bind(this);
238
- this.projectFlat = this.projectFlat.bind(this);
239
- this.unprojectFlat = this.unprojectFlat.bind(this);
240
- }
241
- get subViewports() {
242
- return null;
243
- }
244
- get metersPerPixel() {
245
- return this.distanceScales.metersPerUnit[2] / this.scale;
246
- }
247
- get projectionMode() {
248
- if (this.isGeospatial) {
249
- return this.zoom < 12 ? PROJECTION_MODE.WEB_MERCATOR : PROJECTION_MODE.WEB_MERCATOR_AUTO_OFFSET;
250
- }
251
- return PROJECTION_MODE.IDENTITY;
252
- }
253
- // Two viewports are equal if their dimensions, common-space scale, and
254
- // view and projection matrices are (approximately) equal.
255
- equals(viewport) {
256
- if (!(viewport instanceof _Viewport)) {
257
- return false;
258
- }
259
- if (this === viewport) {
260
- return true;
261
- }
262
- return viewport.width === this.width && viewport.height === this.height && viewport.scale === this.scale && viewport.projectionMode === this.projectionMode && viewport.resolution === this.resolution && (0, import_core2.equals)(viewport.distanceScales.unitsPerMeter, this.distanceScales.unitsPerMeter) && (0, import_core2.equals)(viewport.projectionMatrix, this.projectionMatrix) && (0, import_core2.equals)(viewport.viewMatrix, this.viewMatrix);
263
- }
264
- /**
265
- * Projects xyz (possibly latitude and longitude) to pixel coordinates in window
266
- * using viewport projection parameters
267
- * - [longitude, latitude] to [x, y]
268
- * - [longitude, latitude, Z] => [x, y, z]
269
- * Note: By default, returns top-left coordinates for canvas/SVG type render
270
- *
271
- * @param {Array} lngLatZ - [lng, lat] or [lng, lat, Z]
272
- * @param {Object} opts - options
273
- * @param {Object} opts.topLeft=true - Whether projected coords are top left
274
- * @return {Array} - [x, y] or [x, y, z] in top left coords
275
- */
276
- project(xyz, { topLeft = true } = {}) {
277
- const worldPosition = this.projectPosition(xyz);
278
- const coord = (0, import_web_mercator.worldToPixels)(worldPosition, this.pixelProjectionMatrix);
279
- const [x, y] = coord;
280
- const y2 = topLeft ? y : this.height - y;
281
- return xyz.length === 2 ? [x, y2] : [x, y2, coord[2]];
282
- }
283
- /**
284
- * Unproject pixel coordinates on screen onto world coordinates,
285
- * (possibly [lon, lat]) on map.
286
- * - [x, y] => [lng, lat]
287
- * - [x, y, z] => [lng, lat, Z]
288
- * @param {Array} xyz -
289
- * @param {Object} opts - options
290
- * @param {Object} opts.topLeft=true - Whether origin is top left
291
- * @return {Array|null} - [lng, lat, Z] or [X, Y, Z]
292
- */
293
- unproject(xyz, { topLeft = true, targetZ } = {}) {
294
- const [x, y, z] = xyz;
295
- const y2 = topLeft ? y : this.height - y;
296
- const targetZWorld = targetZ && targetZ * this.distanceScales.unitsPerMeter[2];
297
- const coord = (0, import_web_mercator.pixelsToWorld)([x, y2, z], this.pixelUnprojectionMatrix, targetZWorld);
298
- const [X, Y, Z] = this.unprojectPosition(coord);
299
- if (Number.isFinite(z)) {
300
- return [X, Y, Z];
301
- }
302
- return Number.isFinite(targetZ) ? [X, Y, targetZ] : [X, Y];
303
- }
304
- // NON_LINEAR PROJECTION HOOKS
305
- // Used for web meractor projection
306
- projectPosition(xyz) {
307
- const [X, Y] = this.projectFlat(xyz);
308
- const Z = (xyz[2] || 0) * this.distanceScales.unitsPerMeter[2];
309
- return [X, Y, Z];
310
- }
311
- unprojectPosition(xyz) {
312
- const [X, Y] = this.unprojectFlat(xyz);
313
- const Z = (xyz[2] || 0) * this.distanceScales.metersPerUnit[2];
314
- return [X, Y, Z];
315
- }
316
- /**
317
- * Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.
318
- * Performs the nonlinear part of the web mercator projection.
319
- * Remaining projection is done with 4x4 matrices which also handles
320
- * perspective.
321
- * @param {Array} lngLat - [lng, lat] coordinates
322
- * Specifies a point on the sphere to project onto the map.
323
- * @return {Array} [x,y] coordinates.
324
- */
325
- projectFlat(xyz) {
326
- if (this.isGeospatial) {
327
- const result = (0, import_web_mercator.lngLatToWorld)(xyz);
328
- result[1] = (0, import_core2.clamp)(result[1], -318, 830);
329
- return result;
330
- }
331
- return xyz;
332
- }
333
- /**
334
- * Unproject world point [x,y] on map onto {lat, lon} on sphere
335
- * @param {object|Vector} xy - object with {x,y} members
336
- * representing point on projected map plane
337
- * @return {GeoCoordinates} - object with {lat,lon} of point on sphere.
338
- * Has toArray method if you need a GeoJSON Array.
339
- * Per cartographic tradition, lat and lon are specified as degrees.
340
- */
341
- unprojectFlat(xyz) {
342
- if (this.isGeospatial) {
343
- return (0, import_web_mercator.worldToLngLat)(xyz);
344
- }
345
- return xyz;
346
- }
347
- /**
348
- * Get bounds of the current viewport
349
- * @return {Array} - [minX, minY, maxX, maxY]
350
- */
351
- getBounds(options = {}) {
352
- const unprojectOption = { targetZ: options.z || 0 };
353
- const topLeft = this.unproject([0, 0], unprojectOption);
354
- const topRight = this.unproject([this.width, 0], unprojectOption);
355
- const bottomLeft = this.unproject([0, this.height], unprojectOption);
356
- const bottomRight = this.unproject([this.width, this.height], unprojectOption);
357
- return [
358
- Math.min(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]),
359
- Math.min(topLeft[1], topRight[1], bottomLeft[1], bottomRight[1]),
360
- Math.max(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]),
361
- Math.max(topLeft[1], topRight[1], bottomLeft[1], bottomRight[1])
362
- ];
363
- }
364
- getDistanceScales(coordinateOrigin) {
365
- if (coordinateOrigin && this.isGeospatial) {
366
- return (0, import_web_mercator.getDistanceScales)({
367
- longitude: coordinateOrigin[0],
368
- latitude: coordinateOrigin[1],
369
- highPrecision: true
370
- });
371
- }
372
- return this.distanceScales;
373
- }
374
- containsPixel({
375
- x,
376
- y,
377
- width = 1,
378
- height = 1
379
- }) {
380
- return x < this.x + this.width && this.x < x + width && y < this.y + this.height && this.y < y + height;
381
- }
382
- // Extract frustum planes in common space
383
- getFrustumPlanes() {
384
- if (this._frustumPlanes.near) {
385
- return this._frustumPlanes;
386
- }
387
- Object.assign(this._frustumPlanes, getFrustumPlanes(this.viewProjectionMatrix));
388
- return this._frustumPlanes;
389
- }
390
- // EXPERIMENTAL METHODS
391
- /**
392
- * Needed by panning and linear transition
393
- * Pan the viewport to place a given world coordinate at screen point [x, y]
394
- *
395
- * @param {Array} coords - world coordinates
396
- * @param {Array} pixel - [x,y] coordinates on screen
397
- * @param {Array} startPixel - [x,y] screen position where pan started (optional, for delta-based panning)
398
- * @return {Object} props of the new viewport
399
- */
400
- panByPosition(coords, pixel, startPixel) {
401
- return null;
402
- }
403
- // INTERNAL METHODS
404
- /* eslint-disable complexity, max-statements */
405
- _initProps(opts) {
406
- const longitude = opts.longitude;
407
- const latitude = opts.latitude;
408
- if (this.isGeospatial) {
409
- if (!Number.isFinite(opts.zoom)) {
410
- this.zoom = (0, import_web_mercator.getMeterZoom)({ latitude }) + Math.log2(this.focalDistance);
411
- }
412
- this.distanceScales = opts.distanceScales || (0, import_web_mercator.getDistanceScales)({ latitude, longitude });
413
- }
414
- const scale = Math.pow(2, this.zoom);
415
- this.scale = scale;
416
- const { position, modelMatrix } = opts;
417
- let meterOffset = ZERO_VECTOR;
418
- if (position) {
419
- meterOffset = modelMatrix ? new import_core2.Matrix4(modelMatrix).transformAsVector(position, []) : position;
420
- }
421
- if (this.isGeospatial) {
422
- const center = this.projectPosition([longitude, latitude, 0]);
423
- this.center = new import_core2.Vector3(meterOffset).scale(this.distanceScales.unitsPerMeter).add(center);
424
- } else {
425
- this.center = this.projectPosition(meterOffset);
426
- }
427
- }
428
- /* eslint-enable complexity, max-statements */
429
- _initMatrices(opts) {
430
- const {
431
- // View matrix
432
- viewMatrix: viewMatrix2 = IDENTITY,
433
- // Projection matrix
434
- projectionMatrix = null,
435
- // Projection matrix parameters, used if projectionMatrix not supplied
436
- orthographic = false,
437
- fovyRadians,
438
- fovy = 75,
439
- near = 0.1,
440
- // Distance of near clipping plane
441
- far = 1e3,
442
- // Distance of far clipping plane
443
- padding = null,
444
- // Center offset in pixels
445
- focalDistance = 1
446
- } = opts;
447
- this.viewMatrixUncentered = viewMatrix2;
448
- this.viewMatrix = new import_core2.Matrix4().multiplyRight(viewMatrix2).translate(new import_core2.Vector3(this.center).negate());
449
- this.projectionMatrix = projectionMatrix || createProjectionMatrix({
450
- width: this.width,
451
- height: this.height,
452
- orthographic,
453
- fovyRadians: fovyRadians || fovy * DEGREES_TO_RADIANS,
454
- focalDistance,
455
- padding,
456
- near,
457
- far
458
- });
459
- const vpm = createMat4();
460
- import_core2.mat4.multiply(vpm, vpm, this.projectionMatrix);
461
- import_core2.mat4.multiply(vpm, vpm, this.viewMatrix);
462
- this.viewProjectionMatrix = vpm;
463
- this.viewMatrixInverse = import_core2.mat4.invert([], this.viewMatrix) || this.viewMatrix;
464
- this.cameraPosition = getCameraPosition(this.viewMatrixInverse);
465
- const viewportMatrix = createMat4();
466
- const pixelProjectionMatrix = createMat4();
467
- import_core2.mat4.scale(viewportMatrix, viewportMatrix, [this.width / 2, -this.height / 2, 1]);
468
- import_core2.mat4.translate(viewportMatrix, viewportMatrix, [1, -1, 0]);
469
- import_core2.mat4.multiply(pixelProjectionMatrix, viewportMatrix, this.viewProjectionMatrix);
470
- this.pixelProjectionMatrix = pixelProjectionMatrix;
471
- this.pixelUnprojectionMatrix = import_core2.mat4.invert(createMat4(), this.pixelProjectionMatrix);
472
- if (!this.pixelUnprojectionMatrix) {
473
- log_default.warn("Pixel project matrix not invertible")();
474
- }
475
- }
476
- };
477
- _Viewport.displayName = "Viewport";
478
- var Viewport = _Viewport;
479
-
480
- // ../core/src/viewports/web-mercator-viewport.ts
481
- var import_web_mercator2 = require("@math.gl/web-mercator");
482
- var import_core3 = require("@math.gl/core");
483
- var _WebMercatorViewport = class _WebMercatorViewport extends Viewport {
484
- /* eslint-disable complexity, max-statements */
485
- constructor(opts = {}) {
486
- const {
487
- latitude = 0,
488
- longitude = 0,
489
- zoom = 0,
490
- pitch = 0,
491
- bearing = 0,
492
- nearZMultiplier = 0.1,
493
- farZMultiplier = 1.01,
494
- nearZ,
495
- farZ,
496
- orthographic = false,
497
- projectionMatrix,
498
- repeat = false,
499
- worldOffset = 0,
500
- position,
501
- padding,
502
- // backward compatibility
503
- // TODO: remove in v9
504
- legacyMeterSizes = false
505
- } = opts;
506
- let { width, height, altitude = 1.5 } = opts;
507
- const scale = Math.pow(2, zoom);
508
- width = width || 1;
509
- height = height || 1;
510
- let fovy;
511
- let projectionParameters = null;
512
- if (projectionMatrix) {
513
- altitude = projectionMatrix[5] / 2;
514
- fovy = (0, import_web_mercator2.altitudeToFovy)(altitude);
515
- } else {
516
- if (opts.fovy) {
517
- fovy = opts.fovy;
518
- altitude = (0, import_web_mercator2.fovyToAltitude)(fovy);
519
- } else {
520
- fovy = (0, import_web_mercator2.altitudeToFovy)(altitude);
521
- }
522
- let offset3;
523
- if (padding) {
524
- const { top = 0, bottom = 0 } = padding;
525
- offset3 = [0, (0, import_core3.clamp)((top + height - bottom) / 2, 0, height) - height / 2];
526
- }
527
- projectionParameters = (0, import_web_mercator2.getProjectionParameters)({
528
- width,
529
- height,
530
- scale,
531
- center: position && [0, 0, position[2] * (0, import_web_mercator2.unitsPerMeter)(latitude)],
532
- offset: offset3,
533
- pitch,
534
- fovy,
535
- nearZMultiplier,
536
- farZMultiplier
537
- });
538
- if (Number.isFinite(nearZ)) {
539
- projectionParameters.near = nearZ;
540
- }
541
- if (Number.isFinite(farZ)) {
542
- projectionParameters.far = farZ;
543
- }
544
- }
545
- let viewMatrixUncentered = (0, import_web_mercator2.getViewMatrix)({
546
- height,
547
- pitch,
548
- bearing,
549
- scale,
550
- altitude
551
- });
552
- if (worldOffset) {
553
- const viewOffset = new import_core3.Matrix4().translate([512 * worldOffset, 0, 0]);
554
- viewMatrixUncentered = viewOffset.multiplyLeft(viewMatrixUncentered);
555
- }
556
- super({
557
- ...opts,
558
- // x, y,
559
- width,
560
- height,
561
- // view matrix
562
- viewMatrix: viewMatrixUncentered,
563
- longitude,
564
- latitude,
565
- zoom,
566
- // projection matrix parameters
567
- ...projectionParameters,
568
- fovy,
569
- focalDistance: altitude
570
- });
571
- this.latitude = latitude;
572
- this.longitude = longitude;
573
- this.zoom = zoom;
574
- this.pitch = pitch;
575
- this.bearing = bearing;
576
- this.altitude = altitude;
577
- this.fovy = fovy;
578
- this.orthographic = orthographic;
579
- this._subViewports = repeat ? [] : null;
580
- this._pseudoMeters = legacyMeterSizes;
581
- Object.freeze(this);
582
- }
583
- /* eslint-enable complexity, max-statements */
584
- get subViewports() {
585
- if (this._subViewports && !this._subViewports.length) {
586
- const bounds = this.getBounds();
587
- const minOffset = Math.floor((bounds[0] + 180) / 360);
588
- const maxOffset = Math.ceil((bounds[2] - 180) / 360);
589
- for (let x = minOffset; x <= maxOffset; x++) {
590
- const offsetViewport = x ? new _WebMercatorViewport({
591
- ...this,
592
- worldOffset: x
593
- }) : this;
594
- this._subViewports.push(offsetViewport);
595
- }
596
- }
597
- return this._subViewports;
598
- }
599
- /** Returns whether two Web Mercator viewports use the same projection settings. */
600
- equals(viewport) {
601
- return viewport instanceof _WebMercatorViewport && viewport._pseudoMeters === this._pseudoMeters && super.equals(viewport);
602
- }
603
- projectPosition(xyz) {
604
- if (this._pseudoMeters) {
605
- return super.projectPosition(xyz);
606
- }
607
- const [X, Y] = this.projectFlat(xyz);
608
- const Z = (xyz[2] || 0) * (0, import_web_mercator2.unitsPerMeter)(xyz[1]);
609
- return [X, Y, Z];
610
- }
611
- unprojectPosition(xyz) {
612
- if (this._pseudoMeters) {
613
- return super.unprojectPosition(xyz);
614
- }
615
- const [X, Y] = this.unprojectFlat(xyz);
616
- const Z = (xyz[2] || 0) / (0, import_web_mercator2.unitsPerMeter)(Y);
617
- return [X, Y, Z];
618
- }
619
- /**
620
- * Add a meter delta to a base lnglat coordinate, returning a new lnglat array
621
- *
622
- * Note: Uses simple linear approximation around the viewport center
623
- * Error increases with size of offset (roughly 1% per 100km)
624
- *
625
- * @param {[Number,Number]|[Number,Number,Number]) lngLatZ - base coordinate
626
- * @param {[Number,Number]|[Number,Number,Number]) xyz - array of meter deltas
627
- * @return {[Number,Number]|[Number,Number,Number]) array of [lng,lat,z] deltas
628
- */
629
- addMetersToLngLat(lngLatZ, xyz) {
630
- return (0, import_web_mercator2.addMetersToLngLat)(lngLatZ, xyz);
631
- }
632
- panByPosition(coords, pixel, startPixel) {
633
- const fromLocation = (0, import_web_mercator2.pixelsToWorld)(pixel, this.pixelUnprojectionMatrix);
634
- const toLocation = this.projectFlat(coords);
635
- const translate = import_core3.vec2.add([], toLocation, import_core3.vec2.negate([], fromLocation));
636
- const newCenter = import_core3.vec2.add([], this.center, translate);
637
- const [longitude, latitude] = this.unprojectFlat(newCenter);
638
- return { longitude, latitude };
639
- }
640
- /**
641
- * Returns a new longitude and latitude that keeps a 3D world coordinate at a given screen pixel
642
- * This version handles the z-component (altitude) properly for cameras positioned above ground
643
- */
644
- panByPosition3D(coords, pixel) {
645
- const targetZ = coords[2] || 0;
646
- const deltaLngLat = import_core3.vec2.sub([], coords, this.unproject(pixel, { targetZ }));
647
- return { longitude: this.longitude + deltaLngLat[0], latitude: this.latitude + deltaLngLat[1] };
648
- }
649
- getBounds(options = {}) {
650
- const corners = (0, import_web_mercator2.getBounds)(this, options.z || 0);
651
- return [
652
- Math.min(corners[0][0], corners[1][0], corners[2][0], corners[3][0]),
653
- Math.min(corners[0][1], corners[1][1], corners[2][1], corners[3][1]),
654
- Math.max(corners[0][0], corners[1][0], corners[2][0], corners[3][0]),
655
- Math.max(corners[0][1], corners[1][1], corners[2][1], corners[3][1])
656
- ];
657
- }
658
- /**
659
- * Returns a new viewport that fit around the given rectangle.
660
- * Only supports non-perspective mode.
661
- */
662
- fitBounds(bounds, options = {}) {
663
- const { width, height } = this;
664
- const { longitude, latitude, zoom } = (0, import_web_mercator2.fitBounds)({ width, height, bounds, ...options });
665
- return new _WebMercatorViewport({ width, height, longitude, latitude, zoom });
666
- }
667
- };
668
- _WebMercatorViewport.displayName = "WebMercatorViewport";
669
- var WebMercatorViewport = _WebMercatorViewport;
670
-
671
- // ../core/src/utils/deep-equal.ts
672
- function deepEqual(a, b, depth) {
673
- if (a === b) {
674
- return true;
675
- }
676
- if (!depth || !a || !b) {
677
- return false;
678
- }
679
- if (Array.isArray(a)) {
680
- if (!Array.isArray(b) || a.length !== b.length) {
681
- return false;
682
- }
683
- for (let i = 0; i < a.length; i++) {
684
- if (!deepEqual(a[i], b[i], depth - 1)) {
685
- return false;
686
- }
687
- }
688
- return true;
689
- }
690
- if (Array.isArray(b)) {
691
- return false;
692
- }
693
- if (typeof a === "object" && typeof b === "object") {
694
- const aKeys = Object.keys(a);
695
- const bKeys = Object.keys(b);
696
- if (aKeys.length !== bKeys.length) {
697
- return false;
698
- }
699
- for (const key of aKeys) {
700
- if (!b.hasOwnProperty(key)) {
701
- return false;
702
- }
703
- if (!deepEqual(a[key], b[key], depth - 1)) {
704
- return false;
705
- }
706
- }
707
- return true;
708
- }
709
- return false;
710
- }
711
-
712
- // ../core/src/utils/positions.ts
713
- var NUMBER_REGEX = /^(?:\d+\.?\d*|\.\d+)$/;
714
- function parsePosition(value) {
715
- switch (typeof value) {
716
- case "number":
717
- if (!Number.isFinite(value)) {
718
- throw new Error(`Could not parse position string ${value}`);
719
- }
720
- return { type: "literal", value };
721
- case "string":
722
- try {
723
- const tokens = tokenize(value);
724
- const parser = new LayoutExpressionParser(tokens);
725
- return parser.parseExpression();
726
- } catch (error) {
727
- const reason = error instanceof Error ? error.message : String(error);
728
- throw new Error(`Could not parse position string ${value}: ${reason}`);
729
- }
730
- default:
731
- throw new Error(`Could not parse position string ${value}`);
732
- }
733
- }
734
- function evaluateLayoutExpression(expression, extent) {
735
- switch (expression.type) {
736
- case "literal":
737
- return expression.value;
738
- case "percentage":
739
- return Math.round(expression.value * extent);
740
- case "binary":
741
- const left = evaluateLayoutExpression(expression.left, extent);
742
- const right = evaluateLayoutExpression(expression.right, extent);
743
- return expression.operator === "+" ? left + right : left - right;
744
- default:
745
- throw new Error("Unknown layout expression type");
746
- }
747
- }
748
- function getPosition(expression, extent) {
749
- return evaluateLayoutExpression(expression, extent);
750
- }
751
- function tokenize(input) {
752
- const tokens = [];
753
- let index = 0;
754
- while (index < input.length) {
755
- const char = input[index];
756
- if (/\s/.test(char)) {
757
- index++;
758
- continue;
759
- }
760
- if (char === "+" || char === "-" || char === "(" || char === ")" || char === "%") {
761
- tokens.push({ type: "symbol", value: char });
762
- index++;
763
- continue;
764
- }
765
- if (isDigit(char) || char === ".") {
766
- const start = index;
767
- let hasDecimal = char === ".";
768
- index++;
769
- while (index < input.length) {
770
- const next = input[index];
771
- if (isDigit(next)) {
772
- index++;
773
- continue;
774
- }
775
- if (next === "." && !hasDecimal) {
776
- hasDecimal = true;
777
- index++;
778
- continue;
779
- }
780
- break;
781
- }
782
- const numberString = input.slice(start, index);
783
- if (!NUMBER_REGEX.test(numberString)) {
784
- throw new Error("Invalid number token");
785
- }
786
- tokens.push({ type: "number", value: parseFloat(numberString) });
787
- continue;
788
- }
789
- if (isAlpha(char)) {
790
- const start = index;
791
- while (index < input.length && isAlpha(input[index])) {
792
- index++;
793
- }
794
- const word = input.slice(start, index).toLowerCase();
795
- tokens.push({ type: "word", value: word });
796
- continue;
797
- }
798
- throw new Error("Invalid token in position string");
799
- }
800
- return tokens;
801
- }
802
- var LayoutExpressionParser = class {
803
- constructor(tokens) {
804
- this.index = 0;
805
- this.tokens = tokens;
806
- }
807
- parseExpression() {
808
- const expression = this.parseBinaryExpression();
809
- if (this.index < this.tokens.length) {
810
- throw new Error("Unexpected token at end of expression");
811
- }
812
- return expression;
813
- }
814
- parseBinaryExpression() {
815
- let expression = this.parseFactor();
816
- let token = this.peek();
817
- while (isAddSubSymbol(token)) {
818
- this.index++;
819
- const right = this.parseFactor();
820
- expression = { type: "binary", operator: token.value, left: expression, right };
821
- token = this.peek();
822
- }
823
- return expression;
824
- }
825
- parseFactor() {
826
- const token = this.peek();
827
- if (!token) {
828
- throw new Error("Unexpected end of expression");
829
- }
830
- if (token.type === "symbol" && token.value === "+") {
831
- this.index++;
832
- return this.parseFactor();
833
- }
834
- if (token.type === "symbol" && token.value === "-") {
835
- this.index++;
836
- const factor = this.parseFactor();
837
- return { type: "binary", operator: "-", left: { type: "literal", value: 0 }, right: factor };
838
- }
839
- if (token.type === "symbol" && token.value === "(") {
840
- this.index++;
841
- const expression = this.parseBinaryExpression();
842
- if (!this.consumeSymbol(")")) {
843
- throw new Error("Missing closing parenthesis");
844
- }
845
- return expression;
846
- }
847
- if (token.type === "word" && token.value === "calc") {
848
- this.index++;
849
- if (!this.consumeSymbol("(")) {
850
- throw new Error("Missing opening parenthesis after calc");
851
- }
852
- const expression = this.parseBinaryExpression();
853
- if (!this.consumeSymbol(")")) {
854
- throw new Error("Missing closing parenthesis");
855
- }
856
- return expression;
857
- }
858
- if (token.type === "number") {
859
- this.index++;
860
- const numberValue = token.value;
861
- const nextToken = this.peek();
862
- if (nextToken && nextToken.type === "symbol" && nextToken.value === "%") {
863
- this.index++;
864
- return { type: "percentage", value: numberValue / 100 };
865
- }
866
- if (nextToken && nextToken.type === "word" && nextToken.value === "px") {
867
- this.index++;
868
- return { type: "literal", value: numberValue };
869
- }
870
- return { type: "literal", value: numberValue };
871
- }
872
- throw new Error("Unexpected token in expression");
873
- }
874
- consumeSymbol(value) {
875
- const token = this.peek();
876
- if (token && token.type === "symbol" && token.value === value) {
877
- this.index++;
878
- return true;
879
- }
880
- return false;
881
- }
882
- peek() {
883
- return this.tokens[this.index] || null;
884
- }
885
- };
886
- function isDigit(char) {
887
- return char >= "0" && char <= "9";
888
- }
889
- function isAlpha(char) {
890
- return char >= "a" && char <= "z" || char >= "A" && char <= "Z";
891
- }
892
- function isAddSubSymbol(token) {
893
- return Boolean(token && token.type === "symbol" && (token.value === "+" || token.value === "-"));
894
- }
895
-
896
- // ../core/src/utils/deep-merge.ts
897
- function deepMergeViewState(a, b) {
898
- const result = { ...a };
899
- for (const key in b) {
900
- if (key === "id") continue;
901
- if (Array.isArray(result[key]) && Array.isArray(b[key])) {
902
- result[key] = mergeNumericArray(result[key], b[key]);
903
- } else {
904
- result[key] = b[key];
905
- }
906
- }
907
- return result;
908
- }
909
- function mergeNumericArray(target, source) {
910
- target = target.slice();
911
- for (let i = 0; i < source.length; i++) {
912
- const v = source[i];
913
- if (Number.isFinite(v)) {
914
- target[i] = v;
915
- }
916
- }
917
- return target;
918
- }
919
-
920
- // ../core/src/views/view.ts
921
- var View = class {
922
- constructor(props) {
923
- const { id, x = 0, y = 0, width = "100%", height = "100%", padding = null } = props;
924
- this.id = id || this.constructor.displayName || "view";
925
- this.props = { ...props, id: this.id };
926
- this._x = parsePosition(x);
927
- this._y = parsePosition(y);
928
- this._width = parsePosition(width);
929
- this._height = parsePosition(height);
930
- this._padding = padding && {
931
- left: parsePosition(padding.left || 0),
932
- right: parsePosition(padding.right || 0),
933
- top: parsePosition(padding.top || 0),
934
- bottom: parsePosition(padding.bottom || 0)
935
- };
936
- this.equals = this.equals.bind(this);
937
- Object.seal(this);
938
- }
939
- equals(view) {
940
- if (this === view) {
941
- return true;
942
- }
943
- return this.constructor === view.constructor && deepEqual(this.props, view.props, 2);
944
- }
945
- /** Clone this view with modified props */
946
- clone(newProps) {
947
- const ViewConstructor = this.constructor;
948
- return new ViewConstructor({ ...this.props, ...newProps });
949
- }
950
- /** Make viewport from canvas dimensions and view state */
951
- makeViewport({ width, height, viewState }) {
952
- viewState = this.filterViewState(viewState);
953
- const viewportDimensions = this.getDimensions({ width, height });
954
- if (!viewportDimensions.height || !viewportDimensions.width) {
955
- return null;
956
- }
957
- const ViewportType = this.getViewportType(viewState);
958
- return new ViewportType({ ...viewState, ...this.props, ...viewportDimensions });
959
- }
960
- getViewStateId() {
961
- const { viewState } = this.props;
962
- if (typeof viewState === "string") {
963
- return viewState;
964
- }
965
- return (viewState == null ? void 0 : viewState.id) || this.id;
966
- }
967
- // Allows view to override (or completely define) viewState
968
- filterViewState(viewState) {
969
- if (this.props.viewState && typeof this.props.viewState === "object") {
970
- if (!this.props.viewState.id) {
971
- return this.props.viewState;
972
- }
973
- return deepMergeViewState(viewState, this.props.viewState);
974
- }
975
- return viewState;
976
- }
977
- /** Resolve the dimensions of the view from overall canvas dimensions */
978
- getDimensions({ width, height }) {
979
- const dimensions = {
980
- x: getPosition(this._x, width),
981
- y: getPosition(this._y, height),
982
- width: getPosition(this._width, width),
983
- height: getPosition(this._height, height)
984
- };
985
- if (this._padding) {
986
- dimensions.padding = {
987
- left: getPosition(this._padding.left, width),
988
- top: getPosition(this._padding.top, height),
989
- right: getPosition(this._padding.right, width),
990
- bottom: getPosition(this._padding.bottom, height)
991
- };
992
- }
993
- return dimensions;
994
- }
995
- // Used by sub classes to resolve controller props
996
- get controller() {
997
- const opts = this.props.controller;
998
- if (!opts) {
999
- return null;
1000
- }
1001
- if (opts === true) {
1002
- return { type: this.ControllerType };
1003
- }
1004
- if (typeof opts === "function") {
1005
- return { type: opts };
1006
- }
1007
- return { type: this.ControllerType, ...opts };
1008
- }
1009
- };
1010
-
1011
- // ../core/src/transitions/transition.ts
1012
- var Transition = class {
1013
- /**
1014
- * @params timeline {Timeline}
1015
- */
1016
- constructor(timeline) {
1017
- this._inProgress = false;
1018
- this._handle = null;
1019
- this.time = 0;
1020
- // @ts-expect-error
1021
- this.settings = {
1022
- duration: 0
1023
- };
1024
- this._timeline = timeline;
1025
- }
1026
- /* Public API */
1027
- get inProgress() {
1028
- return this._inProgress;
1029
- }
1030
- /**
1031
- * (re)start this transition.
1032
- * @params props {object} - optional overriding props. see constructor
1033
- */
1034
- start(settings) {
1035
- var _a, _b;
1036
- this.cancel();
1037
- this.settings = settings;
1038
- this._inProgress = true;
1039
- (_b = (_a = this.settings).onStart) == null ? void 0 : _b.call(_a, this);
1040
- }
1041
- /**
1042
- * end this transition if it is in progress.
1043
- */
1044
- end() {
1045
- var _a, _b;
1046
- if (this._inProgress) {
1047
- this._timeline.removeChannel(this._handle);
1048
- this._handle = null;
1049
- this._inProgress = false;
1050
- (_b = (_a = this.settings).onEnd) == null ? void 0 : _b.call(_a, this);
1051
- }
1052
- }
1053
- /**
1054
- * cancel this transition if it is in progress.
1055
- */
1056
- cancel() {
1057
- var _a, _b;
1058
- if (this._inProgress) {
1059
- (_b = (_a = this.settings).onInterrupt) == null ? void 0 : _b.call(_a, this);
1060
- this._timeline.removeChannel(this._handle);
1061
- this._handle = null;
1062
- this._inProgress = false;
1063
- }
1064
- }
1065
- /**
1066
- * update this transition. Returns `true` if updated.
1067
- */
1068
- update() {
1069
- var _a, _b;
1070
- if (!this._inProgress) {
1071
- return false;
1072
- }
1073
- if (this._handle === null) {
1074
- const { _timeline: timeline, settings } = this;
1075
- this._handle = timeline.addChannel({
1076
- delay: timeline.getTime(),
1077
- duration: settings.duration
1078
- });
1079
- }
1080
- this.time = this._timeline.getTime(this._handle);
1081
- this._onUpdate();
1082
- (_b = (_a = this.settings).onUpdate) == null ? void 0 : _b.call(_a, this);
1083
- if (this._timeline.isFinished(this._handle)) {
1084
- this.end();
1085
- }
1086
- return true;
1087
- }
1088
- /* Private API */
1089
- _onUpdate() {
1090
- }
1091
- };
1092
-
1093
- // ../core/src/controllers/transition-manager.ts
1094
- var noop = () => {
1095
- };
1096
- var PRESERVE_CONSTRAINT_CONTEXT = { mode: "preserve" };
1097
- var HARD_CONSTRAINT_CONTEXT = { mode: "hard" };
1098
- var TRANSITION_EVENTS = {
1099
- BREAK: 1,
1100
- SNAP_TO_END: 2,
1101
- IGNORE: 3
1102
- };
1103
- var DEFAULT_EASING = (t) => t;
1104
- var DEFAULT_INTERRUPTION = TRANSITION_EVENTS.BREAK;
1105
- var TransitionManager = class {
1106
- constructor(opts) {
1107
- this._onTransitionUpdate = (transition) => {
1108
- const {
1109
- time,
1110
- settings: { interpolator, startProps, endProps, duration, easing }
1111
- } = transition;
1112
- const t = easing(time / duration);
1113
- const viewport = interpolator.interpolateProps(startProps, endProps, t);
1114
- this.propsInTransition = this.getControllerState(
1115
- {
1116
- ...this.props,
1117
- ...viewport
1118
- },
1119
- PRESERVE_CONSTRAINT_CONTEXT
1120
- ).getViewportProps();
1121
- this.onViewStateChange({
1122
- viewState: this.propsInTransition,
1123
- oldViewState: this.props
1124
- });
1125
- };
1126
- this.getControllerState = opts.getControllerState;
1127
- this.propsInTransition = null;
1128
- this.transition = new Transition(opts.timeline);
1129
- this.onViewStateChange = opts.onViewStateChange || noop;
1130
- this.onStateChange = opts.onStateChange || noop;
1131
- }
1132
- finalize() {
1133
- this.transition.cancel();
1134
- }
1135
- // Returns current transitioned viewport.
1136
- getViewportInTransition() {
1137
- return this.propsInTransition;
1138
- }
1139
- // Process the vewiport change, either ignore or trigger a new transition.
1140
- // Return true if a new transition is triggered, false otherwise.
1141
- processViewStateChange(nextProps) {
1142
- let transitionTriggered = false;
1143
- const currentProps = this.props;
1144
- this.props = nextProps;
1145
- if (!currentProps || this._shouldIgnoreViewportChange(currentProps, nextProps)) {
1146
- return false;
1147
- }
1148
- if (this._isTransitionEnabled(nextProps)) {
1149
- let startProps = currentProps;
1150
- if (this.transition.inProgress) {
1151
- const { interruption, endProps } = this.transition.settings;
1152
- startProps = {
1153
- ...currentProps,
1154
- ...interruption === TRANSITION_EVENTS.SNAP_TO_END ? endProps : this.propsInTransition || currentProps
1155
- };
1156
- }
1157
- this._triggerTransition(startProps, nextProps);
1158
- transitionTriggered = true;
1159
- } else {
1160
- this.transition.cancel();
1161
- }
1162
- return transitionTriggered;
1163
- }
1164
- updateTransition() {
1165
- this.transition.update();
1166
- }
1167
- // Helper methods
1168
- _isTransitionEnabled(props) {
1169
- const { transitionDuration, transitionInterpolator } = props;
1170
- return (transitionDuration > 0 || transitionDuration === "auto") && Boolean(transitionInterpolator);
1171
- }
1172
- _isUpdateDueToCurrentTransition(props) {
1173
- if (this.transition.inProgress && this.propsInTransition) {
1174
- return this.transition.settings.interpolator.arePropsEqual(
1175
- props,
1176
- this.propsInTransition
1177
- );
1178
- }
1179
- return false;
1180
- }
1181
- _shouldIgnoreViewportChange(currentProps, nextProps) {
1182
- if (this.transition.inProgress) {
1183
- const transitionSettings = this.transition.settings;
1184
- return transitionSettings.interruption === TRANSITION_EVENTS.IGNORE || // Ignore update if it is due to current active transition.
1185
- this._isUpdateDueToCurrentTransition(nextProps);
1186
- }
1187
- if (this._isTransitionEnabled(nextProps)) {
1188
- return nextProps.transitionInterpolator.arePropsEqual(
1189
- currentProps,
1190
- nextProps
1191
- );
1192
- }
1193
- return true;
1194
- }
1195
- _triggerTransition(startProps, endProps) {
1196
- const startViewstate = this.getControllerState(startProps, PRESERVE_CONSTRAINT_CONTEXT);
1197
- const endViewStateProps = this.getControllerState(
1198
- endProps,
1199
- HARD_CONSTRAINT_CONTEXT
1200
- ).shortestPathFrom(startViewstate);
1201
- const transitionInterpolator = endProps.transitionInterpolator;
1202
- const duration = transitionInterpolator.getDuration ? transitionInterpolator.getDuration(startProps, endProps) : endProps.transitionDuration;
1203
- if (duration === 0) {
1204
- return;
1205
- }
1206
- const initialProps = transitionInterpolator.initializeProps(startProps, endViewStateProps);
1207
- this.propsInTransition = {};
1208
- const transitionSettings = {
1209
- duration,
1210
- easing: endProps.transitionEasing || DEFAULT_EASING,
1211
- interpolator: transitionInterpolator,
1212
- interruption: endProps.transitionInterruption || DEFAULT_INTERRUPTION,
1213
- startProps: initialProps.start,
1214
- endProps: initialProps.end,
1215
- onStart: endProps.onTransitionStart,
1216
- onUpdate: this._onTransitionUpdate,
1217
- onInterrupt: this._onTransitionEnd(endProps.onTransitionInterrupt),
1218
- onEnd: this._onTransitionEnd(endProps.onTransitionEnd)
1219
- };
1220
- this.transition.start(transitionSettings);
1221
- this.onStateChange({ inTransition: true });
1222
- this.updateTransition();
1223
- }
1224
- _onTransitionEnd(callback) {
1225
- return (transition) => {
1226
- this.propsInTransition = null;
1227
- this.onStateChange({
1228
- inTransition: false,
1229
- isZooming: false,
1230
- isPanning: false,
1231
- isRotating: false
1232
- });
1233
- callback == null ? void 0 : callback(transition);
1234
- };
1235
- }
1236
- };
1237
-
1238
- // ../core/src/transitions/transition-interpolator.ts
1239
- var import_core4 = require("@math.gl/core");
1240
-
1241
- // ../core/src/utils/assert.ts
1242
- function assert(condition, message) {
1243
- if (!condition) {
1244
- throw new Error(message || "deck.gl: assertion failed.");
1245
- }
1246
- }
1247
-
1248
- // ../core/src/transitions/transition-interpolator.ts
1249
- var TransitionInterpolator = class {
1250
- /**
1251
- * @param opts {array|object}
1252
- * @param opts.compare {array} - prop names used in equality check
1253
- * @param opts.extract {array} - prop names needed for interpolation
1254
- * @param opts.required {array} - prop names that must be supplied
1255
- * alternatively, supply one list of prop names as `opts` if all of the above are the same.
1256
- */
1257
- constructor(opts) {
1258
- const { compare, extract, required } = opts;
1259
- this._propsToCompare = compare;
1260
- this._propsToExtract = extract || compare;
1261
- this._requiredProps = required;
1262
- }
1263
- /**
1264
- * Checks if two sets of props need transition in between
1265
- * @param currentProps {object} - a list of viewport props
1266
- * @param nextProps {object} - a list of viewport props
1267
- * @returns {bool} - true if two props are equivalent
1268
- */
1269
- arePropsEqual(currentProps, nextProps) {
1270
- for (const key of this._propsToCompare) {
1271
- if (!(key in currentProps) || !(key in nextProps) || !(0, import_core4.equals)(currentProps[key], nextProps[key])) {
1272
- return false;
1273
- }
1274
- }
1275
- return true;
1276
- }
1277
- /**
1278
- * Called before transition starts to validate/pre-process start and end props
1279
- * @param startProps {object} - a list of starting viewport props
1280
- * @param endProps {object} - a list of target viewport props
1281
- * @returns {Object} {start, end} - start and end props to be passed
1282
- * to `interpolateProps`
1283
- */
1284
- initializeProps(startProps, endProps) {
1285
- const startViewStateProps = {};
1286
- const endViewStateProps = {};
1287
- for (const key of this._propsToExtract) {
1288
- if (key in startProps || key in endProps) {
1289
- startViewStateProps[key] = startProps[key];
1290
- endViewStateProps[key] = endProps[key];
1291
- }
1292
- }
1293
- this._checkRequiredProps(startViewStateProps);
1294
- this._checkRequiredProps(endViewStateProps);
1295
- return { start: startViewStateProps, end: endViewStateProps };
1296
- }
1297
- /**
1298
- * Returns transition duration
1299
- * @param startProps {object} - a list of starting viewport props
1300
- * @param endProps {object} - a list of target viewport props
1301
- * @returns {Number} - transition duration in milliseconds
1302
- */
1303
- getDuration(startProps, endProps) {
1304
- return endProps.transitionDuration;
1305
- }
1306
- _checkRequiredProps(props) {
1307
- if (!this._requiredProps) {
1308
- return;
1309
- }
1310
- this._requiredProps.forEach((propName) => {
1311
- const value = props[propName];
1312
- assert(
1313
- Number.isFinite(value) || Array.isArray(value),
1314
- `${propName} is required for transition`
1315
- );
1316
- });
1317
- }
1318
- };
1319
-
1320
- // ../core/src/transitions/linear-interpolator.ts
1321
- var import_core5 = require("@math.gl/core");
1322
- var DEFAULT_PROPS = ["longitude", "latitude", "zoom", "bearing", "pitch"];
1323
- var DEFAULT_REQUIRED_PROPS = ["longitude", "latitude", "zoom"];
1324
- var LinearInterpolator = class extends TransitionInterpolator {
1325
- /**
1326
- * @param {Object} opts
1327
- * @param {Array} opts.transitionProps - list of props to apply linear transition to.
1328
- * @param {Array} opts.around - a screen point to zoom/rotate around.
1329
- * @param {Function} opts.makeViewport - construct a viewport instance with given props.
1330
- */
1331
- constructor(opts = {}) {
1332
- const transitionProps = Array.isArray(opts) ? opts : opts.transitionProps;
1333
- const normalizedOpts = Array.isArray(opts) ? {} : opts;
1334
- normalizedOpts.transitionProps = Array.isArray(transitionProps) ? {
1335
- compare: transitionProps,
1336
- required: transitionProps
1337
- } : transitionProps || {
1338
- compare: DEFAULT_PROPS,
1339
- required: DEFAULT_REQUIRED_PROPS
1340
- };
1341
- super(normalizedOpts.transitionProps);
1342
- this.opts = normalizedOpts;
1343
- }
1344
- initializeProps(startProps, endProps) {
1345
- const result = super.initializeProps(startProps, endProps);
1346
- const { makeViewport, around } = this.opts;
1347
- if (makeViewport && around) {
1348
- const startViewport = makeViewport(startProps);
1349
- const endViewport = makeViewport(endProps);
1350
- const aroundPosition = startViewport.unproject(around);
1351
- result.start.around = around;
1352
- Object.assign(result.end, {
1353
- around: endViewport.project(aroundPosition),
1354
- aroundPosition,
1355
- width: endProps.width,
1356
- height: endProps.height
1357
- });
1358
- }
1359
- return result;
1360
- }
1361
- interpolateProps(startProps, endProps, t) {
1362
- const propsInTransition = {};
1363
- for (const key of this._propsToExtract) {
1364
- propsInTransition[key] = (0, import_core5.lerp)(startProps[key] || 0, endProps[key] || 0, t);
1365
- }
1366
- if (endProps.aroundPosition && this.opts.makeViewport) {
1367
- const viewport = this.opts.makeViewport({ ...endProps, ...propsInTransition });
1368
- Object.assign(
1369
- propsInTransition,
1370
- viewport.panByPosition(
1371
- endProps.aroundPosition,
1372
- // anchor point in current screen coordinates
1373
- (0, import_core5.lerp)(startProps.around, endProps.around, t)
1374
- )
1375
- );
1376
- }
1377
- return propsInTransition;
1378
- }
1379
- };
1380
-
1381
- // ../core/src/controllers/controller.ts
1382
- var import_web_mercator3 = require("@math.gl/web-mercator");
1383
- var NO_TRANSITION_PROPS = {
1384
- transitionDuration: 0
1385
- };
1386
- var DEFAULT_INERTIA = 300;
1387
- var REBOUND_DURATION = 300;
1388
- var INERTIA_EASING = (t) => 1 - (1 - t) * (1 - t);
1389
- var EASE_OUT_EXPONENTIAL = (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
1390
- var EVENT_TYPES = {
1391
- WHEEL: ["wheel"],
1392
- PAN: ["panstart", "panmove", "panend"],
1393
- PINCH: ["pinchstart", "pinchmove", "pinchend"],
1394
- MULTI_PAN: ["multipanstart", "multipanmove", "multipanend"],
1395
- DOUBLE_CLICK: ["dblclick"],
1396
- DOUBLE_CLICK_DRAG: [
1397
- "dblclickdragstart",
1398
- "dblclickdragmove",
1399
- "dblclickdragend",
1400
- "dblclickdragcancel"
1401
- ],
1402
- KEYBOARD: ["keydown"]
1403
- };
1404
- var pinchEventWorkaround = {};
1405
- var Controller = class {
1406
- constructor(opts) {
1407
- this.state = {};
1408
- this._events = {};
1409
- this._interactionState = {
1410
- isDragging: false
1411
- };
1412
- this._customEvents = [];
1413
- this._eventStartBlocked = null;
1414
- this._panMove = false;
1415
- this._multiPanMode = null;
1416
- this._multiPanStartCenter = null;
1417
- this._doubleClickDragAnchor = null;
1418
- this._suppressDoubleClickUntil = 0;
1419
- this.invertPan = false;
1420
- this.dragMode = "rotate";
1421
- this.inertia = 0;
1422
- this.scrollZoom = true;
1423
- this.dragPan = true;
1424
- this.dragRotate = true;
1425
- this.doubleClickZoom = true;
1426
- this.doubleClickDragZoom = true;
1427
- this.touchZoom = true;
1428
- this.touchRotate = false;
1429
- this.multiTouchDrag = null;
1430
- this.trackpadGesture = false;
1431
- this.zoomAround = "pointer";
1432
- this.keyboard = true;
1433
- this.transitionManager = new TransitionManager({
1434
- ...opts,
1435
- getControllerState: (props, constraintContext) => new this.ControllerState({
1436
- ...props,
1437
- constraintContext,
1438
- makeViewport: opts.makeViewport
1439
- }),
1440
- onViewStateChange: this._onTransition.bind(this),
1441
- onStateChange: this._setInteractionState.bind(this)
1442
- });
1443
- this.handleEvent = this.handleEvent.bind(this);
1444
- this.eventManager = opts.eventManager;
1445
- this.onViewStateChange = opts.onViewStateChange || (() => {
1446
- });
1447
- this.onStateChange = opts.onStateChange || (() => {
1448
- });
1449
- this.makeViewport = opts.makeViewport;
1450
- this.pickPosition = opts.pickPosition;
1451
- }
1452
- set events(customEvents) {
1453
- this.toggleEvents(this._customEvents, false);
1454
- this.toggleEvents(customEvents, true);
1455
- this._customEvents = customEvents;
1456
- if (this.props) {
1457
- this.setProps(this.props);
1458
- }
1459
- }
1460
- finalize() {
1461
- var _a;
1462
- for (const eventName in this._events) {
1463
- if (this._events[eventName]) {
1464
- (_a = this.eventManager) == null ? void 0 : _a.off(eventName, this.handleEvent);
1465
- }
1466
- }
1467
- this.transitionManager.finalize();
1468
- }
1469
- /**
1470
- * Callback for events
1471
- */
1472
- handleEvent(event) {
1473
- this._controllerState = void 0;
1474
- const eventStartBlocked = this._eventStartBlocked;
1475
- switch (event.type) {
1476
- case "panstart":
1477
- return eventStartBlocked ? false : this._onPanStart(event);
1478
- case "panmove":
1479
- return this._onPan(event);
1480
- case "panend":
1481
- return this._onPanEnd(event);
1482
- case "pinchstart":
1483
- return eventStartBlocked || !this._isTrackpadGestureAllowed(event) ? false : this._onPinchStart(event);
1484
- case "pinchmove":
1485
- return this._isTrackpadGestureAllowed(event) ? this._onPinch(event) : false;
1486
- case "pinchend":
1487
- return this._isTrackpadGestureAllowed(event) ? this._onPinchEnd(event) : false;
1488
- case "multipanstart":
1489
- return eventStartBlocked ? false : this._onMultiPanStart(event);
1490
- case "multipanmove":
1491
- return this._onMultiPan(event);
1492
- case "multipanend":
1493
- return this._onMultiPanEnd(event);
1494
- case "dblclick":
1495
- return this._onDoubleClick(event);
1496
- case "dblclickdragstart":
1497
- return eventStartBlocked ? false : this._onDoubleClickDragStart(event);
1498
- case "dblclickdragmove":
1499
- return this._onDoubleClickDrag(event);
1500
- case "dblclickdragend":
1501
- case "dblclickdragcancel":
1502
- return this._onDoubleClickDragEnd(event);
1503
- case "wheel":
1504
- return this._onWheel(event);
1505
- case "keydown":
1506
- return this._onKeyDown(event);
1507
- default:
1508
- return false;
1509
- }
1510
- }
1511
- /* Event utils */
1512
- // Event object: http://hammerjs.github.io/api/#event-object
1513
- get controllerState() {
1514
- this._controllerState = this._controllerState || new this.ControllerState({
1515
- makeViewport: this.makeViewport,
1516
- ...this.props,
1517
- ...this.state
1518
- });
1519
- return this._controllerState;
1520
- }
1521
- getCenter(event) {
1522
- const { x, y } = this.props;
1523
- const { offsetCenter } = event;
1524
- return [offsetCenter.x - x, offsetCenter.y - y];
1525
- }
1526
- /** Resolves the zoom anchor for pointer-based controls. */
1527
- getZoomPosition(position) {
1528
- if (this.zoomAround === "pointer") {
1529
- return position;
1530
- }
1531
- const viewport = this.makeViewport(this.controllerState.getViewportProps());
1532
- const [centerX, centerY] = (0, import_web_mercator3.worldToPixels)(viewport.center, viewport.pixelProjectionMatrix);
1533
- return [centerX, centerY];
1534
- }
1535
- isPointInBounds(pos, event) {
1536
- const { width, height } = this.props;
1537
- if (event && event.handled) {
1538
- return false;
1539
- }
1540
- const inside = pos[0] >= 0 && pos[0] <= width && pos[1] >= 0 && pos[1] <= height;
1541
- if (inside && event) {
1542
- event.stopPropagation();
1543
- }
1544
- return inside;
1545
- }
1546
- isFunctionKeyPressed(event) {
1547
- const { srcEvent } = event;
1548
- return Boolean(srcEvent.metaKey || srcEvent.altKey || srcEvent.ctrlKey || srcEvent.shiftKey);
1549
- }
1550
- isDragging() {
1551
- return this._interactionState.isDragging || false;
1552
- }
1553
- // When a multi-touch event ends, e.g. pinch, not all pointers are lifted at the same time.
1554
- // This triggers a brief `pan` event.
1555
- // Calling this method will temporarily disable *start events to avoid conflicting transitions.
1556
- blockEvents(timeout) {
1557
- const timer = setTimeout(() => {
1558
- if (this._eventStartBlocked === timer) {
1559
- this._eventStartBlocked = null;
1560
- }
1561
- }, timeout);
1562
- this._eventStartBlocked = timer;
1563
- }
1564
- /**
1565
- * Extract interactivity options
1566
- */
1567
- setProps(props) {
1568
- if (props.maxBoundsPadding === void 0) {
1569
- props.maxBoundsPadding = null;
1570
- }
1571
- if (props.dragMode) {
1572
- this.dragMode = props.dragMode;
1573
- }
1574
- const oldProps = this.props;
1575
- this.props = props;
1576
- if (!("transitionInterpolator" in props)) {
1577
- props.transitionInterpolator = this._getTransitionProps().transitionInterpolator;
1578
- }
1579
- this.transitionManager.processViewStateChange(props);
1580
- const { inertia } = props;
1581
- this.inertia = Number.isFinite(inertia) ? inertia : inertia === true ? DEFAULT_INERTIA : 0;
1582
- const {
1583
- scrollZoom = true,
1584
- dragPan = true,
1585
- dragRotate = true,
1586
- doubleClickZoom = true,
1587
- doubleClickDragZoom = false,
1588
- touchZoom = true,
1589
- touchRotate = false,
1590
- multiTouchDrag = touchRotate ? "rotate" : null,
1591
- trackpadGesture = false,
1592
- zoomAround = "pointer",
1593
- keyboard = true
1594
- } = props;
1595
- const isInteractive = Boolean(this.onViewStateChange);
1596
- this.toggleEvents(EVENT_TYPES.WHEEL, isInteractive && scrollZoom);
1597
- this.toggleEvents(EVENT_TYPES.PAN, isInteractive);
1598
- this.toggleEvents(
1599
- EVENT_TYPES.PINCH,
1600
- isInteractive && (touchZoom || multiTouchDrag === "rotate")
1601
- );
1602
- this.toggleEvents(EVENT_TYPES.MULTI_PAN, isInteractive && Boolean(multiTouchDrag));
1603
- this.toggleEvents(EVENT_TYPES.DOUBLE_CLICK, isInteractive && doubleClickZoom);
1604
- this.toggleEvents(EVENT_TYPES.DOUBLE_CLICK_DRAG, isInteractive && doubleClickDragZoom);
1605
- this.toggleEvents(EVENT_TYPES.KEYBOARD, isInteractive && keyboard);
1606
- this.scrollZoom = scrollZoom;
1607
- this.dragPan = dragPan;
1608
- this.dragRotate = dragRotate;
1609
- this.doubleClickZoom = doubleClickZoom;
1610
- this.doubleClickDragZoom = doubleClickDragZoom;
1611
- this.touchZoom = touchZoom;
1612
- this.touchRotate = multiTouchDrag === "rotate";
1613
- this.multiTouchDrag = multiTouchDrag;
1614
- this.trackpadGesture = trackpadGesture;
1615
- this.zoomAround = zoomAround;
1616
- this.keyboard = keyboard;
1617
- const constraintChanged = !oldProps || oldProps.height !== props.height || oldProps.width !== props.width || oldProps.maxBounds !== props.maxBounds || oldProps.maxBoundsPadding !== props.maxBoundsPadding;
1618
- if (constraintChanged && props.maxBounds) {
1619
- const controllerState = new this.ControllerState({ ...props, makeViewport: this.makeViewport });
1620
- const normalizedProps = controllerState.getViewportProps();
1621
- const changed = Object.keys(normalizedProps).some(
1622
- (key) => !deepEqual(normalizedProps[key], props[key], 1)
1623
- );
1624
- if (changed) {
1625
- this.updateViewport(controllerState);
1626
- }
1627
- }
1628
- }
1629
- updateTransition() {
1630
- this.transitionManager.updateTransition();
1631
- }
1632
- toggleEvents(eventNames, enabled) {
1633
- if (this.eventManager) {
1634
- eventNames.forEach((eventName) => {
1635
- if (this._events[eventName] !== enabled) {
1636
- this._events[eventName] = enabled;
1637
- if (enabled) {
1638
- this.eventManager.on(eventName, this.handleEvent);
1639
- } else {
1640
- this.eventManager.off(eventName, this.handleEvent);
1641
- }
1642
- }
1643
- });
1644
- }
1645
- }
1646
- // Private Methods
1647
- /* Callback util */
1648
- // formats map state and invokes callback function
1649
- updateViewport(newControllerState, extraProps = null, interactionState = {}) {
1650
- const viewState = { ...newControllerState.getViewportProps(), ...extraProps };
1651
- const changed = this.controllerState !== newControllerState;
1652
- this.state = newControllerState.getState();
1653
- this._setInteractionState(interactionState);
1654
- if (changed) {
1655
- const oldViewState = this.controllerState && this.controllerState.getViewportProps();
1656
- if (this.onViewStateChange) {
1657
- this.onViewStateChange({
1658
- viewState,
1659
- interactionState: this._interactionState,
1660
- oldViewState,
1661
- viewId: this.props.id
1662
- });
1663
- }
1664
- }
1665
- }
1666
- _onTransition(params) {
1667
- this.onViewStateChange({
1668
- ...params,
1669
- interactionState: this._interactionState,
1670
- viewId: this.props.id
1671
- });
1672
- }
1673
- _setInteractionState(newStates) {
1674
- Object.assign(this._interactionState, newStates);
1675
- this.onStateChange(this._interactionState);
1676
- }
1677
- /** Maps a semantic input lifecycle to the constraint policy seen by controller state. */
1678
- _getConstraintContext(_action, phase) {
1679
- if (!this.props.rubberBand) {
1680
- return { mode: "hard" };
1681
- }
1682
- return { mode: phase === "update" ? "elastic" : phase === "end" ? "rebound" : "hard" };
1683
- }
1684
- /** Returns a rebound transition when hard resolution changed the displayed viewport props. */
1685
- _getReboundTransition(constraintContext, nextControllerState) {
1686
- if (constraintContext.mode !== "rebound") {
1687
- return null;
1688
- }
1689
- const nextViewportProps = nextControllerState.getViewportProps();
1690
- const shouldRebound = Object.keys(nextViewportProps).some(
1691
- (key) => !deepEqual(this.props[key], nextViewportProps[key], 1)
1692
- );
1693
- return shouldRebound ? {
1694
- ...this._getTransitionProps(),
1695
- transitionDuration: REBOUND_DURATION,
1696
- transitionEasing: EASE_OUT_EXPONENTIAL
1697
- } : null;
1698
- }
1699
- /* Event handlers */
1700
- // Default handler for the `panstart` event.
1701
- _onPanStart(event) {
1702
- const pos = this.getCenter(event);
1703
- if (!this.isPointInBounds(pos, event)) {
1704
- return false;
1705
- }
1706
- let alternateMode = this.isFunctionKeyPressed(event) || event.rightButton || false;
1707
- if (this.invertPan || this.dragMode === "pan") {
1708
- alternateMode = !alternateMode;
1709
- }
1710
- const action = alternateMode ? "pan" : "rotate";
1711
- const constraintContext = this._getConstraintContext(action, "start");
1712
- const newControllerState = alternateMode ? this.controllerState.panStart({ pos }, constraintContext) : this.controllerState.rotateStart({ pos }, constraintContext);
1713
- this._panMove = alternateMode;
1714
- this.updateViewport(newControllerState, NO_TRANSITION_PROPS, { isDragging: true });
1715
- return true;
1716
- }
1717
- // Default handler for the `panmove` and `panend` event.
1718
- _onPan(event) {
1719
- if (!this.isDragging()) {
1720
- return false;
1721
- }
1722
- return this._panMove ? this._onPanMove(event) : this._onPanRotate(event);
1723
- }
1724
- _onPanEnd(event) {
1725
- if (!this.isDragging()) {
1726
- return false;
1727
- }
1728
- return this._panMove ? this._onPanMoveEnd(event) : this._onPanRotateEnd(event);
1729
- }
1730
- // Default handler for panning to move.
1731
- // Called by `_onPan` when panning without function key pressed.
1732
- _onPanMove(event) {
1733
- if (!this.dragPan) {
1734
- return false;
1735
- }
1736
- const pos = this.getCenter(event);
1737
- const newControllerState = this.controllerState.pan(
1738
- { pos },
1739
- this._getConstraintContext("pan", "update")
1740
- );
1741
- this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
1742
- isDragging: true,
1743
- isPanning: true
1744
- });
1745
- return true;
1746
- }
1747
- _onPanMoveEnd(event) {
1748
- const { inertia } = this;
1749
- if (this.dragPan && inertia && event.velocity) {
1750
- const pos = this.getCenter(event);
1751
- const endPos = [
1752
- pos[0] + event.velocityX * inertia / 2,
1753
- pos[1] + event.velocityY * inertia / 2
1754
- ];
1755
- const newControllerState = this.controllerState.pan({ pos: endPos }).panEnd();
1756
- this.updateViewport(
1757
- newControllerState,
1758
- {
1759
- ...this._getTransitionProps(),
1760
- transitionDuration: inertia,
1761
- transitionEasing: INERTIA_EASING
1762
- },
1763
- {
1764
- isDragging: false,
1765
- isPanning: true
1766
- }
1767
- );
1768
- } else {
1769
- const currentControllerState = this.controllerState;
1770
- const constraintContext = this._getConstraintContext("pan", "end");
1771
- const newControllerState = currentControllerState.panEnd(constraintContext);
1772
- const reboundTransition = this._getReboundTransition(constraintContext, newControllerState);
1773
- this.updateViewport(newControllerState, reboundTransition, {
1774
- isDragging: false,
1775
- isPanning: Boolean(reboundTransition)
1776
- });
1777
- }
1778
- return true;
1779
- }
1780
- // Default handler for panning to rotate.
1781
- // Called by `_onPan` when panning with function key pressed.
1782
- _onPanRotate(event) {
1783
- if (!this.dragRotate) {
1784
- return false;
1785
- }
1786
- const pos = this.getCenter(event);
1787
- const newControllerState = this.controllerState.rotate(
1788
- { pos },
1789
- this._getConstraintContext("rotate", "update")
1790
- );
1791
- this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
1792
- isDragging: true,
1793
- isRotating: true
1794
- });
1795
- return true;
1796
- }
1797
- _onPanRotateEnd(event) {
1798
- const { inertia } = this;
1799
- if (this.dragRotate && inertia && event.velocity) {
1800
- const pos = this.getCenter(event);
1801
- const endPos = [
1802
- pos[0] + event.velocityX * inertia / 2,
1803
- pos[1] + event.velocityY * inertia / 2
1804
- ];
1805
- const newControllerState = this.controllerState.rotate({ pos: endPos }).rotateEnd();
1806
- this.updateViewport(
1807
- newControllerState,
1808
- {
1809
- ...this._getTransitionProps(),
1810
- transitionDuration: inertia,
1811
- transitionEasing: INERTIA_EASING
1812
- },
1813
- {
1814
- isDragging: false,
1815
- isRotating: true
1816
- }
1817
- );
1818
- } else {
1819
- const currentControllerState = this.controllerState;
1820
- const constraintContext = this._getConstraintContext("rotate", "end");
1821
- const newControllerState = currentControllerState.rotateEnd(constraintContext);
1822
- const reboundTransition = this._getReboundTransition(constraintContext, newControllerState);
1823
- this.updateViewport(newControllerState, reboundTransition, {
1824
- isDragging: false,
1825
- isRotating: Boolean(reboundTransition)
1826
- });
1827
- }
1828
- return true;
1829
- }
1830
- // Default handler for the `wheel` event.
1831
- _onWheel(event) {
1832
- if (!this.scrollZoom) {
1833
- return false;
1834
- }
1835
- if (this.trackpadGesture && event.device !== "mouse") {
1836
- return false;
1837
- }
1838
- const pos = this.getCenter(event);
1839
- if (!this.isPointInBounds(pos, event)) {
1840
- return false;
1841
- }
1842
- event.srcEvent.preventDefault();
1843
- const { speed = 0.01, smooth = false } = this.scrollZoom === true ? {} : this.scrollZoom;
1844
- const { delta } = event;
1845
- let scale = 2 / (1 + Math.exp(-Math.abs(delta * speed)));
1846
- if (delta < 0 && scale !== 0) {
1847
- scale = 1 / scale;
1848
- }
1849
- const zoomPosition = this.getZoomPosition(pos);
1850
- const transitionProps = smooth ? { ...this._getTransitionProps({ around: zoomPosition }), transitionDuration: 250 } : NO_TRANSITION_PROPS;
1851
- const newControllerState = this.controllerState.zoom({ pos: zoomPosition, scale });
1852
- this.updateViewport(newControllerState, transitionProps, {
1853
- isZooming: true,
1854
- isPanning: true
1855
- });
1856
- if (!smooth) {
1857
- this._setInteractionState({ isZooming: false, isPanning: false });
1858
- }
1859
- return true;
1860
- }
1861
- _onMultiPanStart(event) {
1862
- const { multiTouchDrag } = this;
1863
- if (!multiTouchDrag || !this._isMultiPanEventAllowed(event, multiTouchDrag)) {
1864
- return false;
1865
- }
1866
- const currentCenter = event.offsetCenter;
1867
- if (!this.isPointInBounds(this.getCenter(event), event)) {
1868
- return false;
1869
- }
1870
- const isTrackpad = event.pointerType === "trackpad";
1871
- const startCenter = {
1872
- x: currentCenter.x - (isTrackpad ? 0 : event.deltaX),
1873
- y: currentCenter.y - (isTrackpad ? 0 : event.deltaY)
1874
- };
1875
- const startEvent = { ...event, offsetCenter: startCenter };
1876
- const pos = this.getCenter(startEvent);
1877
- const newControllerState = multiTouchDrag === "pan" ? this.controllerState.panStart({ pos }, this._getConstraintContext("pan", "start")) : this.controllerState.rotateStart({ pos }, this._getConstraintContext("rotate", "start"));
1878
- this._multiPanMode = multiTouchDrag;
1879
- this._multiPanStartCenter = startCenter;
1880
- this.updateViewport(newControllerState, NO_TRANSITION_PROPS, { isDragging: true });
1881
- return true;
1882
- }
1883
- _onMultiPan(event) {
1884
- const { mode, event: panEvent } = this._getMultiPanEvent(event);
1885
- if (!mode || !panEvent || !this.isDragging()) {
1886
- return false;
1887
- }
1888
- return mode === "pan" ? this._onPanMove(panEvent) : this._onPanRotate(panEvent);
1889
- }
1890
- _onMultiPanEnd(event) {
1891
- const { mode, event: panEvent } = this._getMultiPanEvent(event);
1892
- if (!mode || !panEvent || !this.isDragging()) {
1893
- this._resetMultiPan();
1894
- return false;
1895
- }
1896
- const handled = mode === "pan" ? this._onPanMoveEnd(panEvent) : this._onPanRotateEnd(panEvent);
1897
- this._resetMultiPan();
1898
- return handled;
1899
- }
1900
- _isTrackpadGestureAllowed(event) {
1901
- return event.pointerType !== "trackpad" || this.trackpadGesture;
1902
- }
1903
- _isMultiPanEventAllowed(event, mode) {
1904
- if (event.pointerType === "trackpad") {
1905
- return this.trackpadGesture && (mode === "pan" ? this.dragPan : this.dragRotate);
1906
- }
1907
- return event.pointerType === "touch" && (mode === "pan" ? this.dragPan : this.dragRotate);
1908
- }
1909
- _getMultiPanEvent(event) {
1910
- const mode = this._multiPanMode;
1911
- const startCenter = this._multiPanStartCenter;
1912
- if (!mode || !startCenter) {
1913
- return { mode: null, event: null };
1914
- }
1915
- return {
1916
- mode,
1917
- event: {
1918
- ...event,
1919
- offsetCenter: {
1920
- x: startCenter.x + event.deltaX,
1921
- y: startCenter.y + event.deltaY
1922
- }
1923
- }
1924
- };
1925
- }
1926
- _resetMultiPan() {
1927
- this._multiPanMode = null;
1928
- this._multiPanStartCenter = null;
1929
- }
1930
- // Default handler for the `pinchstart` event.
1931
- _onPinchStart(event) {
1932
- this._doubleClickDragAnchor = null;
1933
- const pos = this.getCenter(event);
1934
- if (!this.isPointInBounds(pos, event)) {
1935
- return false;
1936
- }
1937
- const newControllerState = this.controllerState.zoomStart({ pos: this.getZoomPosition(pos) }, this._getConstraintContext("zoom", "start")).rotateStart({ pos }, this._getConstraintContext("rotate", "start"));
1938
- pinchEventWorkaround._startPinchRotation = event.rotation;
1939
- pinchEventWorkaround._lastPinchEvent = event;
1940
- this.updateViewport(newControllerState, NO_TRANSITION_PROPS, { isDragging: true });
1941
- return true;
1942
- }
1943
- // Default handler for the `pinchmove` and `pinchend` events.
1944
- _onPinch(event) {
1945
- if (!this.touchZoom && !this.touchRotate) {
1946
- return false;
1947
- }
1948
- if (!this.isDragging()) {
1949
- return false;
1950
- }
1951
- let newControllerState = this.controllerState;
1952
- if (this.touchZoom) {
1953
- const { scale } = event;
1954
- const pos = this.getCenter(event);
1955
- newControllerState = newControllerState.zoom(
1956
- { pos: this.getZoomPosition(pos), scale },
1957
- this._getConstraintContext("zoom", "update")
1958
- );
1959
- }
1960
- if (this.touchRotate) {
1961
- const { rotation } = event;
1962
- newControllerState = newControllerState.rotate(
1963
- { deltaAngleX: pinchEventWorkaround._startPinchRotation - rotation },
1964
- this._getConstraintContext("rotate", "update")
1965
- );
1966
- }
1967
- this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
1968
- isDragging: true,
1969
- isPanning: this.touchZoom,
1970
- isZooming: this.touchZoom,
1971
- isRotating: this.touchRotate
1972
- });
1973
- pinchEventWorkaround._lastPinchEvent = event;
1974
- return true;
1975
- }
1976
- _onPinchEnd(event) {
1977
- if (!this.isDragging()) {
1978
- return false;
1979
- }
1980
- const { inertia } = this;
1981
- const { _lastPinchEvent } = pinchEventWorkaround;
1982
- if (this.touchZoom && inertia && _lastPinchEvent && event.scale !== _lastPinchEvent.scale) {
1983
- const pos = this.getCenter(event);
1984
- const zoomPosition = this.getZoomPosition(pos);
1985
- let newControllerState = this.controllerState.rotateEnd();
1986
- const z = Math.log2(event.scale);
1987
- const velocityZ = (z - Math.log2(_lastPinchEvent.scale)) / (event.deltaTime - _lastPinchEvent.deltaTime);
1988
- const endScale = Math.pow(2, z + velocityZ * inertia / 2);
1989
- newControllerState = newControllerState.zoom({ pos: zoomPosition, scale: endScale }).zoomEnd();
1990
- this.updateViewport(
1991
- newControllerState,
1992
- {
1993
- ...this._getTransitionProps({ around: zoomPosition }),
1994
- transitionDuration: inertia,
1995
- transitionEasing: INERTIA_EASING
1996
- },
1997
- {
1998
- isDragging: false,
1999
- isPanning: this.touchZoom,
2000
- isZooming: this.touchZoom,
2001
- isRotating: false
2002
- }
2003
- );
2004
- this.blockEvents(inertia);
2005
- } else {
2006
- const currentControllerState = this.controllerState;
2007
- const zoomConstraintContext = this._getConstraintContext("zoom", "end");
2008
- const rotateConstraintContext = this._getConstraintContext("rotate", "end");
2009
- const newControllerState = currentControllerState.zoomEnd(zoomConstraintContext).rotateEnd(rotateConstraintContext);
2010
- const reboundTransition = this._getReboundTransition(
2011
- this.touchZoom ? zoomConstraintContext : rotateConstraintContext,
2012
- newControllerState
2013
- );
2014
- this.updateViewport(newControllerState, reboundTransition, {
2015
- isDragging: false,
2016
- isPanning: Boolean(reboundTransition) && this.touchZoom,
2017
- isZooming: Boolean(reboundTransition) && this.touchZoom,
2018
- isRotating: Boolean(reboundTransition) && this.touchRotate
2019
- });
2020
- }
2021
- pinchEventWorkaround._startPinchRotation = null;
2022
- pinchEventWorkaround._lastPinchEvent = null;
2023
- return true;
2024
- }
2025
- // Default handler for the `dblclick` event.
2026
- _onDoubleClick(event) {
2027
- if (!this.doubleClickZoom) {
2028
- return false;
2029
- }
2030
- if (Date.now() < this._suppressDoubleClickUntil) {
2031
- return false;
2032
- }
2033
- const pos = this.getCenter(event);
2034
- if (!this.isPointInBounds(pos, event)) {
2035
- return false;
2036
- }
2037
- const isZoomOut = this.isFunctionKeyPressed(event);
2038
- const zoomPosition = this.getZoomPosition(pos);
2039
- const newControllerState = this.controllerState.zoom({
2040
- pos: zoomPosition,
2041
- scale: isZoomOut ? 0.5 : 2
2042
- });
2043
- this.updateViewport(newControllerState, this._getTransitionProps({ around: zoomPosition }), {
2044
- isZooming: true,
2045
- isPanning: true
2046
- });
2047
- this.blockEvents(100);
2048
- return true;
2049
- }
2050
- _onDoubleClickDragStart(event) {
2051
- if (!this.doubleClickDragZoom) {
2052
- this._doubleClickDragAnchor = null;
2053
- return false;
2054
- }
2055
- const pos = this.getCenter(event);
2056
- if (!this.isPointInBounds(pos, event)) {
2057
- this._doubleClickDragAnchor = null;
2058
- return false;
2059
- }
2060
- this._doubleClickDragAnchor = this.getZoomPosition(pos);
2061
- let newControllerState = this.controllerState.zoomStart(
2062
- { pos: this._doubleClickDragAnchor },
2063
- this._getConstraintContext("zoom", "start")
2064
- );
2065
- if (event.scale !== 1) {
2066
- newControllerState = newControllerState.zoom(
2067
- { pos: this._doubleClickDragAnchor, scale: event.scale },
2068
- this._getConstraintContext("zoom", "update")
2069
- );
2070
- }
2071
- this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
2072
- isDragging: true,
2073
- isPanning: true,
2074
- isZooming: true
2075
- });
2076
- return true;
2077
- }
2078
- _onDoubleClickDrag(event) {
2079
- const pos = this._doubleClickDragAnchor;
2080
- if (!pos) {
2081
- return false;
2082
- }
2083
- const newControllerState = this.controllerState.zoom(
2084
- { pos, scale: event.scale },
2085
- this._getConstraintContext("zoom", "update")
2086
- );
2087
- this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
2088
- isDragging: true,
2089
- isPanning: true,
2090
- isZooming: true
2091
- });
2092
- return true;
2093
- }
2094
- _onDoubleClickDragEnd(_event) {
2095
- const pos = this._doubleClickDragAnchor;
2096
- if (!pos) {
2097
- return false;
2098
- }
2099
- this._doubleClickDragAnchor = null;
2100
- const currentControllerState = this.controllerState;
2101
- const constraintContext = this._getConstraintContext("zoom", "end");
2102
- const newControllerState = currentControllerState.zoomEnd(constraintContext);
2103
- const reboundTransition = this._getReboundTransition(constraintContext, newControllerState);
2104
- this.updateViewport(newControllerState, reboundTransition, {
2105
- isDragging: false,
2106
- isPanning: Boolean(reboundTransition),
2107
- isZooming: Boolean(reboundTransition)
2108
- });
2109
- this._suppressDoubleClickUntil = Date.now() + 100;
2110
- this.blockEvents(100);
2111
- return true;
2112
- }
2113
- // Default handler for the `keydown` event
2114
- _onKeyDown(event) {
2115
- if (!this.keyboard) {
2116
- return false;
2117
- }
2118
- const funcKey = this.isFunctionKeyPressed(event);
2119
- const { zoomSpeed, moveSpeed, rotateSpeedX, rotateSpeedY } = this.keyboard === true ? {} : this.keyboard;
2120
- const { controllerState } = this;
2121
- let newControllerState;
2122
- const interactionState = {};
2123
- switch (event.srcEvent.code) {
2124
- case "Minus":
2125
- newControllerState = funcKey ? controllerState.zoomOut(zoomSpeed).zoomOut(zoomSpeed) : controllerState.zoomOut(zoomSpeed);
2126
- interactionState.isZooming = true;
2127
- break;
2128
- case "Equal":
2129
- newControllerState = funcKey ? controllerState.zoomIn(zoomSpeed).zoomIn(zoomSpeed) : controllerState.zoomIn(zoomSpeed);
2130
- interactionState.isZooming = true;
2131
- break;
2132
- case "ArrowLeft":
2133
- if (funcKey) {
2134
- newControllerState = controllerState.rotateLeft(rotateSpeedX);
2135
- interactionState.isRotating = true;
2136
- } else {
2137
- newControllerState = controllerState.moveLeft(moveSpeed);
2138
- interactionState.isPanning = true;
2139
- }
2140
- break;
2141
- case "ArrowRight":
2142
- if (funcKey) {
2143
- newControllerState = controllerState.rotateRight(rotateSpeedX);
2144
- interactionState.isRotating = true;
2145
- } else {
2146
- newControllerState = controllerState.moveRight(moveSpeed);
2147
- interactionState.isPanning = true;
2148
- }
2149
- break;
2150
- case "ArrowUp":
2151
- if (funcKey) {
2152
- newControllerState = controllerState.rotateUp(rotateSpeedY);
2153
- interactionState.isRotating = true;
2154
- } else {
2155
- newControllerState = controllerState.moveUp(moveSpeed);
2156
- interactionState.isPanning = true;
2157
- }
2158
- break;
2159
- case "ArrowDown":
2160
- if (funcKey) {
2161
- newControllerState = controllerState.rotateDown(rotateSpeedY);
2162
- interactionState.isRotating = true;
2163
- } else {
2164
- newControllerState = controllerState.moveDown(moveSpeed);
2165
- interactionState.isPanning = true;
2166
- }
2167
- break;
2168
- default:
2169
- return false;
2170
- }
2171
- this.updateViewport(newControllerState, this._getTransitionProps(), interactionState);
2172
- return true;
2173
- }
2174
- _getTransitionProps(opts) {
2175
- const { transition } = this;
2176
- if (!transition || !transition.transitionInterpolator) {
2177
- return NO_TRANSITION_PROPS;
2178
- }
2179
- return opts ? {
2180
- ...transition,
2181
- transitionInterpolator: new LinearInterpolator({
2182
- ...opts,
2183
- ...transition.transitionInterpolator.opts,
2184
- makeViewport: this.controllerState.makeViewport
2185
- })
2186
- } : transition;
2187
- }
2188
- };
2189
-
2190
- // ../core/src/controllers/view-state.ts
2191
- var CONSTRAINT_AROUND = /* @__PURE__ */ Symbol("constraintAround");
2192
- var ViewState = class {
2193
- constructor(props, state, makeViewport, constraintContext) {
2194
- this.makeViewport = makeViewport;
2195
- this._viewportProps = this.applyConstraints(props, constraintContext);
2196
- this._state = state;
2197
- }
2198
- getViewportProps() {
2199
- return this._viewportProps;
2200
- }
2201
- getState() {
2202
- return this._state;
2203
- }
2204
- };
2205
-
2206
- // ../core/src/controllers/utils.ts
2207
- function applyRubberBand(value, constrainedValue, range) {
2208
- const overshoot = value - constrainedValue;
2209
- return overshoot && Number.isFinite(overshoot) ? constrainedValue + overshoot * range / (range + Math.abs(overshoot)) : constrainedValue;
2210
- }
2211
- function getMaxBoundsRect(width, height, padding) {
2212
- const left = getPosition(parsePosition((padding == null ? void 0 : padding.left) ?? 0), width);
2213
- const right = getPosition(parsePosition((padding == null ? void 0 : padding.right) ?? 0), width);
2214
- const top = getPosition(parsePosition((padding == null ? void 0 : padding.top) ?? 0), height);
2215
- const bottom = getPosition(parsePosition((padding == null ? void 0 : padding.bottom) ?? 0), height);
2216
- return {
2217
- x: left,
2218
- y: top,
2219
- width: width - left - right,
2220
- height: height - top - bottom
2221
- };
2222
- }
2223
- function getMaxBoundsExtents(viewport, target, rect) {
2224
- let [x, y] = viewport.project(target);
2225
- x = Number.isFinite(x) ? x : viewport.width / 2;
2226
- y = Number.isFinite(y) ? y : viewport.height / 2;
2227
- return {
2228
- left: x - rect.x,
2229
- right: rect.x + rect.width - x,
2230
- top: y - rect.y,
2231
- bottom: rect.y + rect.height - y
2232
- };
2233
- }
2234
-
2235
- // ../core/src/utils/apply-styles.ts
2236
- function applyStyles(element, style) {
2237
- if (style) {
2238
- Object.entries(style).map(([key, value]) => {
2239
- if (key.startsWith("--")) {
2240
- element.style.setProperty(key, value);
2241
- } else {
2242
- element.style[key] = value;
2243
- }
2244
- });
2245
- }
2246
- }
2247
- function removeStyles(element, style) {
2248
- if (style) {
2249
- Object.keys(style).map((key) => {
2250
- if (key.startsWith("--")) {
2251
- element.style.removeProperty(key);
2252
- } else {
2253
- element.style[key] = "";
2254
- }
2255
- });
2256
- }
2257
- }
2258
-
2259
- // ../core/src/lib/widget.ts
2260
- var Widget = class {
2261
- constructor(props) {
2262
- /**
2263
- * The view id that this widget controls and is positioned relative to. Default `null`.
2264
- * If assigned, this widget only responds to events inside the matching view. In multi-canvas
2265
- * mode, the view's `canvasId` determines the positioning offset, but the widget DOM remains
2266
- * under the shared widget root.
2267
- */
2268
- this.viewId = null;
2269
- this.props = {
2270
- // @ts-expect-error `defaultProps` may not exist on constructor
2271
- ...this.constructor.defaultProps,
2272
- ...props
2273
- };
2274
- this.id = this.props.id;
2275
- }
2276
- /** Called to update widget options */
2277
- setProps(props) {
2278
- const oldProps = this.props;
2279
- const el = this.rootElement;
2280
- if (el && oldProps.className !== props.className) {
2281
- if (oldProps.className) el.classList.remove(oldProps.className);
2282
- if (props.className) el.classList.add(props.className);
2283
- }
2284
- if (el && !deepEqual(oldProps.style, props.style, 1)) {
2285
- removeStyles(el, oldProps.style);
2286
- applyStyles(el, props.style);
2287
- }
2288
- Object.assign(this.props, props);
2289
- this.updateHTML();
2290
- }
2291
- /** Update the HTML to reflect latest props and state */
2292
- updateHTML() {
2293
- if (this.rootElement) {
2294
- this.onRenderHTML(this.rootElement);
2295
- }
2296
- }
2297
- // VIEW STATE HELPERS
2298
- get viewIds() {
2299
- var _a;
2300
- return this.viewId ? [this.viewId] : ((_a = this.deck) == null ? void 0 : _a.getViews().map((v) => v.id)) ?? [];
2301
- }
2302
- /** Returns the current view state for the given view */
2303
- getViewState(viewId) {
2304
- var _a, _b;
2305
- return ((_b = (_a = this.deck) == null ? void 0 : _a.viewManager) == null ? void 0 : _b.getViewState(viewId)) || {};
2306
- }
2307
- /** Updates the view state for the given view */
2308
- setViewState(viewId, viewState) {
2309
- var _a;
2310
- (_a = this.deck) == null ? void 0 : _a._onViewStateChange({ viewId, viewState, interactionState: {} });
2311
- }
2312
- // @note empty method calls have an overhead in V8 but it is very low, ~1ns
2313
- /**
2314
- * Common utility to create the root DOM element for this widget
2315
- * Configures the top-level styles and adds basic class names for theming
2316
- * @returns an UI element that should be appended to the Deck container
2317
- */
2318
- onCreateRootElement() {
2319
- const CLASS_NAMES = [
2320
- // Add class names for theming
2321
- "deck-widget",
2322
- this.className,
2323
- // plus any app-supplied class name
2324
- this.props.className
2325
- ];
2326
- const element = document.createElement("div");
2327
- CLASS_NAMES.filter((cls) => typeof cls === "string" && cls.length > 0).forEach(
2328
- (className) => element.classList.add(className)
2329
- );
2330
- applyStyles(element, this.props.style);
2331
- return element;
2332
- }
2333
- /** Internal API called by Deck when the widget is first added to a Deck instance */
2334
- _onAdd(params) {
2335
- return this.onAdd(params) ?? this.onCreateRootElement();
2336
- }
2337
- /** Overridable by subclass - called when the widget is first added to a Deck instance
2338
- * @returns an optional UI element that should be appended to the Deck container
2339
- */
2340
- onAdd(params) {
2341
- }
2342
- /** Called when the widget is removed */
2343
- onRemove() {
2344
- }
2345
- // deck integration - Event hooks
2346
- /** Called when the containing view is changed */
2347
- onViewportChange(viewport) {
2348
- }
2349
- /** Called when the containing view is redrawn */
2350
- onRedraw(params) {
2351
- }
2352
- /** Called when a hover event occurs */
2353
- onHover(info, event) {
2354
- }
2355
- /** Called when a click event occurs */
2356
- onClick(info, event) {
2357
- }
2358
- /** Called when a drag event occurs */
2359
- onDrag(info, event) {
2360
- }
2361
- /** Called when a dragstart event occurs */
2362
- onDragStart(info, event) {
2363
- }
2364
- /** Called when a dragend event occurs */
2365
- onDragEnd(info, event) {
2366
- }
2367
- };
2368
- Widget.defaultProps = {
2369
- id: "widget",
2370
- style: {},
2371
- _container: null,
2372
- className: ""
2373
- };
2374
-
2375
- // ../core/src/viewports/globe-viewport.ts
2376
- var import_core6 = require("@math.gl/core");
2377
- var import_web_mercator4 = require("@math.gl/web-mercator");
2378
- var DEGREES_TO_RADIANS2 = Math.PI / 180;
2379
- var RADIANS_TO_DEGREES = 180 / Math.PI;
2380
- var NORTH_UP_BEARING_THRESHOLD = 1;
2381
- var EARTH_RADIUS = 6370972;
2382
- var GLOBE_RADIUS = 256;
2383
- var GLOBE_ZOOM_ANCHOR_DAMPING_START_RATIO = 0.75;
2384
- var GLOBE_ZOOM_ANCHOR_MAX_DISTANCE_RATIO = 1.15;
2385
- function isGlobeNorthUp(bearing) {
2386
- const normalizedBearing = mod(bearing + 180, 360) - 180;
2387
- return Math.abs(normalizedBearing) < NORTH_UP_BEARING_THRESHOLD;
2388
- }
2389
- function getDistanceScales2() {
2390
- const unitsPerMeter2 = GLOBE_RADIUS / EARTH_RADIUS;
2391
- const unitsPerDegree = Math.PI / 180 * GLOBE_RADIUS;
2392
- return {
2393
- unitsPerMeter: [unitsPerMeter2, unitsPerMeter2, unitsPerMeter2],
2394
- unitsPerMeter2: [0, 0, 0],
2395
- metersPerUnit: [1 / unitsPerMeter2, 1 / unitsPerMeter2, 1 / unitsPerMeter2],
2396
- unitsPerDegree: [unitsPerDegree, unitsPerDegree, unitsPerMeter2],
2397
- unitsPerDegree2: [0, 0, 0],
2398
- degreesPerUnit: [1 / unitsPerDegree, 1 / unitsPerDegree, 1 / unitsPerMeter2]
2399
- };
2400
- }
2401
- var GlobeViewport = class extends Viewport {
2402
- constructor(opts = {}) {
2403
- const {
2404
- longitude = 0,
2405
- bearing = 0,
2406
- pitch = 0,
2407
- zoom = 0,
2408
- // Matches Maplibre defaults
2409
- // https://github.com/maplibre/maplibre-gl-js/blob/f8ab4b48d59ab8fe7b068b102538793bbdd4c848/src/geo/projection/globe_transform.ts#L632-L633
2410
- nearZMultiplier = 0.5,
2411
- farZMultiplier = 1,
2412
- resolution = 10
2413
- } = opts;
2414
- let { latitude = 0, height, altitude = 1.5, fovy } = opts;
2415
- latitude = Math.max(Math.min(latitude, 90), -90);
2416
- height = height || 1;
2417
- if (fovy) {
2418
- altitude = (0, import_web_mercator4.fovyToAltitude)(fovy);
2419
- } else {
2420
- fovy = (0, import_web_mercator4.altitudeToFovy)(altitude);
2421
- }
2422
- const scaleLatitude = Math.max(Math.min(latitude, import_web_mercator4.MAX_LATITUDE), -import_web_mercator4.MAX_LATITUDE);
2423
- const scale = Math.pow(2, zoom - zoomAdjust(scaleLatitude));
2424
- const pitchRadians = pitch * DEGREES_TO_RADIANS2;
2425
- const nearZ = opts.nearZ ?? nearZMultiplier;
2426
- const farZ = opts.farZ ?? (altitude + GLOBE_RADIUS * 2 * scale / height / Math.max(Math.cos(pitchRadians), 0.1)) * farZMultiplier;
2427
- const viewMatrix2 = new import_core6.Matrix4().lookAt({ eye: [0, -altitude, 0], up: [0, 0, 1] }).rotateX(-pitchRadians).rotateY(-bearing * DEGREES_TO_RADIANS2).rotateX(latitude * DEGREES_TO_RADIANS2).rotateZ(-longitude * DEGREES_TO_RADIANS2).scale(scale / height);
2428
- super({
2429
- ...opts,
2430
- // x, y, width,
2431
- height,
2432
- // view matrix
2433
- viewMatrix: viewMatrix2,
2434
- longitude,
2435
- latitude,
2436
- zoom,
2437
- // projection matrix parameters
2438
- distanceScales: getDistanceScales2(),
2439
- fovy,
2440
- focalDistance: altitude,
2441
- near: nearZ,
2442
- far: farZ
2443
- });
2444
- this.scale = scale;
2445
- this.latitude = latitude;
2446
- this.longitude = longitude;
2447
- this.bearing = bearing;
2448
- this.pitch = pitch;
2449
- this.fovy = fovy;
2450
- this.resolution = resolution;
2451
- }
2452
- get projectionMode() {
2453
- return PROJECTION_MODE.GLOBE;
2454
- }
2455
- getDistanceScales() {
2456
- return this.distanceScales;
2457
- }
2458
- getBounds(options = {}) {
2459
- const unprojectOption = { targetZ: options.z || 0 };
2460
- const left = this.unproject([0, this.height / 2], unprojectOption);
2461
- const top = this.unproject([this.width / 2, 0], unprojectOption);
2462
- const right = this.unproject([this.width, this.height / 2], unprojectOption);
2463
- const bottom = this.unproject([this.width / 2, this.height], unprojectOption);
2464
- if (right[0] < this.longitude) right[0] += 360;
2465
- if (left[0] > this.longitude) left[0] -= 360;
2466
- return [
2467
- Math.min(left[0], right[0], top[0], bottom[0]),
2468
- Math.min(left[1], right[1], top[1], bottom[1]),
2469
- Math.max(left[0], right[0], top[0], bottom[0]),
2470
- Math.max(left[1], right[1], top[1], bottom[1])
2471
- ];
2472
- }
2473
- /**
2474
- * Builds the screen-pixel → globe-center ray and the intermediate ray/sphere
2475
- * math reused by `unproject` and anchored zoom. One function so the same
2476
- * pixelUnprojectionMatrix work isn't duplicated.
2477
- */
2478
- _getRayToGlobe(screenPosition, { topLeft = true, targetZ } = {}) {
2479
- const [screenX, screenY] = screenPosition;
2480
- const adjustedScreenY = topLeft ? screenY : this.height - screenY;
2481
- const { pixelUnprojectionMatrix } = this;
2482
- const rayStartPosition = transformVector(pixelUnprojectionMatrix, [
2483
- screenX,
2484
- adjustedScreenY,
2485
- -1,
2486
- 1
2487
- ]);
2488
- const rayEndPosition = transformVector(pixelUnprojectionMatrix, [
2489
- screenX,
2490
- adjustedScreenY,
2491
- 1,
2492
- 1
2493
- ]);
2494
- const radius = ((targetZ || 0) / EARTH_RADIUS + 1) * GLOBE_RADIUS;
2495
- const rayLengthSquared = import_core6.vec3.sqrLen(import_core6.vec3.sub([], rayStartPosition, rayEndPosition));
2496
- const rayStartDistanceSquared = import_core6.vec3.sqrLen(rayStartPosition);
2497
- const rayEndDistanceSquared = import_core6.vec3.sqrLen(rayEndPosition);
2498
- const triangleAreaSquared = (4 * rayStartDistanceSquared * rayEndDistanceSquared - (rayLengthSquared - rayStartDistanceSquared - rayEndDistanceSquared) ** 2) / 16;
2499
- const distanceToCenterSquared = 4 * triangleAreaSquared / rayLengthSquared;
2500
- return {
2501
- rayStartPosition,
2502
- rayEndPosition,
2503
- radius,
2504
- rayLengthSquared,
2505
- rayStartDistanceSquared,
2506
- distanceToCenterSquared
2507
- };
2508
- }
2509
- _getRayDistanceToGlobeCenterRatio(screenPosition, options) {
2510
- const { distanceToCenterSquared, radius } = this._getRayToGlobe(screenPosition, options);
2511
- return Math.sqrt(Math.max(0, distanceToCenterSquared)) / radius;
2512
- }
2513
- /**
2514
- * Returns how strongly a screen position should anchor zoom on the visible globe.
2515
- * A value of `0` means that the controller should fall back to center zoom.
2516
- * @param screenPosition - Screen position to evaluate.
2517
- * @returns Anchor strength from `0` to `1`.
2518
- */
2519
- getZoomAnchorStrength(screenPosition) {
2520
- const distanceRatio = this._getRayDistanceToGlobeCenterRatio(screenPosition);
2521
- if (distanceRatio >= GLOBE_ZOOM_ANCHOR_MAX_DISTANCE_RATIO) {
2522
- return 0;
2523
- }
2524
- const edgeProgress = Math.max(
2525
- 0,
2526
- Math.min(
2527
- 1,
2528
- (distanceRatio - GLOBE_ZOOM_ANCHOR_DAMPING_START_RATIO) / (GLOBE_ZOOM_ANCHOR_MAX_DISTANCE_RATIO - GLOBE_ZOOM_ANCHOR_DAMPING_START_RATIO)
2529
- )
2530
- );
2531
- const smoothProgress = edgeProgress * edgeProgress * (3 - 2 * edgeProgress);
2532
- return 1 - smoothProgress;
2533
- }
2534
- unproject(xyz, { topLeft = true, targetZ } = {}) {
2535
- const [x, y, z] = xyz;
2536
- const y2 = topLeft ? y : this.height - y;
2537
- const { pixelUnprojectionMatrix } = this;
2538
- let coord;
2539
- if (Number.isFinite(z)) {
2540
- coord = transformVector(pixelUnprojectionMatrix, [x, y2, z, 1]);
2541
- } else {
2542
- const {
2543
- rayStartPosition,
2544
- rayEndPosition,
2545
- radius,
2546
- rayLengthSquared,
2547
- rayStartDistanceSquared,
2548
- distanceToCenterSquared
2549
- } = this._getRayToGlobe(xyz, { topLeft, targetZ });
2550
- const rayStartToClosestApproach = Math.sqrt(
2551
- rayStartDistanceSquared - distanceToCenterSquared
2552
- );
2553
- const closestApproachToIntersection = Math.sqrt(
2554
- Math.max(0, radius * radius - distanceToCenterSquared)
2555
- );
2556
- const intersectionRatio = (rayStartToClosestApproach - closestApproachToIntersection) / Math.sqrt(rayLengthSquared);
2557
- coord = import_core6.vec3.lerp([], rayStartPosition, rayEndPosition, intersectionRatio);
2558
- }
2559
- const [X, Y, Z] = this.unprojectPosition(coord);
2560
- if (Number.isFinite(z)) {
2561
- return [X, Y, Z];
2562
- }
2563
- return Number.isFinite(targetZ) ? [X, Y, targetZ] : [X, Y];
2564
- }
2565
- projectPosition(xyz) {
2566
- const [lng, lat, Z = 0] = xyz;
2567
- const lambda = lng * DEGREES_TO_RADIANS2;
2568
- const phi = lat * DEGREES_TO_RADIANS2;
2569
- const cosPhi = Math.cos(phi);
2570
- const D = (Z / EARTH_RADIUS + 1) * GLOBE_RADIUS;
2571
- return [Math.sin(lambda) * cosPhi * D, -Math.cos(lambda) * cosPhi * D, Math.sin(phi) * D];
2572
- }
2573
- unprojectPosition(xyz) {
2574
- const [x, y, z] = xyz;
2575
- const D = import_core6.vec3.len(xyz);
2576
- const phi = Math.asin(z / D);
2577
- const lambda = Math.atan2(x, -y);
2578
- const lng = lambda * RADIANS_TO_DEGREES;
2579
- const lat = phi * RADIANS_TO_DEGREES;
2580
- const Z = (D / GLOBE_RADIUS - 1) * EARTH_RADIUS;
2581
- return [lng, lat, Z];
2582
- }
2583
- projectFlat(xyz) {
2584
- return xyz;
2585
- }
2586
- unprojectFlat(xyz) {
2587
- return xyz;
2588
- }
2589
- /**
2590
- * Pan the globe to place geographic coordinates at a screen pixel.
2591
- * When `dragStartPosition` is supplied, applies the delta-based movement used by globe dragging.
2592
- * @param coordinates - Geographic anchor, or the starting longitude, latitude and zoom.
2593
- * @param screenPosition - Current screen position.
2594
- * @param dragStartPosition - Screen position where a drag started.
2595
- * @returns Updated viewport options.
2596
- */
2597
- panByPosition(coordinates, screenPosition, dragStartPosition) {
2598
- if (!dragStartPosition) {
2599
- let anchorStrength = this.getZoomAnchorStrength(screenPosition);
2600
- if (anchorStrength === 0) {
2601
- return { longitude: this.longitude, latitude: this.latitude };
2602
- }
2603
- const currentCoordinates = this.unproject(screenPosition);
2604
- const longitudeDelta = mod(coordinates[0] - currentCoordinates[0] + 180, 360) - 180;
2605
- const latitudeDelta = coordinates[1] - currentCoordinates[1];
2606
- const crossesPole = Math.abs(currentCoordinates[1]) > import_web_mercator4.MAX_LATITUDE || Math.abs(longitudeDelta) > 90;
2607
- if (isGlobeNorthUp(this.bearing) && crossesPole) {
2608
- return { longitude: this.longitude, latitude: this.latitude };
2609
- }
2610
- if (isGlobeNorthUp(this.bearing) && latitudeDelta !== 0) {
2611
- const latitudeLimit = latitudeDelta > 0 ? import_web_mercator4.MAX_LATITUDE : -import_web_mercator4.MAX_LATITUDE;
2612
- const latitudeConstraintStrength = (latitudeLimit - this.latitude) / latitudeDelta;
2613
- anchorStrength = Math.min(anchorStrength, Math.max(0, latitudeConstraintStrength));
2614
- }
2615
- const longitude2 = this.longitude + longitudeDelta * anchorStrength;
2616
- const latitude2 = Math.max(Math.min(this.latitude + latitudeDelta * anchorStrength, 90), -90);
2617
- return { longitude: longitude2, latitude: latitude2 };
2618
- }
2619
- const [startLongitude, startLatitude, startZoom] = coordinates;
2620
- const scale = Math.pow(2, this.zoom - zoomAdjust(this.latitude));
2621
- const rotationSpeed = 0.25 / scale;
2622
- const longitude = startLongitude + rotationSpeed * (dragStartPosition[0] - screenPosition[0]);
2623
- let latitude = startLatitude - rotationSpeed * (dragStartPosition[1] - screenPosition[1]);
2624
- latitude = Math.max(Math.min(latitude, 90), -90);
2625
- const nextViewState = { longitude, latitude, zoom: startZoom - zoomAdjust(startLatitude) };
2626
- nextViewState.zoom += zoomAdjust(nextViewState.latitude);
2627
- return nextViewState;
2628
- }
2629
- };
2630
- GlobeViewport.displayName = "GlobeViewport";
2631
- function zoomAdjust(latitude, clampToPoles) {
2632
- if (clampToPoles) {
2633
- latitude = Math.max(Math.min(latitude, import_web_mercator4.MAX_LATITUDE), -import_web_mercator4.MAX_LATITUDE);
2634
- }
2635
- const scaleAdjust = Math.PI * Math.cos(latitude * Math.PI / 180);
2636
- return Math.log2(scaleAdjust);
2637
- }
2638
- function transformVector(matrix, vector) {
2639
- const result = import_core6.vec4.transformMat4([], vector, matrix);
2640
- import_core6.vec4.scale(result, result, 1 / result[3]);
2641
- return result;
2642
- }
2643
-
2644
- // ../core/src/viewports/orthographic-viewport.ts
2645
- var import_core7 = require("@math.gl/core");
2646
- var import_web_mercator5 = require("@math.gl/web-mercator");
2647
- var viewMatrix = new import_core7.Matrix4().lookAt({ eye: [0, 0, 1] });
2648
- function getProjectionMatrix({
2649
- width,
2650
- height,
2651
- near,
2652
- far,
2653
- padding
2654
- }) {
2655
- let left = -width / 2;
2656
- let right = width / 2;
2657
- let bottom = -height / 2;
2658
- let top = height / 2;
2659
- if (padding) {
2660
- const { left: l = 0, right: r = 0, top: t = 0, bottom: b = 0 } = padding;
2661
- const offsetX = (0, import_core7.clamp)((l + width - r) / 2, 0, width) - width / 2;
2662
- const offsetY = (0, import_core7.clamp)((t + height - b) / 2, 0, height) - height / 2;
2663
- left -= offsetX;
2664
- right -= offsetX;
2665
- bottom += offsetY;
2666
- top += offsetY;
2667
- }
2668
- return new import_core7.Matrix4().ortho({
2669
- left,
2670
- right,
2671
- bottom,
2672
- top,
2673
- near,
2674
- far
2675
- });
2676
- }
2677
- var OrthographicViewport = class extends Viewport {
2678
- constructor(props) {
2679
- const {
2680
- width,
2681
- height,
2682
- near = 0.1,
2683
- far = 1e3,
2684
- zoom = 0,
2685
- target = [0, 0, 0],
2686
- padding = null,
2687
- flipY = true
2688
- } = props;
2689
- const zoomX = props.zoomX ?? (Array.isArray(zoom) ? zoom[0] : zoom);
2690
- const zoomY = props.zoomY ?? (Array.isArray(zoom) ? zoom[1] : zoom);
2691
- const zoom_ = Number.isFinite(props.zoom) ? props.zoom : Math.min(zoomX, zoomY);
2692
- const scale = Math.pow(2, zoom_);
2693
- let distanceScales;
2694
- if (zoomX !== zoom_ || zoomY !== zoom_) {
2695
- const scaleX = Math.pow(2, zoomX);
2696
- const scaleY = Math.pow(2, zoomY);
2697
- distanceScales = {
2698
- unitsPerMeter: [scaleX / scale, scaleY / scale, 1],
2699
- metersPerUnit: [scale / scaleX, scale / scaleY, 1]
2700
- };
2701
- }
2702
- super({
2703
- ...props,
2704
- // in case viewState contains longitude/latitude values,
2705
- // make sure that the base Viewport class does not treat this as a geospatial viewport
2706
- longitude: void 0,
2707
- position: target,
2708
- viewMatrix: viewMatrix.clone().scale([scale, scale * (flipY ? -1 : 1), scale]),
2709
- projectionMatrix: getProjectionMatrix({
2710
- width: width || 1,
2711
- height: height || 1,
2712
- padding,
2713
- near,
2714
- far
2715
- }),
2716
- zoom: zoom_,
2717
- distanceScales
2718
- });
2719
- this.target = target;
2720
- this.zoomX = zoomX;
2721
- this.zoomY = zoomY;
2722
- this.flipY = flipY;
2723
- }
2724
- projectFlat([X, Y]) {
2725
- const { unitsPerMeter: unitsPerMeter2 } = this.distanceScales;
2726
- return [X * unitsPerMeter2[0], Y * unitsPerMeter2[1]];
2727
- }
2728
- unprojectFlat([x, y]) {
2729
- const { metersPerUnit } = this.distanceScales;
2730
- return [x * metersPerUnit[0], y * metersPerUnit[1]];
2731
- }
2732
- /* Needed by LinearInterpolator */
2733
- panByPosition(coords, pixel, startPixel) {
2734
- const fromLocation = (0, import_web_mercator5.pixelsToWorld)(pixel, this.pixelUnprojectionMatrix);
2735
- const toLocation = this.projectFlat(coords);
2736
- const translate = import_core7.vec2.add([], toLocation, import_core7.vec2.negate([], fromLocation));
2737
- const newCenter = import_core7.vec2.add([], this.center, translate);
2738
- return { target: this.unprojectFlat(newCenter) };
2739
- }
2740
- };
2741
- OrthographicViewport.displayName = "OrthographicViewport";
2742
-
2743
- // ../core/src/controllers/orthographic-controller.ts
2744
- var import_core8 = require("@math.gl/core");
2745
- var ZOOM_RUBBER_BAND_RANGE = 1;
2746
- function normalizeZoom({
2747
- zoom = 0,
2748
- zoomX,
2749
- zoomY
2750
- }) {
2751
- zoomX = zoomX ?? (Array.isArray(zoom) ? zoom[0] : zoom);
2752
- zoomY = zoomY ?? (Array.isArray(zoom) ? zoom[1] : zoom);
2753
- return { zoomX, zoomY };
2754
- }
2755
- function getAxisBounds(maxBounds, index, negativeExtent, positiveExtent, target) {
2756
- const minimum = maxBounds[0][index] + negativeExtent;
2757
- const maximum = maxBounds[1][index] - positiveExtent;
2758
- const midpoint = (minimum + maximum) / 2;
2759
- return {
2760
- minimum,
2761
- maximum,
2762
- midpoint,
2763
- settledTarget: Number.isFinite(negativeExtent) && Number.isFinite(positiveExtent) && minimum <= maximum ? (0, import_core8.clamp)(target, minimum, maximum) : midpoint
2764
- };
2765
- }
2766
- var OrthographicState = class extends ViewState {
2767
- constructor(options) {
2768
- const {
2769
- /* Viewport arguments */
2770
- width,
2771
- // Width of viewport
2772
- height,
2773
- // Height of viewport
2774
- target = [0, 0, 0],
2775
- zoom = 0,
2776
- zoomAxis = "all",
2777
- /* Viewport constraints */
2778
- minZoom = -Infinity,
2779
- maxZoom = Infinity,
2780
- minZoomX = minZoom,
2781
- maxZoomX = maxZoom,
2782
- minZoomY = minZoom,
2783
- maxZoomY = maxZoom,
2784
- maxBounds = null,
2785
- maxBoundsPadding = null,
2786
- rubberBand = false,
2787
- /** Interaction states, required to calculate change during transform */
2788
- // Model state when the pan operation first started
2789
- startPanPosition,
2790
- // Model state when the zoom operation first started
2791
- startZoomPosition,
2792
- startZoom
2793
- } = options;
2794
- const { [CONSTRAINT_AROUND]: constraintAround } = options;
2795
- const { zoomX, zoomY } = normalizeZoom(options);
2796
- super(
2797
- {
2798
- width,
2799
- height,
2800
- target,
2801
- zoom,
2802
- zoomX,
2803
- zoomY,
2804
- zoomAxis,
2805
- minZoomX,
2806
- maxZoomX,
2807
- minZoomY,
2808
- maxZoomY,
2809
- maxBounds,
2810
- maxBoundsPadding,
2811
- rubberBand,
2812
- ...{ [CONSTRAINT_AROUND]: constraintAround }
2813
- },
2814
- {
2815
- startPanPosition,
2816
- startZoomPosition,
2817
- startZoom
2818
- },
2819
- options.makeViewport,
2820
- options.constraintContext
2821
- );
2822
- }
2823
- /**
2824
- * Start panning
2825
- * @param {[Number, Number]} pos - position on screen where the pointer grabs
2826
- */
2827
- panStart({ pos }, constraintContext) {
2828
- return this._getUpdatedState({ startPanPosition: this._unproject(pos) }, constraintContext);
2829
- }
2830
- /**
2831
- * Pan
2832
- * @param {[Number, Number]} pos - position on screen where the pointer is
2833
- */
2834
- pan({ pos, startPosition }, constraintContext) {
2835
- const startPanPosition = this.getState().startPanPosition || startPosition;
2836
- if (!startPanPosition) {
2837
- return this;
2838
- }
2839
- const viewport = this.makeViewport(this.getViewportProps());
2840
- const newProps = viewport.panByPosition(startPanPosition, pos);
2841
- return this._getUpdatedState(newProps, constraintContext);
2842
- }
2843
- /**
2844
- * End panning
2845
- * Must call if `panStart()` was called
2846
- */
2847
- panEnd(constraintContext) {
2848
- return this._getUpdatedState({ startPanPosition: null }, constraintContext);
2849
- }
2850
- /**
2851
- * Start rotating
2852
- */
2853
- rotateStart() {
2854
- return this;
2855
- }
2856
- /**
2857
- * Rotate
2858
- */
2859
- rotate() {
2860
- return this;
2861
- }
2862
- /**
2863
- * End rotating
2864
- */
2865
- rotateEnd() {
2866
- return this;
2867
- }
2868
- // shortest path between two view states
2869
- shortestPathFrom(viewState) {
2870
- const fromProps = viewState.getViewportProps();
2871
- const props = { ...this.getViewportProps() };
2872
- return props;
2873
- }
2874
- /**
2875
- * Start zooming
2876
- * @param {[Number, Number]} pos - position on screen where the pointer grabs
2877
- */
2878
- zoomStart({ pos }, constraintContext) {
2879
- const { zoomX, zoomY } = this.getViewportProps();
2880
- return this._getUpdatedState(
2881
- {
2882
- startZoomPosition: this._unproject(pos),
2883
- startZoom: [zoomX, zoomY]
2884
- },
2885
- constraintContext
2886
- );
2887
- }
2888
- /**
2889
- * Zoom
2890
- * @param {[Number, Number]} pos - position on screen where the current target is
2891
- * @param {[Number, Number]} startPos - the target position at
2892
- * the start of the operation. Must be supplied of `zoomStart()` was not called
2893
- * @param {Number} scale - a number between [0, 1] specifying the accumulated
2894
- * relative scale.
2895
- */
2896
- zoom({
2897
- pos,
2898
- startPos,
2899
- scale
2900
- }, constraintContext) {
2901
- let { startZoom, startZoomPosition } = this.getState();
2902
- if (!startZoomPosition) {
2903
- const { zoomX, zoomY } = this.getViewportProps();
2904
- startZoom = [zoomX, zoomY];
2905
- startZoomPosition = this._unproject(startPos || pos);
2906
- }
2907
- if (!startZoomPosition) {
2908
- return this;
2909
- }
2910
- const newZoomProps = this._calculateNewZoom({ scale, startZoom });
2911
- return this._getUpdatedState(
2912
- {
2913
- ...newZoomProps,
2914
- [CONSTRAINT_AROUND]: { position: startZoomPosition, screenPosition: pos }
2915
- },
2916
- constraintContext
2917
- );
2918
- }
2919
- /**
2920
- * End zooming
2921
- * Must call if `zoomStart()` was called
2922
- */
2923
- zoomEnd(constraintContext) {
2924
- return this._getUpdatedState(
2925
- {
2926
- startZoomPosition: null,
2927
- startZoom: null
2928
- },
2929
- constraintContext
2930
- );
2931
- }
2932
- zoomIn(speed = 2, constraintContext) {
2933
- return this._getUpdatedState(this._calculateNewZoom({ scale: speed }), constraintContext);
2934
- }
2935
- zoomOut(speed = 2, constraintContext) {
2936
- return this._getUpdatedState(this._calculateNewZoom({ scale: 1 / speed }), constraintContext);
2937
- }
2938
- moveLeft(speed = 50, constraintContext) {
2939
- return this._panFromCenter([-speed, 0], constraintContext);
2940
- }
2941
- moveRight(speed = 50, constraintContext) {
2942
- return this._panFromCenter([speed, 0], constraintContext);
2943
- }
2944
- moveUp(speed = 50, constraintContext) {
2945
- return this._panFromCenter([0, -speed], constraintContext);
2946
- }
2947
- moveDown(speed = 50, constraintContext) {
2948
- return this._panFromCenter([0, speed], constraintContext);
2949
- }
2950
- rotateLeft(speed = 15) {
2951
- return this;
2952
- }
2953
- rotateRight(speed = 15) {
2954
- return this;
2955
- }
2956
- rotateUp(speed = 10) {
2957
- return this;
2958
- }
2959
- rotateDown(speed = 10) {
2960
- return this;
2961
- }
2962
- /* Private methods */
2963
- _project(pos) {
2964
- const viewport = this.makeViewport(this.getViewportProps());
2965
- return viewport.project(pos);
2966
- }
2967
- _unproject(pos) {
2968
- const viewport = this.makeViewport(this.getViewportProps());
2969
- const [x, y] = viewport.unproject(pos);
2970
- return [x, y];
2971
- }
2972
- // Calculates new zoom
2973
- _calculateNewZoom({ scale, startZoom }) {
2974
- const { zoomX, zoomY, zoomAxis } = this.getViewportProps();
2975
- if (startZoom === void 0) {
2976
- startZoom = [zoomX, zoomY];
2977
- }
2978
- const deltaZoom = Math.log2(scale);
2979
- let [newZoomX, newZoomY] = startZoom;
2980
- switch (zoomAxis) {
2981
- case "X":
2982
- newZoomX += deltaZoom;
2983
- break;
2984
- case "Y":
2985
- newZoomY += deltaZoom;
2986
- break;
2987
- default:
2988
- newZoomX += deltaZoom;
2989
- newZoomY += deltaZoom;
2990
- }
2991
- return {
2992
- zoomX: newZoomX,
2993
- zoomY: newZoomY
2994
- };
2995
- }
2996
- _panFromCenter(offset3, constraintContext) {
2997
- const { target } = this.getViewportProps();
2998
- const center = this._project(target);
2999
- return this.pan(
3000
- {
3001
- startPosition: target,
3002
- pos: [center[0] + offset3[0], center[1] + offset3[1]]
3003
- },
3004
- constraintContext
3005
- );
3006
- }
3007
- _getUpdatedState(newProps, constraintContext) {
3008
- return new this.constructor({
3009
- makeViewport: this.makeViewport,
3010
- ...this.getViewportProps(),
3011
- ...this.getState(),
3012
- ...newProps,
3013
- constraintContext
3014
- });
3015
- }
3016
- // Apply any constraints (mathematical or defined by _viewportProps) to map state
3017
- applyConstraints(props, constraintContext) {
3018
- const internalProps = props;
3019
- const constraintAround = internalProps[CONSTRAINT_AROUND];
3020
- delete internalProps[CONSTRAINT_AROUND];
3021
- const normalizedZoom = normalizeZoom(props);
3022
- const constrainedZoom = this._constrainZoom(normalizedZoom, props);
3023
- const shouldRubberBand = props.rubberBand && (constraintContext == null ? void 0 : constraintContext.mode) === "elastic";
3024
- const { zoomX, zoomY } = (constraintContext == null ? void 0 : constraintContext.mode) === "preserve" ? normalizedZoom : shouldRubberBand ? {
3025
- zoomX: applyRubberBand(
3026
- normalizedZoom.zoomX,
3027
- constrainedZoom.zoomX,
3028
- ZOOM_RUBBER_BAND_RANGE
3029
- ),
3030
- zoomY: applyRubberBand(
3031
- normalizedZoom.zoomY,
3032
- constrainedZoom.zoomY,
3033
- ZOOM_RUBBER_BAND_RANGE
3034
- )
3035
- } : constrainedZoom;
3036
- props.zoomX = zoomX;
3037
- props.zoomY = zoomY;
3038
- if (constraintAround) {
3039
- const viewport = this.makeViewport({ ...props, zoomX, zoomY });
3040
- Object.assign(
3041
- props,
3042
- viewport.panByPosition(constraintAround.position, constraintAround.screenPosition)
3043
- );
3044
- }
3045
- props.zoom = Array.isArray(props.zoom) || props.zoomX !== props.zoomY ? [props.zoomX, props.zoomY] : props.zoomX;
3046
- const { maxBounds, rubberBand, target } = props;
3047
- if (maxBounds) {
3048
- const maxBoundsRect = getMaxBoundsRect(props.width, props.height, props.maxBoundsPadding);
3049
- const viewport = this.makeViewport(props);
3050
- const screenExtents = getMaxBoundsExtents(viewport, target, maxBoundsRect);
3051
- const projectedTarget = viewport.project(target);
3052
- const pixelsPerUnit = [0, 1].map((index) => {
3053
- const sampleTarget = target.slice();
3054
- sampleTarget[index] += 1;
3055
- const projectedDelta = viewport.project(sampleTarget)[index] - projectedTarget[index];
3056
- return Number.isFinite(projectedDelta) ? projectedDelta : 2 ** (index === 0 ? zoomX : zoomY) * (index === 0 ? 1 : -1);
3057
- });
3058
- const worldExtents = pixelsPerUnit.map((projectedDelta, index) => {
3059
- const negativeScreenExtent = index === 0 ? screenExtents.left : screenExtents.top;
3060
- const positiveScreenExtent = index === 0 ? screenExtents.right : screenExtents.bottom;
3061
- const scale = Math.abs(projectedDelta);
3062
- return projectedDelta >= 0 ? [negativeScreenExtent / scale, positiveScreenExtent / scale] : [positiveScreenExtent / scale, negativeScreenExtent / scale];
3063
- });
3064
- const constrainedTarget = target.slice();
3065
- const targetDimensions = [maxBoundsRect.width, maxBoundsRect.height];
3066
- for (const [index, [negativeExtent, positiveExtent]] of worldExtents.entries()) {
3067
- if (targetDimensions[index] < 0) {
3068
- continue;
3069
- }
3070
- const { minimum, maximum, midpoint, settledTarget } = getAxisBounds(
3071
- maxBounds,
3072
- index,
3073
- negativeExtent,
3074
- positiveExtent,
3075
- target[index]
3076
- );
3077
- if ((constraintContext == null ? void 0 : constraintContext.mode) !== "preserve" && rubberBand && (!Number.isFinite(negativeExtent) || !Number.isFinite(positiveExtent))) {
3078
- constrainedTarget[index] = midpoint;
3079
- continue;
3080
- }
3081
- const constrained = rubberBand ? settledTarget : (0, import_core8.clamp)(target[index], minimum, maximum);
3082
- constrainedTarget[index] = (constraintContext == null ? void 0 : constraintContext.mode) === "preserve" ? target[index] : shouldRubberBand ? applyRubberBand(
3083
- target[index],
3084
- constrained,
3085
- (index === 0 ? maxBoundsRect.width : maxBoundsRect.height) / 2 / Math.abs(pixelsPerUnit[index])
3086
- ) : constrained;
3087
- }
3088
- if (constrainedTarget[0] !== target[0] || constrainedTarget[1] !== target[1]) {
3089
- props.target = constrainedTarget;
3090
- }
3091
- }
3092
- return props;
3093
- }
3094
- _constrainZoom({ zoomX, zoomY }, props) {
3095
- props ||= this.getViewportProps();
3096
- const { zoomAxis, maxZoomX, maxZoomY, maxBounds } = props;
3097
- let { minZoomX, minZoomY } = props;
3098
- const shouldApplyMaxBounds = maxBounds !== null && props.width > 0 && props.height > 0;
3099
- if (shouldApplyMaxBounds) {
3100
- const maxBoundsRect = getMaxBoundsRect(props.width, props.height, props.maxBoundsPadding);
3101
- const bl = maxBounds[0];
3102
- const tr = maxBounds[1];
3103
- const w = tr[0] - bl[0];
3104
- const h = tr[1] - bl[1];
3105
- if (maxBoundsRect.width > 0 && Number.isFinite(w) && w > 0) {
3106
- minZoomX = Math.max(minZoomX, Math.log2(maxBoundsRect.width / w));
3107
- if (minZoomX > maxZoomX) minZoomX = maxZoomX;
3108
- }
3109
- if (maxBoundsRect.height > 0 && Number.isFinite(h) && h > 0) {
3110
- minZoomY = Math.max(minZoomY, Math.log2(maxBoundsRect.height / h));
3111
- if (minZoomY > maxZoomY) minZoomY = maxZoomY;
3112
- }
3113
- }
3114
- switch (zoomAxis) {
3115
- case "X":
3116
- zoomX = (0, import_core8.clamp)(zoomX, minZoomX, maxZoomX);
3117
- break;
3118
- case "Y":
3119
- zoomY = (0, import_core8.clamp)(zoomY, minZoomY, maxZoomY);
3120
- break;
3121
- default:
3122
- let delta = Math.min(maxZoomX - zoomX, maxZoomY - zoomY, 0);
3123
- if (delta === 0) {
3124
- delta = Math.max(minZoomX - zoomX, minZoomY - zoomY, 0);
3125
- }
3126
- if (delta !== 0) {
3127
- zoomX += delta;
3128
- zoomY += delta;
3129
- }
3130
- }
3131
- return { zoomX, zoomY };
3132
- }
3133
- };
3134
- var OrthographicController = class extends Controller {
3135
- constructor() {
3136
- super(...arguments);
3137
- this.ControllerState = OrthographicState;
3138
- this.transition = {
3139
- transitionDuration: 300,
3140
- transitionInterpolator: new LinearInterpolator(["target", "zoomX", "zoomY"])
3141
- };
3142
- this.dragMode = "pan";
3143
- }
3144
- setProps(props) {
3145
- Object.assign(props, normalizeZoom(props));
3146
- super.setProps(props);
3147
- }
3148
- _onMultiPanStart(event) {
3149
- return this.multiTouchDrag === "pan" && super._onMultiPanStart(event);
3150
- }
3151
- _onPanRotate() {
3152
- return false;
3153
- }
3154
- };
3155
-
3156
- // ../core/src/views/orthographic-view.ts
3157
- var OrthographicView = class extends View {
3158
- constructor(props = {}) {
3159
- super(props);
3160
- }
3161
- getViewportType() {
3162
- return OrthographicViewport;
3163
- }
3164
- get ControllerType() {
3165
- return OrthographicController;
3166
- }
3167
- };
3168
- OrthographicView.displayName = "OrthographicView";
3169
-
3170
- // ../core/src/transitions/fly-to-interpolator.ts
3171
- var import_core9 = require("@math.gl/core");
3172
- var import_web_mercator6 = require("@math.gl/web-mercator");
3173
- var LINEARLY_INTERPOLATED_PROPS = {
3174
- bearing: 0,
3175
- pitch: 0,
3176
- position: [0, 0, 0]
3177
- };
3178
- var DEFAULT_OPTS = {
3179
- speed: 1.2,
3180
- curve: 1.414
3181
- };
3182
- var FlyToInterpolator = class extends TransitionInterpolator {
3183
- constructor(opts = {}) {
3184
- super({
3185
- compare: ["longitude", "latitude", "zoom", "bearing", "pitch", "position"],
3186
- extract: ["width", "height", "longitude", "latitude", "zoom", "bearing", "pitch", "position"],
3187
- required: ["width", "height", "latitude", "longitude", "zoom"]
3188
- });
3189
- this.opts = { ...DEFAULT_OPTS, ...opts };
3190
- }
3191
- interpolateProps(startProps, endProps, t) {
3192
- const viewport = (0, import_web_mercator6.flyToViewport)(startProps, endProps, t, this.opts);
3193
- for (const key in LINEARLY_INTERPOLATED_PROPS) {
3194
- viewport[key] = (0, import_core9.lerp)(
3195
- startProps[key] || LINEARLY_INTERPOLATED_PROPS[key],
3196
- endProps[key] || LINEARLY_INTERPOLATED_PROPS[key],
3197
- t
3198
- );
3199
- }
3200
- return viewport;
3201
- }
3202
- // computes the transition duration
3203
- getDuration(startProps, endProps) {
3204
- let { transitionDuration } = endProps;
3205
- if (transitionDuration === "auto") {
3206
- transitionDuration = (0, import_web_mercator6.getFlyToDuration)(startProps, endProps, this.opts);
3207
- }
3208
- return transitionDuration;
3209
- }
3210
- };
3211
-
3212
- // dist/zoom-widget.js
63
+ var import_core = require("@deck.gl/core");
3213
64
  var import_preact = require("preact");
3214
65
 
3215
66
  // dist/lib/components/button-group.js
@@ -3311,7 +162,7 @@ var IconButton = (props) => {
3311
162
  };
3312
163
 
3313
164
  // dist/zoom-widget.js
3314
- var ZoomWidget = class extends Widget {
165
+ var ZoomWidget = class extends import_core.Widget {
3315
166
  constructor(props = {}) {
3316
167
  super(props);
3317
168
  this.className = "deck-widget-zoom";
@@ -3330,7 +181,7 @@ var ZoomWidget = class extends Widget {
3330
181
  isOrthographicView(viewId) {
3331
182
  const deck = this.deck;
3332
183
  const view = (deck == null ? void 0 : deck.isInitialized) && deck.getView(viewId);
3333
- return view instanceof OrthographicView;
184
+ return view instanceof import_core.OrthographicView;
3334
185
  }
3335
186
  handleZoom(viewId, delta) {
3336
187
  var _a, _b, _c, _d;
@@ -3342,13 +193,13 @@ var ZoomWidget = class extends Widget {
3342
193
  let nextZoom;
3343
194
  let nextZoomY;
3344
195
  if (zoomAxis === "X") {
3345
- nextZoom = clamp5(zoomX + delta, minZoomX, maxZoomX);
196
+ nextZoom = clamp(zoomX + delta, minZoomX, maxZoomX);
3346
197
  nextZoomY = zoomY;
3347
198
  } else if (zoomAxis === "Y") {
3348
199
  nextZoom = zoomX;
3349
- nextZoomY = clamp5(zoomY + delta, minZoomY, maxZoomY);
200
+ nextZoomY = clamp(zoomY + delta, minZoomY, maxZoomY);
3350
201
  } else {
3351
- const clampedDelta = clamp5(delta, Math.max(minZoomX - zoomX, minZoomY - zoomY), Math.min(maxZoomX - zoomX, maxZoomY - zoomY));
202
+ const clampedDelta = clamp(delta, Math.max(minZoomX - zoomX, minZoomY - zoomY), Math.min(maxZoomX - zoomX, maxZoomY - zoomY));
3352
203
  nextZoom = zoomX + clampedDelta;
3353
204
  nextZoomY = zoomY + clampedDelta;
3354
205
  }
@@ -3365,7 +216,7 @@ var ZoomWidget = class extends Widget {
3365
216
  });
3366
217
  } else {
3367
218
  const { zoom = 0, minZoom, maxZoom } = viewState;
3368
- const nextZoom = clamp5(zoom + delta, minZoom, maxZoom);
219
+ const nextZoom = clamp(zoom + delta, minZoom, maxZoom);
3369
220
  newViewState.zoom = nextZoom;
3370
221
  (_d = (_c = this.props).onZoom) == null ? void 0 : _d.call(_c, {
3371
222
  viewId,
@@ -3379,7 +230,7 @@ var ZoomWidget = class extends Widget {
3379
230
  };
3380
231
  if (this.props.transitionDuration > 0) {
3381
232
  nextViewState.transitionDuration = this.props.transitionDuration;
3382
- nextViewState.transitionInterpolator = "latitude" in nextViewState ? new FlyToInterpolator() : new LinearInterpolator({
233
+ nextViewState.transitionInterpolator = "latitude" in nextViewState ? new import_core.FlyToInterpolator() : new import_core.LinearInterpolator({
3383
234
  transitionProps: "zoomX" in newViewState ? ["zoomX", "zoomY"] : ["zoom"]
3384
235
  });
3385
236
  }
@@ -3397,7 +248,7 @@ var ZoomWidget = class extends Widget {
3397
248
  }
3398
249
  };
3399
250
  ZoomWidget.defaultProps = {
3400
- ...Widget.defaultProps,
251
+ ...import_core.Widget.defaultProps,
3401
252
  id: "zoom",
3402
253
  placement: "top-left",
3403
254
  orientation: "vertical",
@@ -3412,7 +263,7 @@ ZoomWidget.defaultProps = {
3412
263
  onZoom: () => {
3413
264
  }
3414
265
  };
3415
- function clamp5(zoom, minZoom, maxZoom) {
266
+ function clamp(zoom, minZoom, maxZoom) {
3416
267
  return zoom < minZoom ? minZoom : zoom > maxZoom ? maxZoom : zoom;
3417
268
  }
3418
269
  function normalizeOrthographicViewState({ zoom = 0, zoomX, zoomY, minZoom = -Infinity, maxZoom = Infinity, minZoomX = minZoom, maxZoomX = maxZoom, minZoomY = minZoom, maxZoomY = maxZoom }) {
@@ -3424,7 +275,8 @@ function normalizeOrthographicViewState({ zoom = 0, zoomX, zoomY, minZoom = -Inf
3424
275
  // dist/reset-view-widget.js
3425
276
  var import_jsx_runtime5 = require("preact/jsx-runtime");
3426
277
  var import_preact2 = require("preact");
3427
- var ResetViewWidget = class extends Widget {
278
+ var import_core2 = require("@deck.gl/core");
279
+ var ResetViewWidget = class extends import_core2.Widget {
3428
280
  constructor(props = {}) {
3429
281
  super(props);
3430
282
  this.className = "deck-widget-reset-view";
@@ -3459,7 +311,7 @@ var ResetViewWidget = class extends Widget {
3459
311
  }
3460
312
  };
3461
313
  ResetViewWidget.defaultProps = {
3462
- ...Widget.defaultProps,
314
+ ...import_core2.Widget.defaultProps,
3463
315
  id: "reset-view",
3464
316
  placement: "top-left",
3465
317
  label: "Reset View",
@@ -3472,8 +324,9 @@ ResetViewWidget.defaultProps = {
3472
324
 
3473
325
  // dist/gimbal-widget.js
3474
326
  var import_jsx_runtime6 = require("preact/jsx-runtime");
327
+ var import_core3 = require("@deck.gl/core");
3475
328
  var import_preact3 = require("preact");
3476
- var GimbalWidget = class extends Widget {
329
+ var GimbalWidget = class extends import_core3.Widget {
3477
330
  constructor(props = {}) {
3478
331
  super(props);
3479
332
  this.className = "deck-widget-gimbal";
@@ -3524,7 +377,7 @@ var GimbalWidget = class extends Widget {
3524
377
  rotationOrbit: 0,
3525
378
  rotationX: 0,
3526
379
  transitionDuration: this.props.transitionDuration,
3527
- transitionInterpolator: new LinearInterpolator({
380
+ transitionInterpolator: new import_core3.LinearInterpolator({
3528
381
  transitionProps: ["rotationOrbit", "rotationX"]
3529
382
  })
3530
383
  };
@@ -3547,7 +400,7 @@ var GimbalWidget = class extends Widget {
3547
400
  }
3548
401
  };
3549
402
  GimbalWidget.defaultProps = {
3550
- ...Widget.defaultProps,
403
+ ...import_core3.Widget.defaultProps,
3551
404
  id: "gimbal",
3552
405
  placement: "top-left",
3553
406
  viewId: null,
@@ -3574,8 +427,9 @@ function normalizeAndClampAngle(angle) {
3574
427
 
3575
428
  // dist/compass-widget.js
3576
429
  var import_jsx_runtime7 = require("preact/jsx-runtime");
430
+ var import_core4 = require("@deck.gl/core");
3577
431
  var import_preact4 = require("preact");
3578
- var CompassWidget = class extends Widget {
432
+ var CompassWidget = class extends import_core4.Widget {
3579
433
  constructor(props = {}) {
3580
434
  super(props);
3581
435
  this.className = "deck-widget-compass";
@@ -3608,9 +462,9 @@ var CompassWidget = class extends Widget {
3608
462
  }
3609
463
  }
3610
464
  getRotation(viewport) {
3611
- if (viewport instanceof WebMercatorViewport) {
465
+ if (viewport instanceof import_core4.WebMercatorViewport) {
3612
466
  return [-viewport.bearing, viewport.pitch];
3613
- } else if (viewport instanceof GlobeViewport) {
467
+ } else if (viewport instanceof import_core4._GlobeViewport) {
3614
468
  return [0, Math.max(-80, Math.min(80, viewport.latitude))];
3615
469
  }
3616
470
  return [0, 0];
@@ -3618,7 +472,7 @@ var CompassWidget = class extends Widget {
3618
472
  handleCompassReset(viewport) {
3619
473
  var _a, _b;
3620
474
  const viewId = this.viewId || viewport.id;
3621
- if (viewport instanceof WebMercatorViewport) {
475
+ if (viewport instanceof import_core4.WebMercatorViewport) {
3622
476
  const viewState = this.getViewState(viewId);
3623
477
  const resetPitch = this.getRotation(viewport)[0] === 0;
3624
478
  const nextBearing = 0;
@@ -3629,14 +483,14 @@ var CompassWidget = class extends Widget {
3629
483
  bearing: nextBearing,
3630
484
  ...resetPitch ? { pitch: nextPitch } : {},
3631
485
  transitionDuration: this.props.transitionDuration,
3632
- transitionInterpolator: new FlyToInterpolator()
486
+ transitionInterpolator: new import_core4.FlyToInterpolator()
3633
487
  };
3634
488
  this.setViewState(viewId, nextViewState);
3635
489
  }
3636
490
  }
3637
491
  };
3638
492
  CompassWidget.defaultProps = {
3639
- ...Widget.defaultProps,
493
+ ...import_core4.Widget.defaultProps,
3640
494
  id: "compass",
3641
495
  placement: "top-left",
3642
496
  viewId: null,
@@ -3650,7 +504,8 @@ CompassWidget.defaultProps = {
3650
504
  // dist/scale-widget.js
3651
505
  var import_jsx_runtime8 = require("preact/jsx-runtime");
3652
506
  var import_preact5 = require("preact");
3653
- var ScaleWidget = class extends Widget {
507
+ var import_core5 = require("@deck.gl/core");
508
+ var ScaleWidget = class extends import_core5.Widget {
3654
509
  constructor(props = {}) {
3655
510
  super(props);
3656
511
  this.className = "deck-widget-scale";
@@ -3690,7 +545,7 @@ var ScaleWidget = class extends Widget {
3690
545
  }
3691
546
  };
3692
547
  ScaleWidget.defaultProps = {
3693
- ...Widget.defaultProps,
548
+ ...import_core5.Widget.defaultProps,
3694
549
  id: "scale",
3695
550
  placement: "bottom-left",
3696
551
  label: "Scale",
@@ -3733,6 +588,8 @@ function computeScaleCandidate(metersPerPixel) {
3733
588
 
3734
589
  // dist/geocoder-widget.js
3735
590
  var import_jsx_runtime10 = require("preact/jsx-runtime");
591
+ var import_core6 = require("@deck.gl/core");
592
+ var import_core7 = require("@deck.gl/core");
3736
593
  var import_preact6 = require("preact");
3737
594
 
3738
595
  // dist/lib/components/dropdown-menu.js
@@ -3987,7 +844,7 @@ var CURRENT_LOCATION_ITEM = {
3987
844
  value: CURRENT_LOCATION2,
3988
845
  icon: LOCATION_ICON
3989
846
  };
3990
- var GeocoderWidget = class extends Widget {
847
+ var GeocoderWidget = class extends import_core6.Widget {
3991
848
  constructor(props = {}) {
3992
849
  super(props);
3993
850
  this.className = "deck-widget-geocoder";
@@ -4089,14 +946,14 @@ var GeocoderWidget = class extends Widget {
4089
946
  };
4090
947
  if (this.props.transitionDuration > 0) {
4091
948
  nextViewState.transitionDuration = this.props.transitionDuration;
4092
- nextViewState.transitionInterpolator = "latitude" in nextViewState ? new FlyToInterpolator() : new LinearInterpolator();
949
+ nextViewState.transitionInterpolator = "latitude" in nextViewState ? new import_core7.FlyToInterpolator() : new import_core7.LinearInterpolator();
4093
950
  }
4094
951
  this.setViewState(viewId, nextViewState);
4095
952
  }
4096
953
  }
4097
954
  };
4098
955
  GeocoderWidget.defaultProps = {
4099
- ...Widget.defaultProps,
956
+ ...import_core6.Widget.defaultProps,
4100
957
  id: "geocoder",
4101
958
  viewId: null,
4102
959
  placement: "top-left",
@@ -4131,8 +988,9 @@ function getGeocoder(props) {
4131
988
 
4132
989
  // dist/fullscreen-widget.js
4133
990
  var import_jsx_runtime11 = require("preact/jsx-runtime");
991
+ var import_core8 = require("@deck.gl/core");
4134
992
  var import_preact7 = require("preact");
4135
- var FullscreenWidget = class extends Widget {
993
+ var FullscreenWidget = class extends import_core8.Widget {
4136
994
  constructor(props = {}) {
4137
995
  super(props);
4138
996
  this.className = "deck-widget-fullscreen";
@@ -4149,7 +1007,7 @@ var FullscreenWidget = class extends Widget {
4149
1007
  onRenderHTML(rootElement) {
4150
1008
  const isFullscreen = this.getFullscreen();
4151
1009
  (0, import_preact7.render)((0, import_jsx_runtime11.jsx)(IconButton, { onClick: () => {
4152
- this.handleClick().catch((err) => log_default.error(err)());
1010
+ this.handleClick().catch((err) => import_core8.log.error(err)());
4153
1011
  }, label: isFullscreen ? this.props.exitLabel : this.props.enterLabel, tooltip: isFullscreen ? this.props.exitTooltip : this.props.enterTooltip, className: isFullscreen ? "deck-widget-fullscreen-exit" : "deck-widget-fullscreen-enter" }), rootElement);
4154
1012
  }
4155
1013
  setProps(props) {
@@ -4205,7 +1063,7 @@ var FullscreenWidget = class extends Widget {
4205
1063
  }
4206
1064
  };
4207
1065
  FullscreenWidget.defaultProps = {
4208
- ...Widget.defaultProps,
1066
+ ...import_core8.Widget.defaultProps,
4209
1067
  id: "fullscreen",
4210
1068
  placement: "top-left",
4211
1069
  viewId: null,
@@ -4222,12 +1080,14 @@ FullscreenWidget.defaultProps = {
4222
1080
  var import_jsx_runtime12 = require("preact/jsx-runtime");
4223
1081
  var import_preact8 = require("preact");
4224
1082
  var import_hooks4 = require("preact/hooks");
1083
+ var import_core10 = require("@deck.gl/core");
4225
1084
 
4226
1085
  // dist/view-layout/view-layout.js
1086
+ var import_core9 = require("@deck.gl/core");
4227
1087
  var VIEW_LAYOUT_TYPES = /* @__PURE__ */ new Set(["row", "column", "overlay", "spacer"]);
4228
1088
  var VIEW_LAYOUT_ORIENTATIONS = /* @__PURE__ */ new Set(["horizontal", "vertical"]);
4229
1089
  function isViewLayout(child) {
4230
- return Boolean(child && typeof child === "object" && !(child instanceof View) && ("type" in child && VIEW_LAYOUT_TYPES.has(String(child.type)) || "orientation" in child && VIEW_LAYOUT_ORIENTATIONS.has(String(child.orientation))));
1090
+ return Boolean(child && typeof child === "object" && !(child instanceof import_core9.View) && ("type" in child && VIEW_LAYOUT_TYPES.has(String(child.type)) || "orientation" in child && VIEW_LAYOUT_ORIENTATIONS.has(String(child.orientation))));
4231
1091
  }
4232
1092
  function getViewLayoutType(item) {
4233
1093
  if ("orientation" in item) {
@@ -4277,7 +1137,7 @@ function assertViewLayoutChild(child) {
4277
1137
  assertViewLayout(child);
4278
1138
  return;
4279
1139
  }
4280
- if (child instanceof View) {
1140
+ if (child instanceof import_core9.View) {
4281
1141
  return;
4282
1142
  }
4283
1143
  throw new Error("ViewLayout children must be deck.gl View instances or layout objects.");
@@ -4779,7 +1639,7 @@ function evaluateViews(layout, viewLayouts, splitValues) {
4779
1639
  height: `${view.props.height}%`
4780
1640
  }));
4781
1641
  }
4782
- var SplitterWidget = class extends Widget {
1642
+ var SplitterWidget = class extends import_core10.Widget {
4783
1643
  constructor(props) {
4784
1644
  super(props);
4785
1645
  this.className = "deck-widget-splitter";
@@ -4789,7 +1649,7 @@ var SplitterWidget = class extends Widget {
4789
1649
  this.updateViewLayout(this.props.viewLayout);
4790
1650
  }
4791
1651
  setProps(props) {
4792
- if (props.viewLayout && !deepEqual(props.viewLayout, this.props.viewLayout, -1)) {
1652
+ if (props.viewLayout && !(0, import_core10._deepEqual)(props.viewLayout, this.props.viewLayout, -1)) {
4793
1653
  this.updateViewLayout(props.viewLayout);
4794
1654
  this.views = void 0;
4795
1655
  }
@@ -4841,7 +1701,7 @@ var SplitterWidget = class extends Widget {
4841
1701
  }
4842
1702
  };
4843
1703
  SplitterWidget.defaultProps = {
4844
- ...Widget.defaultProps,
1704
+ ...import_core10.Widget.defaultProps,
4845
1705
  id: "splitter-widget",
4846
1706
  viewLayout: void 0,
4847
1707
  onChange: () => {
@@ -4902,6 +1762,7 @@ function Splitter({ orientation, x, y, width, height, split, minSplit, maxSplit,
4902
1762
 
4903
1763
  // dist/info-widget.js
4904
1764
  var import_jsx_runtime15 = require("preact/jsx-runtime");
1765
+ var import_core11 = require("@deck.gl/core");
4905
1766
  var import_preact9 = require("preact");
4906
1767
 
4907
1768
  // dist/lib/components/popover.js
@@ -5016,7 +1877,7 @@ var UserContent = ({ text, html, element, ...props }) => {
5016
1877
  };
5017
1878
 
5018
1879
  // dist/info-widget.js
5019
- var InfoWidget = class extends Widget {
1880
+ var InfoWidget = class extends import_core11.Widget {
5020
1881
  constructor(props) {
5021
1882
  super(props);
5022
1883
  this.className = "deck-widget-info";
@@ -5087,7 +1948,7 @@ var InfoWidget = class extends Widget {
5087
1948
  }
5088
1949
  };
5089
1950
  InfoWidget.defaultProps = {
5090
- ...Widget.defaultProps,
1951
+ ...import_core11.Widget.defaultProps,
5091
1952
  id: "info",
5092
1953
  viewId: null,
5093
1954
  mode: "hover",
@@ -5099,8 +1960,9 @@ InfoWidget.defaultProps = {
5099
1960
 
5100
1961
  // dist/popup-widget.js
5101
1962
  var import_jsx_runtime16 = require("preact/jsx-runtime");
1963
+ var import_core12 = require("@deck.gl/core");
5102
1964
  var import_preact10 = require("preact");
5103
- var PopupWidget = class extends Widget {
1965
+ var PopupWidget = class extends import_core12.Widget {
5104
1966
  constructor(props) {
5105
1967
  super(props);
5106
1968
  this.className = "deck-widget-popup";
@@ -5149,7 +2011,7 @@ var PopupWidget = class extends Widget {
5149
2011
  }
5150
2012
  };
5151
2013
  PopupWidget.defaultProps = {
5152
- ...Widget.defaultProps,
2014
+ ...import_core12.Widget.defaultProps,
5153
2015
  id: "info",
5154
2016
  viewId: null,
5155
2017
  position: [0, 0],
@@ -5167,8 +2029,9 @@ PopupWidget.defaultProps = {
5167
2029
 
5168
2030
  // dist/context-menu-widget.js
5169
2031
  var import_jsx_runtime17 = require("preact/jsx-runtime");
2032
+ var import_core13 = require("@deck.gl/core");
5170
2033
  var import_preact11 = require("preact");
5171
- var ContextMenuWidget = class extends Widget {
2034
+ var ContextMenuWidget = class extends import_core13.Widget {
5172
2035
  constructor(props) {
5173
2036
  super(props);
5174
2037
  this.className = "deck-widget-context-menu";
@@ -5222,7 +2085,7 @@ var ContextMenuWidget = class extends Widget {
5222
2085
  }
5223
2086
  };
5224
2087
  ContextMenuWidget.defaultProps = {
5225
- ...Widget.defaultProps,
2088
+ ...import_core13.Widget.defaultProps,
5226
2089
  id: "context",
5227
2090
  viewId: null,
5228
2091
  menuItems: [],
@@ -5236,13 +2099,14 @@ ContextMenuWidget.defaultProps = {
5236
2099
 
5237
2100
  // dist/scrollbar-widget.js
5238
2101
  var import_jsx_runtime19 = require("preact/jsx-runtime");
2102
+ var import_core14 = require("@deck.gl/core");
5239
2103
  var import_preact12 = require("preact");
5240
2104
 
5241
2105
  // dist/lib/components/range-input.js
5242
2106
  var import_jsx_runtime18 = require("preact/jsx-runtime");
5243
2107
  var import_hooks7 = require("preact/hooks");
5244
2108
  var wheelListenerOptions = { passive: false };
5245
- var clamp6 = (value, min, max) => {
2109
+ var clamp2 = (value, min, max) => {
5246
2110
  if (value < min) {
5247
2111
  return min;
5248
2112
  }
@@ -5284,7 +2148,7 @@ function RangeInput(props) {
5284
2148
  const range = max - min;
5285
2149
  const rangeSize = Math.max(0, value[1] - value[0]);
5286
2150
  const maxStart = Math.max(0, range - rangeSize);
5287
- const clampedStart = clamp6(value[0], min, min + maxStart);
2151
+ const clampedStart = clamp2(value[0], min, min + maxStart);
5288
2152
  const { thumbLength, thumbOffset } = (0, import_hooks7.useMemo)(() => {
5289
2153
  if (trackLength <= 0 || range <= 0) {
5290
2154
  return { thumbLength: 0, thumbOffset: 0 };
@@ -5294,7 +2158,7 @@ function RangeInput(props) {
5294
2158
  }
5295
2159
  const nextThumbLength = rangeSize / range;
5296
2160
  const travel = Math.max(0, 1 - nextThumbLength);
5297
- const ratio = maxStart <= 0 ? 0 : clamp6((clampedStart - min) / maxStart, 0, 1);
2161
+ const ratio = maxStart <= 0 ? 0 : clamp2((clampedStart - min) / maxStart, 0, 1);
5298
2162
  return {
5299
2163
  thumbLength: Math.max(0, Math.min(nextThumbLength, 1)),
5300
2164
  thumbOffset: travel * ratio
@@ -5304,7 +2168,7 @@ function RangeInput(props) {
5304
2168
  if (!onChange) {
5305
2169
  return;
5306
2170
  }
5307
- const clamped = clamp6(nextStart, min, min + maxStart);
2171
+ const clamped = clamp2(nextStart, min, min + maxStart);
5308
2172
  onChange([clamped, clamped + rangeSize]);
5309
2173
  }, [onChange, min, maxStart, rangeSize]);
5310
2174
  const handleStepNegative = (0, import_hooks7.useCallback)((event) => {
@@ -5333,7 +2197,7 @@ function RangeInput(props) {
5333
2197
  const coordinate = vertical ? event.clientY - trackStart : event.clientX - trackStart;
5334
2198
  const span = Math.max(1, 1 - thumbLength) * trackLength;
5335
2199
  const thumbCenter = thumbLength / 2 * trackLength;
5336
- const ratio = span <= 0 ? 0 : clamp6((coordinate - thumbCenter) / span, 0, 1);
2200
+ const ratio = span <= 0 ? 0 : clamp2((coordinate - thumbCenter) / span, 0, 1);
5337
2201
  emitRange(min + ratio * maxStart);
5338
2202
  }, [vertical, trackLength, thumbLength, emitRange, min, maxStart]);
5339
2203
  const handleThumbPointerDown = (event) => {
@@ -5365,7 +2229,7 @@ function RangeInput(props) {
5365
2229
  const coordinate = vertical ? event.clientY : event.clientX;
5366
2230
  const delta = coordinate - state.startCoord;
5367
2231
  const ratio = state.startRatio + delta / trackLength2;
5368
- const nextStart = clamp6(ratio * (state.max - state.min), 0, state.maxStart) + state.min;
2232
+ const nextStart = clamp2(ratio * (state.max - state.min), 0, state.maxStart) + state.min;
5369
2233
  emitRange(nextStart);
5370
2234
  event.preventDefault();
5371
2235
  }, [emitRange, vertical]);
@@ -5496,7 +2360,7 @@ function RangeInput(props) {
5496
2360
  }
5497
2361
 
5498
2362
  // dist/scrollbar-widget.js
5499
- var clamp7 = (value, min, max) => {
2363
+ var clamp3 = (value, min, max) => {
5500
2364
  if (value < min) {
5501
2365
  return min;
5502
2366
  }
@@ -5505,7 +2369,7 @@ var clamp7 = (value, min, max) => {
5505
2369
  }
5506
2370
  return value;
5507
2371
  };
5508
- var ScrollbarWidget = class _ScrollbarWidget extends Widget {
2372
+ var ScrollbarWidget = class _ScrollbarWidget extends import_core14.Widget {
5509
2373
  constructor(props) {
5510
2374
  const resolved = {
5511
2375
  ..._ScrollbarWidget.defaultProps,
@@ -5567,7 +2431,7 @@ var ScrollbarWidget = class _ScrollbarWidget extends Widget {
5567
2431
  const contentBounds = this.getContentBounds(viewport.id);
5568
2432
  const isVertical = this.isVertical();
5569
2433
  const projectedBounds = contentBounds ? projectBounds(contentBounds, viewport, isVertical) : [0, 0];
5570
- const contentRect = getMaxBoundsRect(viewport.width, viewport.height, this.getContentBoundsPadding(viewport.id));
2434
+ const contentRect = (0, import_core14._getMaxBoundsRect)(viewport.width, viewport.height, this.getContentBoundsPadding(viewport.id));
5571
2435
  const contentStart = isVertical ? contentRect.y : contentRect.x;
5572
2436
  const viewportSize = isVertical ? contentRect.height : contentRect.width;
5573
2437
  this.contentSize = projectedBounds[1] - projectedBounds[0];
@@ -5619,7 +2483,7 @@ var ScrollbarWidget = class _ScrollbarWidget extends Widget {
5619
2483
  }
5620
2484
  getClampedOffset() {
5621
2485
  const maxScroll = this.getMaxScroll();
5622
- return clamp7(this.scrollOffset, 0, maxScroll);
2486
+ return clamp3(this.scrollOffset, 0, maxScroll);
5623
2487
  }
5624
2488
  isVertical() {
5625
2489
  return this.props.orientation !== "horizontal";
@@ -5638,7 +2502,7 @@ var ScrollbarWidget = class _ScrollbarWidget extends Widget {
5638
2502
  }
5639
2503
  emitScroll(next) {
5640
2504
  const maxScroll = this.getMaxScroll();
5641
- const target = clamp7(Math.round(next), 0, maxScroll);
2505
+ const target = clamp3(Math.round(next), 0, maxScroll);
5642
2506
  const viewport = this.viewport;
5643
2507
  if (viewport && target !== this.getClampedOffset()) {
5644
2508
  const pixel = viewport.project(viewport.position);
@@ -5660,7 +2524,7 @@ var ScrollbarWidget = class _ScrollbarWidget extends Widget {
5660
2524
  }
5661
2525
  };
5662
2526
  ScrollbarWidget.defaultProps = {
5663
- ...Widget.defaultProps,
2527
+ ...import_core14.Widget.defaultProps,
5664
2528
  contentBounds: null,
5665
2529
  contentBoundsPadding: null,
5666
2530
  placement: "top-right",
@@ -5685,7 +2549,8 @@ function projectBounds(bounds, viewport, isVertical) {
5685
2549
  // dist/icon-widget.js
5686
2550
  var import_jsx_runtime20 = require("preact/jsx-runtime");
5687
2551
  var import_preact13 = require("preact");
5688
- var IconWidget = class extends Widget {
2552
+ var import_core15 = require("@deck.gl/core");
2553
+ var IconWidget = class extends import_core15.Widget {
5689
2554
  constructor(props) {
5690
2555
  super(props);
5691
2556
  this.className = "";
@@ -5703,7 +2568,7 @@ var IconWidget = class extends Widget {
5703
2568
  }
5704
2569
  };
5705
2570
  IconWidget.defaultProps = {
5706
- ...Widget.defaultProps,
2571
+ ...import_core15.Widget.defaultProps,
5707
2572
  id: "icon",
5708
2573
  placement: "top-left",
5709
2574
  viewId: null,
@@ -5717,7 +2582,8 @@ IconWidget.defaultProps = {
5717
2582
  // dist/toggle-widget.js
5718
2583
  var import_jsx_runtime21 = require("preact/jsx-runtime");
5719
2584
  var import_preact14 = require("preact");
5720
- var ToggleWidget = class extends Widget {
2585
+ var import_core16 = require("@deck.gl/core");
2586
+ var ToggleWidget = class extends import_core16.Widget {
5721
2587
  constructor(props) {
5722
2588
  super(props);
5723
2589
  this.className = "deck-widget-toggle";
@@ -5744,7 +2610,7 @@ var ToggleWidget = class extends Widget {
5744
2610
  }
5745
2611
  };
5746
2612
  ToggleWidget.defaultProps = {
5747
- ...Widget.defaultProps,
2613
+ ...import_core16.Widget.defaultProps,
5748
2614
  id: "icon",
5749
2615
  placement: "top-left",
5750
2616
  viewId: null,
@@ -5763,7 +2629,8 @@ ToggleWidget.defaultProps = {
5763
2629
  // dist/selector-widget.js
5764
2630
  var import_jsx_runtime22 = require("preact/jsx-runtime");
5765
2631
  var import_preact15 = require("preact");
5766
- var SelectorWidget = class extends Widget {
2632
+ var import_core17 = require("@deck.gl/core");
2633
+ var SelectorWidget = class extends import_core17.Widget {
5767
2634
  constructor(props) {
5768
2635
  super(props);
5769
2636
  this.className = "deck-widget-selector";
@@ -5800,7 +2667,7 @@ var SelectorWidget = class extends Widget {
5800
2667
  }
5801
2668
  };
5802
2669
  SelectorWidget.defaultProps = {
5803
- ...Widget.defaultProps,
2670
+ ...import_core17.Widget.defaultProps,
5804
2671
  id: "view-selector",
5805
2672
  placement: "top-left",
5806
2673
  viewId: null,
@@ -5813,8 +2680,9 @@ SelectorWidget.defaultProps = {
5813
2680
 
5814
2681
  // dist/timeline-widget.js
5815
2682
  var import_jsx_runtime23 = require("preact/jsx-runtime");
2683
+ var import_core18 = require("@deck.gl/core");
5816
2684
  var import_preact16 = require("preact");
5817
- var TimelineWidget = class extends Widget {
2685
+ var TimelineWidget = class extends import_core18.Widget {
5818
2686
  /**
5819
2687
  * Returns the current time value.
5820
2688
  * In controlled mode, returns the time prop.
@@ -5970,7 +2838,7 @@ var TimelineWidget = class extends Widget {
5970
2838
  }
5971
2839
  };
5972
2840
  TimelineWidget.defaultProps = {
5973
- ...Widget.defaultProps,
2841
+ ...import_core18.Widget.defaultProps,
5974
2842
  id: "timeline",
5975
2843
  placement: "bottom-left",
5976
2844
  viewId: null,
@@ -5995,7 +2863,8 @@ TimelineWidget.defaultProps = {
5995
2863
  // dist/screenshot-widget.js
5996
2864
  var import_jsx_runtime24 = require("preact/jsx-runtime");
5997
2865
  var import_preact17 = require("preact");
5998
- var ScreenshotWidget = class extends Widget {
2866
+ var import_core19 = require("@deck.gl/core");
2867
+ var ScreenshotWidget = class extends import_core19.Widget {
5999
2868
  constructor(props = {}) {
6000
2869
  super(props);
6001
2870
  this.className = "deck-widget-screenshot";
@@ -6035,7 +2904,7 @@ var ScreenshotWidget = class extends Widget {
6035
2904
  }
6036
2905
  };
6037
2906
  ScreenshotWidget.defaultProps = {
6038
- ...Widget.defaultProps,
2907
+ ...import_core19.Widget.defaultProps,
6039
2908
  id: "screenshot",
6040
2909
  placement: "top-left",
6041
2910
  viewId: null,
@@ -6048,6 +2917,8 @@ ScreenshotWidget.defaultProps = {
6048
2917
 
6049
2918
  // dist/theme-widget.js
6050
2919
  var import_jsx_runtime25 = require("preact/jsx-runtime");
2920
+ var import_core20 = require("@deck.gl/core");
2921
+ var import_core21 = require("@deck.gl/core");
6051
2922
  var import_preact18 = require("preact");
6052
2923
 
6053
2924
  // dist/themes.js
@@ -6169,7 +3040,7 @@ var DarkGlassTheme = {
6169
3040
  };
6170
3041
 
6171
3042
  // dist/theme-widget.js
6172
- var ThemeWidget = class extends Widget {
3043
+ var ThemeWidget = class extends import_core21.Widget {
6173
3044
  constructor(props = {}) {
6174
3045
  super(props);
6175
3046
  this.className = "deck-widget-theme";
@@ -6212,16 +3083,16 @@ var ThemeWidget = class extends Widget {
6212
3083
  /** Apply theme styling without changing internal state */
6213
3084
  _applyTheme(themeMode, rootElement) {
6214
3085
  const themeStyle = themeMode === "dark" ? this.props.darkModeTheme : this.props.lightModeTheme;
6215
- if (deepEqual(themeStyle, this.appliedTheme, 1)) {
3086
+ if ((0, import_core20._deepEqual)(themeStyle, this.appliedTheme, 1)) {
6216
3087
  return;
6217
3088
  }
6218
3089
  const container = rootElement.closest(".deck-widget-container");
6219
3090
  if (!container)
6220
3091
  return;
6221
- applyStyles(container, themeStyle);
3092
+ (0, import_core20._applyStyles)(container, themeStyle);
6222
3093
  this.appliedTheme = themeStyle;
6223
3094
  const label = themeMode === "dark" ? this.props.darkModeLabel : this.props.lightModeLabel;
6224
- log_default.log(1, `Switched theme to ${label}`, themeStyle)();
3095
+ import_core20.log.log(1, `Switched theme to ${label}`, themeStyle)();
6225
3096
  }
6226
3097
  /** Read browser preference */
6227
3098
  _getInitialThemeMode() {
@@ -6236,7 +3107,7 @@ var ThemeWidget = class extends Widget {
6236
3107
  }
6237
3108
  };
6238
3109
  ThemeWidget.defaultProps = {
6239
- ...Widget.defaultProps,
3110
+ ...import_core21.Widget.defaultProps,
6240
3111
  id: "theme",
6241
3112
  placement: "top-left",
6242
3113
  viewId: null,
@@ -6255,7 +3126,8 @@ ThemeWidget.defaultProps = {
6255
3126
  // dist/loading-widget.js
6256
3127
  var import_jsx_runtime26 = require("preact/jsx-runtime");
6257
3128
  var import_preact19 = require("preact");
6258
- var LoadingWidget = class extends Widget {
3129
+ var import_core22 = require("@deck.gl/core");
3130
+ var LoadingWidget = class extends import_core22.Widget {
6259
3131
  constructor(props = {}) {
6260
3132
  super(props);
6261
3133
  this.className = "deck-widget-loading";
@@ -6289,7 +3161,7 @@ var LoadingWidget = class extends Widget {
6289
3161
  }
6290
3162
  };
6291
3163
  LoadingWidget.defaultProps = {
6292
- ...Widget.defaultProps,
3164
+ ...import_core22.Widget.defaultProps,
6293
3165
  id: "loading",
6294
3166
  placement: "top-left",
6295
3167
  viewId: null,
@@ -6301,7 +3173,8 @@ LoadingWidget.defaultProps = {
6301
3173
 
6302
3174
  // dist/stats-widget.js
6303
3175
  var import_jsx_runtime27 = require("preact/jsx-runtime");
6304
- var import_core33 = require("@luma.gl/core");
3176
+ var import_core23 = require("@deck.gl/core");
3177
+ var import_core24 = require("@luma.gl/core");
6305
3178
  var import_preact20 = require("preact");
6306
3179
  var import_hooks8 = require("preact/hooks");
6307
3180
  var DEFAULT_COUNT_FORMATTER = (stat) => `${stat.name}: ${stat.count}`;
@@ -6319,7 +3192,7 @@ var DEFAULT_FORMATTERS = {
6319
3192
  fps: (stat) => `${stat.name}: ${Math.round(stat.getHz())}fps`,
6320
3193
  memory: (stat) => `${stat.name}: ${formatMemory(stat.count)}`
6321
3194
  };
6322
- var StatsWidget = class extends Widget {
3195
+ var StatsWidget = class extends import_core23.Widget {
6323
3196
  /**
6324
3197
  * Returns the current expanded state.
6325
3198
  * In controlled mode, returns the expanded prop.
@@ -6409,7 +3282,7 @@ var StatsWidget = class extends Widget {
6409
3282
  const metrics = ((_a = this.deck) == null ? void 0 : _a.metrics) ?? {};
6410
3283
  return Object.entries(metrics);
6411
3284
  case "luma":
6412
- return Array.from(import_core33.luma.stats.stats.values())[0];
3285
+ return Array.from(import_core24.luma.stats.stats.values())[0];
6413
3286
  case "device":
6414
3287
  const device = (_b = this.deck) == null ? void 0 : _b.device;
6415
3288
  const stats = device == null ? void 0 : device.statsManager.stats.values();
@@ -6446,7 +3319,7 @@ var StatsWidget = class extends Widget {
6446
3319
  }
6447
3320
  };
6448
3321
  StatsWidget.defaultProps = {
6449
- ...Widget.defaultProps,
3322
+ ...import_core23.Widget.defaultProps,
6450
3323
  type: "deck",
6451
3324
  placement: "top-left",
6452
3325
  viewId: null,