@deck.gl/arcgis 9.3.4 → 9.3.6

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
@@ -17,15 +17,15 @@ var __copyProps = (to, from, except, desc) => {
17
17
  }
18
18
  return to;
19
19
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ var __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__getProtoOf(mod2)) : {}, __copyProps(
21
21
  // If the importer is in node compatibility mode or this is not an ESM
22
22
  // file that has been converted to a CommonJS file using a Babel-
23
23
  // compatible transform (i.e. "__esModule" has not been set), then set
24
24
  // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
25
+ isNodeMode || !mod2 || !mod2.__esModule ? __defProp(target, "default", { value: mod2, enumerable: true }) : target,
26
+ mod2
27
27
  ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
29
29
 
30
30
  // dist/index.js
31
31
  var dist_exports = {};
@@ -171,7 +171,9 @@ out vec4 fragColor;
171
171
 
172
172
  void main(void) {
173
173
  vec4 imageColor = texture(deckglTexture, v_texcoord);
174
- imageColor.rgb *= imageColor.a;
174
+ // FBO stores premultiplied RGBA (rgb already multiplied by alpha).
175
+ // The composite blend (ONE, ONE_MINUS_SRC_ALPHA) handles premultiplied
176
+ // input correctly; multiplying again here would darken overlays.
175
177
  fragColor = imageColor;
176
178
  }
177
179
  `,
@@ -179,8 +181,8 @@ void main(void) {
179
181
  deckglTexture: texture
180
182
  },
181
183
  parameters: {
182
- depthWriteEnabled: true,
183
- depthCompare: "less-equal",
184
+ depthWriteEnabled: false,
185
+ depthCompare: "always",
184
186
  blendColorSrcFactor: "one",
185
187
  blendColorDstFactor: "one-minus-src-alpha",
186
188
  blendAlphaSrcFactor: "one",
@@ -209,6 +211,8 @@ void main(void) {
209
211
  _framebuffer: fbo,
210
212
  _customRender: (redrawReason) => {
211
213
  if (redrawReason === "arcgis") {
214
+ const glCtx = device.gl;
215
+ glCtx.blendFuncSeparate(glCtx.ONE, glCtx.ONE_MINUS_SRC_ALPHA, glCtx.ONE, glCtx.ONE_MINUS_SRC_ALPHA);
212
216
  deckInstance._drawLayers(redrawReason);
213
217
  } else {
214
218
  this.redraw();
@@ -218,33 +222,48 @@ void main(void) {
218
222
  return { deck: deckInstance, texture, fbo, model };
219
223
  }
220
224
  function render(resources, viewport) {
221
- var _a, _b;
222
225
  const { model, deck, fbo } = resources;
223
226
  const device = model.device;
224
227
  if (device instanceof import_webgl.WebGLDevice) {
225
- const { width, height, ...viewState } = viewport;
228
+ const rawScreenFbo = device.getParametersWebGL(36006);
229
+ const { width, height, views, viewState, ...defaultViewState } = viewport;
226
230
  const dpr = window.devicePixelRatio;
227
231
  const pixelWidth = Math.round(width * dpr);
228
232
  const pixelHeight = Math.round(height * dpr);
229
- const externalFbo = device.getParametersWebGL(36006);
230
- let screenFbo = null;
231
- if (externalFbo) {
232
- if (((_a = resources._externalFramebuffer) == null ? void 0 : _a.handle) !== externalFbo) {
233
- (_b = resources._externalFramebuffer) == null ? void 0 : _b.wrapper.destroy();
234
- const wrapper = device.createFramebuffer({
235
- handle: externalFbo,
236
- width: pixelWidth,
237
- height: pixelHeight
238
- });
239
- resources._externalFramebuffer = { handle: externalFbo, wrapper };
240
- }
241
- screenFbo = resources._externalFramebuffer.wrapper;
242
- }
243
233
  fbo.resize({ width: pixelWidth, height: pixelHeight });
244
- deck.setProps({ viewState });
234
+ const currentTexture = fbo.colorAttachments[0].texture ?? fbo.colorAttachments[0];
235
+ if (currentTexture !== resources.texture) {
236
+ resources.texture = currentTexture;
237
+ model.setBindings({ deckglTexture: currentTexture });
238
+ }
239
+ const deckProps = {
240
+ width,
241
+ height,
242
+ viewState: viewState || defaultViewState
243
+ };
244
+ if (views) {
245
+ deckProps.views = views;
246
+ }
247
+ deck.setProps(deckProps);
245
248
  deck.redraw("arcgis");
249
+ const { gl } = device;
250
+ if (rawScreenFbo) {
251
+ gl.bindFramebuffer(36160, rawScreenFbo);
252
+ gl.drawBuffers([36064]);
253
+ } else {
254
+ gl.drawBuffers([1029]);
255
+ }
256
+ gl.enable(3042);
257
+ gl.blendFuncSeparate(1, 771, 1, 771);
258
+ gl.blendEquationSeparate(32774, 32774);
259
+ const screenFboAdapter = {
260
+ handle: rawScreenFbo,
261
+ width: pixelWidth,
262
+ height: pixelHeight,
263
+ colorAttachments: [null]
264
+ };
246
265
  const textureToScreenPass = device.beginRenderPass({
247
- framebuffer: screenFbo,
266
+ framebuffer: screenFboAdapter,
248
267
  parameters: { viewport: [0, 0, pixelWidth, pixelHeight] },
249
268
  clearColor: false,
250
269
  clearDepth: false
@@ -257,12 +276,10 @@ function render(resources, viewport) {
257
276
  }
258
277
  }
259
278
  function finalizeResources(resources) {
260
- var _a;
261
279
  resources.deck.finalize();
262
280
  resources.model.destroy();
263
281
  resources.fbo.destroy();
264
282
  resources.texture.destroy();
265
- (_a = resources._externalFramebuffer) == null ? void 0 : _a.wrapper.destroy();
266
283
  }
267
284
 
268
285
  // dist/deck-layer-view-2d.js
@@ -318,55 +335,2793 @@ function createDeckLayerView2D(BaseLayerViewGL2D2) {
318
335
  });
319
336
  }
320
337
 
338
+ // ../core/src/utils/positions.ts
339
+ var NUMBER_REGEX = /^(?:\d+\.?\d*|\.\d+)$/;
340
+ function parsePosition(value) {
341
+ switch (typeof value) {
342
+ case "number":
343
+ if (!Number.isFinite(value)) {
344
+ throw new Error(`Could not parse position string ${value}`);
345
+ }
346
+ return { type: "literal", value };
347
+ case "string":
348
+ try {
349
+ const tokens = tokenize(value);
350
+ const parser = new LayoutExpressionParser(tokens);
351
+ return parser.parseExpression();
352
+ } catch (error) {
353
+ const reason = error instanceof Error ? error.message : String(error);
354
+ throw new Error(`Could not parse position string ${value}: ${reason}`);
355
+ }
356
+ default:
357
+ throw new Error(`Could not parse position string ${value}`);
358
+ }
359
+ }
360
+ function evaluateLayoutExpression(expression, extent) {
361
+ switch (expression.type) {
362
+ case "literal":
363
+ return expression.value;
364
+ case "percentage":
365
+ return Math.round(expression.value * extent);
366
+ case "binary":
367
+ const left = evaluateLayoutExpression(expression.left, extent);
368
+ const right = evaluateLayoutExpression(expression.right, extent);
369
+ return expression.operator === "+" ? left + right : left - right;
370
+ default:
371
+ throw new Error("Unknown layout expression type");
372
+ }
373
+ }
374
+ function getPosition(expression, extent) {
375
+ return evaluateLayoutExpression(expression, extent);
376
+ }
377
+ function tokenize(input) {
378
+ const tokens = [];
379
+ let index = 0;
380
+ while (index < input.length) {
381
+ const char = input[index];
382
+ if (/\s/.test(char)) {
383
+ index++;
384
+ continue;
385
+ }
386
+ if (char === "+" || char === "-" || char === "(" || char === ")" || char === "%") {
387
+ tokens.push({ type: "symbol", value: char });
388
+ index++;
389
+ continue;
390
+ }
391
+ if (isDigit(char) || char === ".") {
392
+ const start = index;
393
+ let hasDecimal = char === ".";
394
+ index++;
395
+ while (index < input.length) {
396
+ const next = input[index];
397
+ if (isDigit(next)) {
398
+ index++;
399
+ continue;
400
+ }
401
+ if (next === "." && !hasDecimal) {
402
+ hasDecimal = true;
403
+ index++;
404
+ continue;
405
+ }
406
+ break;
407
+ }
408
+ const numberString = input.slice(start, index);
409
+ if (!NUMBER_REGEX.test(numberString)) {
410
+ throw new Error("Invalid number token");
411
+ }
412
+ tokens.push({ type: "number", value: parseFloat(numberString) });
413
+ continue;
414
+ }
415
+ if (isAlpha(char)) {
416
+ const start = index;
417
+ while (index < input.length && isAlpha(input[index])) {
418
+ index++;
419
+ }
420
+ const word = input.slice(start, index).toLowerCase();
421
+ tokens.push({ type: "word", value: word });
422
+ continue;
423
+ }
424
+ throw new Error("Invalid token in position string");
425
+ }
426
+ return tokens;
427
+ }
428
+ var LayoutExpressionParser = class {
429
+ constructor(tokens) {
430
+ this.index = 0;
431
+ this.tokens = tokens;
432
+ }
433
+ parseExpression() {
434
+ const expression = this.parseBinaryExpression();
435
+ if (this.index < this.tokens.length) {
436
+ throw new Error("Unexpected token at end of expression");
437
+ }
438
+ return expression;
439
+ }
440
+ parseBinaryExpression() {
441
+ let expression = this.parseFactor();
442
+ let token = this.peek();
443
+ while (isAddSubSymbol(token)) {
444
+ this.index++;
445
+ const right = this.parseFactor();
446
+ expression = { type: "binary", operator: token.value, left: expression, right };
447
+ token = this.peek();
448
+ }
449
+ return expression;
450
+ }
451
+ parseFactor() {
452
+ const token = this.peek();
453
+ if (!token) {
454
+ throw new Error("Unexpected end of expression");
455
+ }
456
+ if (token.type === "symbol" && token.value === "+") {
457
+ this.index++;
458
+ return this.parseFactor();
459
+ }
460
+ if (token.type === "symbol" && token.value === "-") {
461
+ this.index++;
462
+ const factor = this.parseFactor();
463
+ return { type: "binary", operator: "-", left: { type: "literal", value: 0 }, right: factor };
464
+ }
465
+ if (token.type === "symbol" && token.value === "(") {
466
+ this.index++;
467
+ const expression = this.parseBinaryExpression();
468
+ if (!this.consumeSymbol(")")) {
469
+ throw new Error("Missing closing parenthesis");
470
+ }
471
+ return expression;
472
+ }
473
+ if (token.type === "word" && token.value === "calc") {
474
+ this.index++;
475
+ if (!this.consumeSymbol("(")) {
476
+ throw new Error("Missing opening parenthesis after calc");
477
+ }
478
+ const expression = this.parseBinaryExpression();
479
+ if (!this.consumeSymbol(")")) {
480
+ throw new Error("Missing closing parenthesis");
481
+ }
482
+ return expression;
483
+ }
484
+ if (token.type === "number") {
485
+ this.index++;
486
+ const numberValue = token.value;
487
+ const nextToken = this.peek();
488
+ if (nextToken && nextToken.type === "symbol" && nextToken.value === "%") {
489
+ this.index++;
490
+ return { type: "percentage", value: numberValue / 100 };
491
+ }
492
+ if (nextToken && nextToken.type === "word" && nextToken.value === "px") {
493
+ this.index++;
494
+ return { type: "literal", value: numberValue };
495
+ }
496
+ return { type: "literal", value: numberValue };
497
+ }
498
+ throw new Error("Unexpected token in expression");
499
+ }
500
+ consumeSymbol(value) {
501
+ const token = this.peek();
502
+ if (token && token.type === "symbol" && token.value === value) {
503
+ this.index++;
504
+ return true;
505
+ }
506
+ return false;
507
+ }
508
+ peek() {
509
+ return this.tokens[this.index] || null;
510
+ }
511
+ };
512
+ function isDigit(char) {
513
+ return char >= "0" && char <= "9";
514
+ }
515
+ function isAlpha(char) {
516
+ return char >= "a" && char <= "z" || char >= "A" && char <= "Z";
517
+ }
518
+ function isAddSubSymbol(token) {
519
+ return Boolean(token && token.type === "symbol" && (token.value === "+" || token.value === "-"));
520
+ }
521
+
522
+ // ../core/src/utils/deep-equal.ts
523
+ function deepEqual(a, b, depth) {
524
+ if (a === b) {
525
+ return true;
526
+ }
527
+ if (!depth || !a || !b) {
528
+ return false;
529
+ }
530
+ if (Array.isArray(a)) {
531
+ if (!Array.isArray(b) || a.length !== b.length) {
532
+ return false;
533
+ }
534
+ for (let i = 0; i < a.length; i++) {
535
+ if (!deepEqual(a[i], b[i], depth - 1)) {
536
+ return false;
537
+ }
538
+ }
539
+ return true;
540
+ }
541
+ if (Array.isArray(b)) {
542
+ return false;
543
+ }
544
+ if (typeof a === "object" && typeof b === "object") {
545
+ const aKeys = Object.keys(a);
546
+ const bKeys = Object.keys(b);
547
+ if (aKeys.length !== bKeys.length) {
548
+ return false;
549
+ }
550
+ for (const key of aKeys) {
551
+ if (!b.hasOwnProperty(key)) {
552
+ return false;
553
+ }
554
+ if (!deepEqual(a[key], b[key], depth - 1)) {
555
+ return false;
556
+ }
557
+ }
558
+ return true;
559
+ }
560
+ return false;
561
+ }
562
+
563
+ // ../core/src/utils/deep-merge.ts
564
+ function deepMergeViewState(a, b) {
565
+ const result = { ...a };
566
+ for (const key in b) {
567
+ if (key === "id")
568
+ continue;
569
+ if (Array.isArray(result[key]) && Array.isArray(b[key])) {
570
+ result[key] = mergeNumericArray(result[key], b[key]);
571
+ } else {
572
+ result[key] = b[key];
573
+ }
574
+ }
575
+ return result;
576
+ }
577
+ function mergeNumericArray(target, source) {
578
+ target = target.slice();
579
+ for (let i = 0; i < source.length; i++) {
580
+ const v = source[i];
581
+ if (Number.isFinite(v)) {
582
+ target[i] = v;
583
+ }
584
+ }
585
+ return target;
586
+ }
587
+
588
+ // ../core/src/views/view.ts
589
+ var View = class {
590
+ constructor(props) {
591
+ const { id, x = 0, y = 0, width = "100%", height = "100%", padding = null } = props;
592
+ this.id = id || this.constructor.displayName || "view";
593
+ this.props = { ...props, id: this.id };
594
+ this._x = parsePosition(x);
595
+ this._y = parsePosition(y);
596
+ this._width = parsePosition(width);
597
+ this._height = parsePosition(height);
598
+ this._padding = padding && {
599
+ left: parsePosition(padding.left || 0),
600
+ right: parsePosition(padding.right || 0),
601
+ top: parsePosition(padding.top || 0),
602
+ bottom: parsePosition(padding.bottom || 0)
603
+ };
604
+ this.equals = this.equals.bind(this);
605
+ Object.seal(this);
606
+ }
607
+ equals(view) {
608
+ if (this === view) {
609
+ return true;
610
+ }
611
+ return this.constructor === view.constructor && deepEqual(this.props, view.props, 2);
612
+ }
613
+ /** Clone this view with modified props */
614
+ clone(newProps) {
615
+ const ViewConstructor = this.constructor;
616
+ return new ViewConstructor({ ...this.props, ...newProps });
617
+ }
618
+ /** Make viewport from canvas dimensions and view state */
619
+ makeViewport({ width, height, viewState }) {
620
+ viewState = this.filterViewState(viewState);
621
+ const viewportDimensions = this.getDimensions({ width, height });
622
+ if (!viewportDimensions.height || !viewportDimensions.width) {
623
+ return null;
624
+ }
625
+ const ViewportType = this.getViewportType(viewState);
626
+ return new ViewportType({ ...viewState, ...this.props, ...viewportDimensions });
627
+ }
628
+ getViewStateId() {
629
+ const { viewState } = this.props;
630
+ if (typeof viewState === "string") {
631
+ return viewState;
632
+ }
633
+ return (viewState == null ? void 0 : viewState.id) || this.id;
634
+ }
635
+ // Allows view to override (or completely define) viewState
636
+ filterViewState(viewState) {
637
+ if (this.props.viewState && typeof this.props.viewState === "object") {
638
+ if (!this.props.viewState.id) {
639
+ return this.props.viewState;
640
+ }
641
+ return deepMergeViewState(viewState, this.props.viewState);
642
+ }
643
+ return viewState;
644
+ }
645
+ /** Resolve the dimensions of the view from overall canvas dimensions */
646
+ getDimensions({ width, height }) {
647
+ const dimensions = {
648
+ x: getPosition(this._x, width),
649
+ y: getPosition(this._y, height),
650
+ width: getPosition(this._width, width),
651
+ height: getPosition(this._height, height)
652
+ };
653
+ if (this._padding) {
654
+ dimensions.padding = {
655
+ left: getPosition(this._padding.left, width),
656
+ top: getPosition(this._padding.top, height),
657
+ right: getPosition(this._padding.right, width),
658
+ bottom: getPosition(this._padding.bottom, height)
659
+ };
660
+ }
661
+ return dimensions;
662
+ }
663
+ // Used by sub classes to resolve controller props
664
+ get controller() {
665
+ const opts = this.props.controller;
666
+ if (!opts) {
667
+ return null;
668
+ }
669
+ if (opts === true) {
670
+ return { type: this.ControllerType };
671
+ }
672
+ if (typeof opts === "function") {
673
+ return { type: opts };
674
+ }
675
+ return { type: this.ControllerType, ...opts };
676
+ }
677
+ };
678
+
679
+ // ../core/src/utils/log.ts
680
+ var import_log = require("@probe.gl/log");
681
+ var defaultLogger = new import_log.Log({ id: "deck" });
682
+ var log_default = defaultLogger;
683
+
684
+ // ../core/src/utils/math-utils.ts
685
+ var import_core2 = require("@math.gl/core");
686
+ function createMat4() {
687
+ return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
688
+ }
689
+ function mod(value, divisor) {
690
+ const modulus = value % divisor;
691
+ return modulus < 0 ? divisor + modulus : modulus;
692
+ }
693
+ function getCameraPosition(viewMatrixInverse) {
694
+ return [viewMatrixInverse[12], viewMatrixInverse[13], viewMatrixInverse[14]];
695
+ }
696
+ function getFrustumPlanes(viewProjectionMatrix) {
697
+ return {
698
+ left: getFrustumPlane(
699
+ viewProjectionMatrix[3] + viewProjectionMatrix[0],
700
+ viewProjectionMatrix[7] + viewProjectionMatrix[4],
701
+ viewProjectionMatrix[11] + viewProjectionMatrix[8],
702
+ viewProjectionMatrix[15] + viewProjectionMatrix[12]
703
+ ),
704
+ right: getFrustumPlane(
705
+ viewProjectionMatrix[3] - viewProjectionMatrix[0],
706
+ viewProjectionMatrix[7] - viewProjectionMatrix[4],
707
+ viewProjectionMatrix[11] - viewProjectionMatrix[8],
708
+ viewProjectionMatrix[15] - viewProjectionMatrix[12]
709
+ ),
710
+ bottom: getFrustumPlane(
711
+ viewProjectionMatrix[3] + viewProjectionMatrix[1],
712
+ viewProjectionMatrix[7] + viewProjectionMatrix[5],
713
+ viewProjectionMatrix[11] + viewProjectionMatrix[9],
714
+ viewProjectionMatrix[15] + viewProjectionMatrix[13]
715
+ ),
716
+ top: getFrustumPlane(
717
+ viewProjectionMatrix[3] - viewProjectionMatrix[1],
718
+ viewProjectionMatrix[7] - viewProjectionMatrix[5],
719
+ viewProjectionMatrix[11] - viewProjectionMatrix[9],
720
+ viewProjectionMatrix[15] - viewProjectionMatrix[13]
721
+ ),
722
+ near: getFrustumPlane(
723
+ viewProjectionMatrix[3] + viewProjectionMatrix[2],
724
+ viewProjectionMatrix[7] + viewProjectionMatrix[6],
725
+ viewProjectionMatrix[11] + viewProjectionMatrix[10],
726
+ viewProjectionMatrix[15] + viewProjectionMatrix[14]
727
+ ),
728
+ far: getFrustumPlane(
729
+ viewProjectionMatrix[3] - viewProjectionMatrix[2],
730
+ viewProjectionMatrix[7] - viewProjectionMatrix[6],
731
+ viewProjectionMatrix[11] - viewProjectionMatrix[10],
732
+ viewProjectionMatrix[15] - viewProjectionMatrix[14]
733
+ )
734
+ };
735
+ }
736
+ var scratchVector = new import_core2.Vector3();
737
+ function getFrustumPlane(a, b, c, d) {
738
+ scratchVector.set(a, b, c);
739
+ const L = scratchVector.len();
740
+ return { distance: d / L, normal: new import_core2.Vector3(-a / L, -b / L, -c / L) };
741
+ }
742
+
743
+ // ../core/src/viewports/viewport.ts
744
+ var import_core3 = require("@math.gl/core");
745
+ var import_web_mercator = require("@math.gl/web-mercator");
746
+
747
+ // ../core/src/lib/constants.ts
748
+ var import_mjolnir = require("mjolnir.js");
749
+ var COORDINATE_SYSTEM = {
750
+ /**
751
+ * `LNGLAT` if rendering into a geospatial viewport, `CARTESIAN` otherwise
752
+ */
753
+ DEFAULT: "default",
754
+ /**
755
+ * Positions are interpreted as [longitude, latitude, elevation]
756
+ * longitude/latitude are in degrees, elevation is in meters.
757
+ * Dimensions are in meters.
758
+ */
759
+ LNGLAT: "lnglat",
760
+ /**
761
+ * Positions are interpreted as [x, y, z] in meter offsets from the coordinate origin.
762
+ * Dimensions are in meters.
763
+ */
764
+ METER_OFFSETS: "meter-offsets",
765
+ /**
766
+ * Positions are interpreted as [deltaLng, deltaLat, elevation] from the coordinate origin.
767
+ * deltaLng/deltaLat are in degrees, elevation is in meters.
768
+ * Dimensions are in meters.
769
+ */
770
+ LNGLAT_OFFSETS: "lnglat-offsets",
771
+ /**
772
+ * Positions and dimensions are in the common units of the viewport.
773
+ */
774
+ CARTESIAN: "cartesian"
775
+ };
776
+ Object.defineProperty(COORDINATE_SYSTEM, "IDENTITY", {
777
+ get: () => {
778
+ log_default.deprecated("COORDINATE_SYSTEM.IDENTITY", "COORDINATE_SYSTEM.CARTESIAN")();
779
+ return COORDINATE_SYSTEM.CARTESIAN;
780
+ }
781
+ });
782
+ var PROJECTION_MODE = {
783
+ /**
784
+ * Render geospatial data in Web Mercator projection
785
+ */
786
+ WEB_MERCATOR: 1,
787
+ /**
788
+ * Render geospatial data as a 3D globe
789
+ */
790
+ GLOBE: 2,
791
+ /**
792
+ * (Internal use only) Web Mercator projection at high zoom
793
+ */
794
+ WEB_MERCATOR_AUTO_OFFSET: 4,
795
+ /**
796
+ * No transformation
797
+ */
798
+ IDENTITY: 0
799
+ };
800
+ var RECOGNIZERS = {
801
+ multipan: [import_mjolnir.Pan, { threshold: 10, direction: import_mjolnir.InputDirection.Vertical, pointers: 2 }],
802
+ pinch: [import_mjolnir.Pinch, {}, null, ["multipan"]],
803
+ pan: [import_mjolnir.Pan, { threshold: 1 }, ["pinch"], ["multipan"]],
804
+ dblclick: [import_mjolnir.Tap, { event: "dblclick", taps: 2 }],
805
+ click: [import_mjolnir.Tap, { event: "click" }, null, ["dblclick"]]
806
+ };
807
+
808
+ // ../core/src/viewports/viewport.ts
809
+ var DEGREES_TO_RADIANS = Math.PI / 180;
810
+ var IDENTITY = createMat4();
811
+ var ZERO_VECTOR = [0, 0, 0];
812
+ var DEFAULT_DISTANCE_SCALES = {
813
+ unitsPerMeter: [1, 1, 1],
814
+ metersPerUnit: [1, 1, 1]
815
+ };
816
+ function createProjectionMatrix({
817
+ width,
818
+ height,
819
+ orthographic,
820
+ fovyRadians,
821
+ focalDistance,
822
+ padding,
823
+ near,
824
+ far
825
+ }) {
826
+ const aspect = width / height;
827
+ const matrix = orthographic ? new import_core3.Matrix4().orthographic({ fovy: fovyRadians, aspect, focalDistance, near, far }) : new import_core3.Matrix4().perspective({ fovy: fovyRadians, aspect, near, far });
828
+ if (padding) {
829
+ const { left = 0, right = 0, top = 0, bottom = 0 } = padding;
830
+ const offsetX = (0, import_core3.clamp)((left + width - right) / 2, 0, width) - width / 2;
831
+ const offsetY = (0, import_core3.clamp)((top + height - bottom) / 2, 0, height) - height / 2;
832
+ matrix[8] -= offsetX * 2 / width;
833
+ matrix[9] += offsetY * 2 / height;
834
+ }
835
+ return matrix;
836
+ }
837
+ var _Viewport = class {
838
+ // eslint-disable-next-line complexity
839
+ constructor(opts = {}) {
840
+ this._frustumPlanes = {};
841
+ this.id = opts.id || this.constructor.displayName || "viewport";
842
+ this.x = opts.x || 0;
843
+ this.y = opts.y || 0;
844
+ this.width = opts.width || 1;
845
+ this.height = opts.height || 1;
846
+ this.zoom = opts.zoom || 0;
847
+ this.padding = opts.padding;
848
+ this.distanceScales = opts.distanceScales || DEFAULT_DISTANCE_SCALES;
849
+ this.focalDistance = opts.focalDistance || 1;
850
+ this.position = opts.position || ZERO_VECTOR;
851
+ this.modelMatrix = opts.modelMatrix || null;
852
+ const { longitude, latitude } = opts;
853
+ this.isGeospatial = Number.isFinite(latitude) && Number.isFinite(longitude);
854
+ this._initProps(opts);
855
+ this._initMatrices(opts);
856
+ this.equals = this.equals.bind(this);
857
+ this.project = this.project.bind(this);
858
+ this.unproject = this.unproject.bind(this);
859
+ this.projectPosition = this.projectPosition.bind(this);
860
+ this.unprojectPosition = this.unprojectPosition.bind(this);
861
+ this.projectFlat = this.projectFlat.bind(this);
862
+ this.unprojectFlat = this.unprojectFlat.bind(this);
863
+ }
864
+ get subViewports() {
865
+ return null;
866
+ }
867
+ get metersPerPixel() {
868
+ return this.distanceScales.metersPerUnit[2] / this.scale;
869
+ }
870
+ get projectionMode() {
871
+ if (this.isGeospatial) {
872
+ return this.zoom < 12 ? PROJECTION_MODE.WEB_MERCATOR : PROJECTION_MODE.WEB_MERCATOR_AUTO_OFFSET;
873
+ }
874
+ return PROJECTION_MODE.IDENTITY;
875
+ }
876
+ // Two viewports are equal if width and height are identical, and if
877
+ // their view and projection matrices are (approximately) equal.
878
+ equals(viewport) {
879
+ if (!(viewport instanceof _Viewport)) {
880
+ return false;
881
+ }
882
+ if (this === viewport) {
883
+ return true;
884
+ }
885
+ return viewport.width === this.width && viewport.height === this.height && viewport.scale === this.scale && (0, import_core3.equals)(viewport.projectionMatrix, this.projectionMatrix) && (0, import_core3.equals)(viewport.viewMatrix, this.viewMatrix);
886
+ }
887
+ /**
888
+ * Projects xyz (possibly latitude and longitude) to pixel coordinates in window
889
+ * using viewport projection parameters
890
+ * - [longitude, latitude] to [x, y]
891
+ * - [longitude, latitude, Z] => [x, y, z]
892
+ * Note: By default, returns top-left coordinates for canvas/SVG type render
893
+ *
894
+ * @param {Array} lngLatZ - [lng, lat] or [lng, lat, Z]
895
+ * @param {Object} opts - options
896
+ * @param {Object} opts.topLeft=true - Whether projected coords are top left
897
+ * @return {Array} - [x, y] or [x, y, z] in top left coords
898
+ */
899
+ project(xyz, { topLeft = true } = {}) {
900
+ const worldPosition = this.projectPosition(xyz);
901
+ const coord = (0, import_web_mercator.worldToPixels)(worldPosition, this.pixelProjectionMatrix);
902
+ const [x, y] = coord;
903
+ const y2 = topLeft ? y : this.height - y;
904
+ return xyz.length === 2 ? [x, y2] : [x, y2, coord[2]];
905
+ }
906
+ /**
907
+ * Unproject pixel coordinates on screen onto world coordinates,
908
+ * (possibly [lon, lat]) on map.
909
+ * - [x, y] => [lng, lat]
910
+ * - [x, y, z] => [lng, lat, Z]
911
+ * @param {Array} xyz -
912
+ * @param {Object} opts - options
913
+ * @param {Object} opts.topLeft=true - Whether origin is top left
914
+ * @return {Array|null} - [lng, lat, Z] or [X, Y, Z]
915
+ */
916
+ unproject(xyz, { topLeft = true, targetZ } = {}) {
917
+ const [x, y, z] = xyz;
918
+ const y2 = topLeft ? y : this.height - y;
919
+ const targetZWorld = targetZ && targetZ * this.distanceScales.unitsPerMeter[2];
920
+ const coord = (0, import_web_mercator.pixelsToWorld)([x, y2, z], this.pixelUnprojectionMatrix, targetZWorld);
921
+ const [X, Y, Z] = this.unprojectPosition(coord);
922
+ if (Number.isFinite(z)) {
923
+ return [X, Y, Z];
924
+ }
925
+ return Number.isFinite(targetZ) ? [X, Y, targetZ] : [X, Y];
926
+ }
927
+ // NON_LINEAR PROJECTION HOOKS
928
+ // Used for web meractor projection
929
+ projectPosition(xyz) {
930
+ const [X, Y] = this.projectFlat(xyz);
931
+ const Z = (xyz[2] || 0) * this.distanceScales.unitsPerMeter[2];
932
+ return [X, Y, Z];
933
+ }
934
+ unprojectPosition(xyz) {
935
+ const [X, Y] = this.unprojectFlat(xyz);
936
+ const Z = (xyz[2] || 0) * this.distanceScales.metersPerUnit[2];
937
+ return [X, Y, Z];
938
+ }
939
+ /**
940
+ * Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.
941
+ * Performs the nonlinear part of the web mercator projection.
942
+ * Remaining projection is done with 4x4 matrices which also handles
943
+ * perspective.
944
+ * @param {Array} lngLat - [lng, lat] coordinates
945
+ * Specifies a point on the sphere to project onto the map.
946
+ * @return {Array} [x,y] coordinates.
947
+ */
948
+ projectFlat(xyz) {
949
+ if (this.isGeospatial) {
950
+ const result = (0, import_web_mercator.lngLatToWorld)(xyz);
951
+ result[1] = (0, import_core3.clamp)(result[1], -318, 830);
952
+ return result;
953
+ }
954
+ return xyz;
955
+ }
956
+ /**
957
+ * Unproject world point [x,y] on map onto {lat, lon} on sphere
958
+ * @param {object|Vector} xy - object with {x,y} members
959
+ * representing point on projected map plane
960
+ * @return {GeoCoordinates} - object with {lat,lon} of point on sphere.
961
+ * Has toArray method if you need a GeoJSON Array.
962
+ * Per cartographic tradition, lat and lon are specified as degrees.
963
+ */
964
+ unprojectFlat(xyz) {
965
+ if (this.isGeospatial) {
966
+ return (0, import_web_mercator.worldToLngLat)(xyz);
967
+ }
968
+ return xyz;
969
+ }
970
+ /**
971
+ * Get bounds of the current viewport
972
+ * @return {Array} - [minX, minY, maxX, maxY]
973
+ */
974
+ getBounds(options = {}) {
975
+ const unprojectOption = { targetZ: options.z || 0 };
976
+ const topLeft = this.unproject([0, 0], unprojectOption);
977
+ const topRight = this.unproject([this.width, 0], unprojectOption);
978
+ const bottomLeft = this.unproject([0, this.height], unprojectOption);
979
+ const bottomRight = this.unproject([this.width, this.height], unprojectOption);
980
+ return [
981
+ Math.min(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]),
982
+ Math.min(topLeft[1], topRight[1], bottomLeft[1], bottomRight[1]),
983
+ Math.max(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]),
984
+ Math.max(topLeft[1], topRight[1], bottomLeft[1], bottomRight[1])
985
+ ];
986
+ }
987
+ getDistanceScales(coordinateOrigin) {
988
+ if (coordinateOrigin && this.isGeospatial) {
989
+ return (0, import_web_mercator.getDistanceScales)({
990
+ longitude: coordinateOrigin[0],
991
+ latitude: coordinateOrigin[1],
992
+ highPrecision: true
993
+ });
994
+ }
995
+ return this.distanceScales;
996
+ }
997
+ containsPixel({
998
+ x,
999
+ y,
1000
+ width = 1,
1001
+ height = 1
1002
+ }) {
1003
+ return x < this.x + this.width && this.x < x + width && y < this.y + this.height && this.y < y + height;
1004
+ }
1005
+ // Extract frustum planes in common space
1006
+ getFrustumPlanes() {
1007
+ if (this._frustumPlanes.near) {
1008
+ return this._frustumPlanes;
1009
+ }
1010
+ Object.assign(this._frustumPlanes, getFrustumPlanes(this.viewProjectionMatrix));
1011
+ return this._frustumPlanes;
1012
+ }
1013
+ // EXPERIMENTAL METHODS
1014
+ /**
1015
+ * Needed by panning and linear transition
1016
+ * Pan the viewport to place a given world coordinate at screen point [x, y]
1017
+ *
1018
+ * @param {Array} coords - world coordinates
1019
+ * @param {Array} pixel - [x,y] coordinates on screen
1020
+ * @param {Array} startPixel - [x,y] screen position where pan started (optional, for delta-based panning)
1021
+ * @return {Object} props of the new viewport
1022
+ */
1023
+ panByPosition(coords, pixel, startPixel) {
1024
+ return null;
1025
+ }
1026
+ // INTERNAL METHODS
1027
+ /* eslint-disable complexity, max-statements */
1028
+ _initProps(opts) {
1029
+ const longitude = opts.longitude;
1030
+ const latitude = opts.latitude;
1031
+ if (this.isGeospatial) {
1032
+ if (!Number.isFinite(opts.zoom)) {
1033
+ this.zoom = (0, import_web_mercator.getMeterZoom)({ latitude }) + Math.log2(this.focalDistance);
1034
+ }
1035
+ this.distanceScales = opts.distanceScales || (0, import_web_mercator.getDistanceScales)({ latitude, longitude });
1036
+ }
1037
+ const scale = Math.pow(2, this.zoom);
1038
+ this.scale = scale;
1039
+ const { position, modelMatrix } = opts;
1040
+ let meterOffset = ZERO_VECTOR;
1041
+ if (position) {
1042
+ meterOffset = modelMatrix ? new import_core3.Matrix4(modelMatrix).transformAsVector(position, []) : position;
1043
+ }
1044
+ if (this.isGeospatial) {
1045
+ const center = this.projectPosition([longitude, latitude, 0]);
1046
+ this.center = new import_core3.Vector3(meterOffset).scale(this.distanceScales.unitsPerMeter).add(center);
1047
+ } else {
1048
+ this.center = this.projectPosition(meterOffset);
1049
+ }
1050
+ }
1051
+ /* eslint-enable complexity, max-statements */
1052
+ _initMatrices(opts) {
1053
+ const {
1054
+ // View matrix
1055
+ viewMatrix = IDENTITY,
1056
+ // Projection matrix
1057
+ projectionMatrix = null,
1058
+ // Projection matrix parameters, used if projectionMatrix not supplied
1059
+ orthographic = false,
1060
+ fovyRadians,
1061
+ fovy = 75,
1062
+ near = 0.1,
1063
+ // Distance of near clipping plane
1064
+ far = 1e3,
1065
+ // Distance of far clipping plane
1066
+ padding = null,
1067
+ // Center offset in pixels
1068
+ focalDistance = 1
1069
+ } = opts;
1070
+ this.viewMatrixUncentered = viewMatrix;
1071
+ this.viewMatrix = new import_core3.Matrix4().multiplyRight(viewMatrix).translate(new import_core3.Vector3(this.center).negate());
1072
+ this.projectionMatrix = projectionMatrix || createProjectionMatrix({
1073
+ width: this.width,
1074
+ height: this.height,
1075
+ orthographic,
1076
+ fovyRadians: fovyRadians || fovy * DEGREES_TO_RADIANS,
1077
+ focalDistance,
1078
+ padding,
1079
+ near,
1080
+ far
1081
+ });
1082
+ const vpm = createMat4();
1083
+ import_core3.mat4.multiply(vpm, vpm, this.projectionMatrix);
1084
+ import_core3.mat4.multiply(vpm, vpm, this.viewMatrix);
1085
+ this.viewProjectionMatrix = vpm;
1086
+ this.viewMatrixInverse = import_core3.mat4.invert([], this.viewMatrix) || this.viewMatrix;
1087
+ this.cameraPosition = getCameraPosition(this.viewMatrixInverse);
1088
+ const viewportMatrix = createMat4();
1089
+ const pixelProjectionMatrix = createMat4();
1090
+ import_core3.mat4.scale(viewportMatrix, viewportMatrix, [this.width / 2, -this.height / 2, 1]);
1091
+ import_core3.mat4.translate(viewportMatrix, viewportMatrix, [1, -1, 0]);
1092
+ import_core3.mat4.multiply(pixelProjectionMatrix, viewportMatrix, this.viewProjectionMatrix);
1093
+ this.pixelProjectionMatrix = pixelProjectionMatrix;
1094
+ this.pixelUnprojectionMatrix = import_core3.mat4.invert(createMat4(), this.pixelProjectionMatrix);
1095
+ if (!this.pixelUnprojectionMatrix) {
1096
+ log_default.warn("Pixel project matrix not invertible")();
1097
+ }
1098
+ }
1099
+ };
1100
+ var Viewport = _Viewport;
1101
+ Viewport.displayName = "Viewport";
1102
+
1103
+ // ../core/src/viewports/web-mercator-viewport.ts
1104
+ var import_web_mercator2 = require("@math.gl/web-mercator");
1105
+ var import_core4 = require("@math.gl/core");
1106
+ var _WebMercatorViewport = class extends Viewport {
1107
+ /* eslint-disable complexity, max-statements */
1108
+ constructor(opts = {}) {
1109
+ const {
1110
+ latitude = 0,
1111
+ longitude = 0,
1112
+ zoom = 0,
1113
+ pitch = 0,
1114
+ bearing = 0,
1115
+ nearZMultiplier = 0.1,
1116
+ farZMultiplier = 1.01,
1117
+ nearZ,
1118
+ farZ,
1119
+ orthographic = false,
1120
+ projectionMatrix,
1121
+ repeat = false,
1122
+ worldOffset = 0,
1123
+ position,
1124
+ padding,
1125
+ // backward compatibility
1126
+ // TODO: remove in v9
1127
+ legacyMeterSizes = false
1128
+ } = opts;
1129
+ let { width, height, altitude = 1.5 } = opts;
1130
+ const scale = Math.pow(2, zoom);
1131
+ width = width || 1;
1132
+ height = height || 1;
1133
+ let fovy;
1134
+ let projectionParameters = null;
1135
+ if (projectionMatrix) {
1136
+ altitude = projectionMatrix[5] / 2;
1137
+ fovy = (0, import_web_mercator2.altitudeToFovy)(altitude);
1138
+ } else {
1139
+ if (opts.fovy) {
1140
+ fovy = opts.fovy;
1141
+ altitude = (0, import_web_mercator2.fovyToAltitude)(fovy);
1142
+ } else {
1143
+ fovy = (0, import_web_mercator2.altitudeToFovy)(altitude);
1144
+ }
1145
+ let offset;
1146
+ if (padding) {
1147
+ const { top = 0, bottom = 0 } = padding;
1148
+ offset = [0, (0, import_core4.clamp)((top + height - bottom) / 2, 0, height) - height / 2];
1149
+ }
1150
+ projectionParameters = (0, import_web_mercator2.getProjectionParameters)({
1151
+ width,
1152
+ height,
1153
+ scale,
1154
+ center: position && [0, 0, position[2] * (0, import_web_mercator2.unitsPerMeter)(latitude)],
1155
+ offset,
1156
+ pitch,
1157
+ fovy,
1158
+ nearZMultiplier,
1159
+ farZMultiplier
1160
+ });
1161
+ if (Number.isFinite(nearZ)) {
1162
+ projectionParameters.near = nearZ;
1163
+ }
1164
+ if (Number.isFinite(farZ)) {
1165
+ projectionParameters.far = farZ;
1166
+ }
1167
+ }
1168
+ let viewMatrixUncentered = (0, import_web_mercator2.getViewMatrix)({
1169
+ height,
1170
+ pitch,
1171
+ bearing,
1172
+ scale,
1173
+ altitude
1174
+ });
1175
+ if (worldOffset) {
1176
+ const viewOffset = new import_core4.Matrix4().translate([512 * worldOffset, 0, 0]);
1177
+ viewMatrixUncentered = viewOffset.multiplyLeft(viewMatrixUncentered);
1178
+ }
1179
+ super({
1180
+ ...opts,
1181
+ // x, y,
1182
+ width,
1183
+ height,
1184
+ // view matrix
1185
+ viewMatrix: viewMatrixUncentered,
1186
+ longitude,
1187
+ latitude,
1188
+ zoom,
1189
+ // projection matrix parameters
1190
+ ...projectionParameters,
1191
+ fovy,
1192
+ focalDistance: altitude
1193
+ });
1194
+ this.latitude = latitude;
1195
+ this.longitude = longitude;
1196
+ this.zoom = zoom;
1197
+ this.pitch = pitch;
1198
+ this.bearing = bearing;
1199
+ this.altitude = altitude;
1200
+ this.fovy = fovy;
1201
+ this.orthographic = orthographic;
1202
+ this._subViewports = repeat ? [] : null;
1203
+ this._pseudoMeters = legacyMeterSizes;
1204
+ Object.freeze(this);
1205
+ }
1206
+ /* eslint-enable complexity, max-statements */
1207
+ get subViewports() {
1208
+ if (this._subViewports && !this._subViewports.length) {
1209
+ const bounds = this.getBounds();
1210
+ const minOffset = Math.floor((bounds[0] + 180) / 360);
1211
+ const maxOffset = Math.ceil((bounds[2] - 180) / 360);
1212
+ for (let x = minOffset; x <= maxOffset; x++) {
1213
+ const offsetViewport = x ? new _WebMercatorViewport({
1214
+ ...this,
1215
+ worldOffset: x
1216
+ }) : this;
1217
+ this._subViewports.push(offsetViewport);
1218
+ }
1219
+ }
1220
+ return this._subViewports;
1221
+ }
1222
+ projectPosition(xyz) {
1223
+ if (this._pseudoMeters) {
1224
+ return super.projectPosition(xyz);
1225
+ }
1226
+ const [X, Y] = this.projectFlat(xyz);
1227
+ const Z = (xyz[2] || 0) * (0, import_web_mercator2.unitsPerMeter)(xyz[1]);
1228
+ return [X, Y, Z];
1229
+ }
1230
+ unprojectPosition(xyz) {
1231
+ if (this._pseudoMeters) {
1232
+ return super.unprojectPosition(xyz);
1233
+ }
1234
+ const [X, Y] = this.unprojectFlat(xyz);
1235
+ const Z = (xyz[2] || 0) / (0, import_web_mercator2.unitsPerMeter)(Y);
1236
+ return [X, Y, Z];
1237
+ }
1238
+ /**
1239
+ * Add a meter delta to a base lnglat coordinate, returning a new lnglat array
1240
+ *
1241
+ * Note: Uses simple linear approximation around the viewport center
1242
+ * Error increases with size of offset (roughly 1% per 100km)
1243
+ *
1244
+ * @param {[Number,Number]|[Number,Number,Number]) lngLatZ - base coordinate
1245
+ * @param {[Number,Number]|[Number,Number,Number]) xyz - array of meter deltas
1246
+ * @return {[Number,Number]|[Number,Number,Number]) array of [lng,lat,z] deltas
1247
+ */
1248
+ addMetersToLngLat(lngLatZ, xyz) {
1249
+ return (0, import_web_mercator2.addMetersToLngLat)(lngLatZ, xyz);
1250
+ }
1251
+ panByPosition(coords, pixel, startPixel) {
1252
+ const fromLocation = (0, import_web_mercator2.pixelsToWorld)(pixel, this.pixelUnprojectionMatrix);
1253
+ const toLocation = this.projectFlat(coords);
1254
+ const translate = import_core4.vec2.add([], toLocation, import_core4.vec2.negate([], fromLocation));
1255
+ const newCenter = import_core4.vec2.add([], this.center, translate);
1256
+ const [longitude, latitude] = this.unprojectFlat(newCenter);
1257
+ return { longitude, latitude };
1258
+ }
1259
+ /**
1260
+ * Returns a new longitude and latitude that keeps a 3D world coordinate at a given screen pixel
1261
+ * This version handles the z-component (altitude) properly for cameras positioned above ground
1262
+ */
1263
+ panByPosition3D(coords, pixel) {
1264
+ const targetZ = coords[2] || 0;
1265
+ const deltaLngLat = import_core4.vec2.sub([], coords, this.unproject(pixel, { targetZ }));
1266
+ return { longitude: this.longitude + deltaLngLat[0], latitude: this.latitude + deltaLngLat[1] };
1267
+ }
1268
+ getBounds(options = {}) {
1269
+ const corners = (0, import_web_mercator2.getBounds)(this, options.z || 0);
1270
+ return [
1271
+ Math.min(corners[0][0], corners[1][0], corners[2][0], corners[3][0]),
1272
+ Math.min(corners[0][1], corners[1][1], corners[2][1], corners[3][1]),
1273
+ Math.max(corners[0][0], corners[1][0], corners[2][0], corners[3][0]),
1274
+ Math.max(corners[0][1], corners[1][1], corners[2][1], corners[3][1])
1275
+ ];
1276
+ }
1277
+ /**
1278
+ * Returns a new viewport that fit around the given rectangle.
1279
+ * Only supports non-perspective mode.
1280
+ */
1281
+ fitBounds(bounds, options = {}) {
1282
+ const { width, height } = this;
1283
+ const { longitude, latitude, zoom } = (0, import_web_mercator2.fitBounds)({ width, height, bounds, ...options });
1284
+ return new _WebMercatorViewport({ width, height, longitude, latitude, zoom });
1285
+ }
1286
+ };
1287
+ var WebMercatorViewport = _WebMercatorViewport;
1288
+ WebMercatorViewport.displayName = "WebMercatorViewport";
1289
+
1290
+ // ../core/src/controllers/map-controller.ts
1291
+ var import_core9 = require("@math.gl/core");
1292
+
1293
+ // ../core/src/transitions/transition.ts
1294
+ var Transition = class {
1295
+ /**
1296
+ * @params timeline {Timeline}
1297
+ */
1298
+ constructor(timeline) {
1299
+ this._inProgress = false;
1300
+ this._handle = null;
1301
+ this.time = 0;
1302
+ // @ts-expect-error
1303
+ this.settings = {
1304
+ duration: 0
1305
+ };
1306
+ this._timeline = timeline;
1307
+ }
1308
+ /* Public API */
1309
+ get inProgress() {
1310
+ return this._inProgress;
1311
+ }
1312
+ /**
1313
+ * (re)start this transition.
1314
+ * @params props {object} - optional overriding props. see constructor
1315
+ */
1316
+ start(settings) {
1317
+ var _a, _b;
1318
+ this.cancel();
1319
+ this.settings = settings;
1320
+ this._inProgress = true;
1321
+ (_b = (_a = this.settings).onStart) == null ? void 0 : _b.call(_a, this);
1322
+ }
1323
+ /**
1324
+ * end this transition if it is in progress.
1325
+ */
1326
+ end() {
1327
+ var _a, _b;
1328
+ if (this._inProgress) {
1329
+ this._timeline.removeChannel(this._handle);
1330
+ this._handle = null;
1331
+ this._inProgress = false;
1332
+ (_b = (_a = this.settings).onEnd) == null ? void 0 : _b.call(_a, this);
1333
+ }
1334
+ }
1335
+ /**
1336
+ * cancel this transition if it is in progress.
1337
+ */
1338
+ cancel() {
1339
+ var _a, _b;
1340
+ if (this._inProgress) {
1341
+ (_b = (_a = this.settings).onInterrupt) == null ? void 0 : _b.call(_a, this);
1342
+ this._timeline.removeChannel(this._handle);
1343
+ this._handle = null;
1344
+ this._inProgress = false;
1345
+ }
1346
+ }
1347
+ /**
1348
+ * update this transition. Returns `true` if updated.
1349
+ */
1350
+ update() {
1351
+ var _a, _b;
1352
+ if (!this._inProgress) {
1353
+ return false;
1354
+ }
1355
+ if (this._handle === null) {
1356
+ const { _timeline: timeline, settings } = this;
1357
+ this._handle = timeline.addChannel({
1358
+ delay: timeline.getTime(),
1359
+ duration: settings.duration
1360
+ });
1361
+ }
1362
+ this.time = this._timeline.getTime(this._handle);
1363
+ this._onUpdate();
1364
+ (_b = (_a = this.settings).onUpdate) == null ? void 0 : _b.call(_a, this);
1365
+ if (this._timeline.isFinished(this._handle)) {
1366
+ this.end();
1367
+ }
1368
+ return true;
1369
+ }
1370
+ /* Private API */
1371
+ _onUpdate() {
1372
+ }
1373
+ };
1374
+
1375
+ // ../core/src/controllers/transition-manager.ts
1376
+ var noop = () => {
1377
+ };
1378
+ var TRANSITION_EVENTS = {
1379
+ BREAK: 1,
1380
+ SNAP_TO_END: 2,
1381
+ IGNORE: 3
1382
+ };
1383
+ var DEFAULT_EASING = (t) => t;
1384
+ var DEFAULT_INTERRUPTION = TRANSITION_EVENTS.BREAK;
1385
+ var TransitionManager = class {
1386
+ constructor(opts) {
1387
+ this._onTransitionUpdate = (transition) => {
1388
+ const {
1389
+ time,
1390
+ settings: { interpolator, startProps, endProps, duration, easing }
1391
+ } = transition;
1392
+ const t = easing(time / duration);
1393
+ const viewport = interpolator.interpolateProps(startProps, endProps, t);
1394
+ this.propsInTransition = this.getControllerState({
1395
+ ...this.props,
1396
+ ...viewport
1397
+ }).getViewportProps();
1398
+ this.onViewStateChange({
1399
+ viewState: this.propsInTransition,
1400
+ oldViewState: this.props
1401
+ });
1402
+ };
1403
+ this.getControllerState = opts.getControllerState;
1404
+ this.propsInTransition = null;
1405
+ this.transition = new Transition(opts.timeline);
1406
+ this.onViewStateChange = opts.onViewStateChange || noop;
1407
+ this.onStateChange = opts.onStateChange || noop;
1408
+ }
1409
+ finalize() {
1410
+ this.transition.cancel();
1411
+ }
1412
+ // Returns current transitioned viewport.
1413
+ getViewportInTransition() {
1414
+ return this.propsInTransition;
1415
+ }
1416
+ // Process the vewiport change, either ignore or trigger a new transition.
1417
+ // Return true if a new transition is triggered, false otherwise.
1418
+ processViewStateChange(nextProps) {
1419
+ let transitionTriggered = false;
1420
+ const currentProps = this.props;
1421
+ this.props = nextProps;
1422
+ if (!currentProps || this._shouldIgnoreViewportChange(currentProps, nextProps)) {
1423
+ return false;
1424
+ }
1425
+ if (this._isTransitionEnabled(nextProps)) {
1426
+ let startProps = currentProps;
1427
+ if (this.transition.inProgress) {
1428
+ const { interruption, endProps } = this.transition.settings;
1429
+ startProps = {
1430
+ ...currentProps,
1431
+ ...interruption === TRANSITION_EVENTS.SNAP_TO_END ? endProps : this.propsInTransition || currentProps
1432
+ };
1433
+ }
1434
+ this._triggerTransition(startProps, nextProps);
1435
+ transitionTriggered = true;
1436
+ } else {
1437
+ this.transition.cancel();
1438
+ }
1439
+ return transitionTriggered;
1440
+ }
1441
+ updateTransition() {
1442
+ this.transition.update();
1443
+ }
1444
+ // Helper methods
1445
+ _isTransitionEnabled(props) {
1446
+ const { transitionDuration, transitionInterpolator } = props;
1447
+ return (transitionDuration > 0 || transitionDuration === "auto") && Boolean(transitionInterpolator);
1448
+ }
1449
+ _isUpdateDueToCurrentTransition(props) {
1450
+ if (this.transition.inProgress && this.propsInTransition) {
1451
+ return this.transition.settings.interpolator.arePropsEqual(
1452
+ props,
1453
+ this.propsInTransition
1454
+ );
1455
+ }
1456
+ return false;
1457
+ }
1458
+ _shouldIgnoreViewportChange(currentProps, nextProps) {
1459
+ if (this.transition.inProgress) {
1460
+ const transitionSettings = this.transition.settings;
1461
+ return transitionSettings.interruption === TRANSITION_EVENTS.IGNORE || // Ignore update if it is due to current active transition.
1462
+ this._isUpdateDueToCurrentTransition(nextProps);
1463
+ }
1464
+ if (this._isTransitionEnabled(nextProps)) {
1465
+ return nextProps.transitionInterpolator.arePropsEqual(
1466
+ currentProps,
1467
+ nextProps
1468
+ );
1469
+ }
1470
+ return true;
1471
+ }
1472
+ _triggerTransition(startProps, endProps) {
1473
+ const startViewstate = this.getControllerState(startProps);
1474
+ const endViewStateProps = this.getControllerState(endProps).shortestPathFrom(startViewstate);
1475
+ const transitionInterpolator = endProps.transitionInterpolator;
1476
+ const duration = transitionInterpolator.getDuration ? transitionInterpolator.getDuration(startProps, endProps) : endProps.transitionDuration;
1477
+ if (duration === 0) {
1478
+ return;
1479
+ }
1480
+ const initialProps = transitionInterpolator.initializeProps(startProps, endViewStateProps);
1481
+ this.propsInTransition = {};
1482
+ const transitionSettings = {
1483
+ duration,
1484
+ easing: endProps.transitionEasing || DEFAULT_EASING,
1485
+ interpolator: transitionInterpolator,
1486
+ interruption: endProps.transitionInterruption || DEFAULT_INTERRUPTION,
1487
+ startProps: initialProps.start,
1488
+ endProps: initialProps.end,
1489
+ onStart: endProps.onTransitionStart,
1490
+ onUpdate: this._onTransitionUpdate,
1491
+ onInterrupt: this._onTransitionEnd(endProps.onTransitionInterrupt),
1492
+ onEnd: this._onTransitionEnd(endProps.onTransitionEnd)
1493
+ };
1494
+ this.transition.start(transitionSettings);
1495
+ this.onStateChange({ inTransition: true });
1496
+ this.updateTransition();
1497
+ }
1498
+ _onTransitionEnd(callback) {
1499
+ return (transition) => {
1500
+ this.propsInTransition = null;
1501
+ this.onStateChange({
1502
+ inTransition: false,
1503
+ isZooming: false,
1504
+ isPanning: false,
1505
+ isRotating: false
1506
+ });
1507
+ callback == null ? void 0 : callback(transition);
1508
+ };
1509
+ }
1510
+ };
1511
+
1512
+ // ../core/src/transitions/transition-interpolator.ts
1513
+ var import_core5 = require("@math.gl/core");
1514
+
1515
+ // ../core/src/utils/assert.ts
1516
+ function assert(condition, message) {
1517
+ if (!condition) {
1518
+ throw new Error(message || "deck.gl: assertion failed.");
1519
+ }
1520
+ }
1521
+
1522
+ // ../core/src/transitions/transition-interpolator.ts
1523
+ var TransitionInterpolator = class {
1524
+ /**
1525
+ * @param opts {array|object}
1526
+ * @param opts.compare {array} - prop names used in equality check
1527
+ * @param opts.extract {array} - prop names needed for interpolation
1528
+ * @param opts.required {array} - prop names that must be supplied
1529
+ * alternatively, supply one list of prop names as `opts` if all of the above are the same.
1530
+ */
1531
+ constructor(opts) {
1532
+ const { compare, extract, required } = opts;
1533
+ this._propsToCompare = compare;
1534
+ this._propsToExtract = extract || compare;
1535
+ this._requiredProps = required;
1536
+ }
1537
+ /**
1538
+ * Checks if two sets of props need transition in between
1539
+ * @param currentProps {object} - a list of viewport props
1540
+ * @param nextProps {object} - a list of viewport props
1541
+ * @returns {bool} - true if two props are equivalent
1542
+ */
1543
+ arePropsEqual(currentProps, nextProps) {
1544
+ for (const key of this._propsToCompare) {
1545
+ if (!(key in currentProps) || !(key in nextProps) || !(0, import_core5.equals)(currentProps[key], nextProps[key])) {
1546
+ return false;
1547
+ }
1548
+ }
1549
+ return true;
1550
+ }
1551
+ /**
1552
+ * Called before transition starts to validate/pre-process start and end props
1553
+ * @param startProps {object} - a list of starting viewport props
1554
+ * @param endProps {object} - a list of target viewport props
1555
+ * @returns {Object} {start, end} - start and end props to be passed
1556
+ * to `interpolateProps`
1557
+ */
1558
+ initializeProps(startProps, endProps) {
1559
+ const startViewStateProps = {};
1560
+ const endViewStateProps = {};
1561
+ for (const key of this._propsToExtract) {
1562
+ if (key in startProps || key in endProps) {
1563
+ startViewStateProps[key] = startProps[key];
1564
+ endViewStateProps[key] = endProps[key];
1565
+ }
1566
+ }
1567
+ this._checkRequiredProps(startViewStateProps);
1568
+ this._checkRequiredProps(endViewStateProps);
1569
+ return { start: startViewStateProps, end: endViewStateProps };
1570
+ }
1571
+ /**
1572
+ * Returns transition duration
1573
+ * @param startProps {object} - a list of starting viewport props
1574
+ * @param endProps {object} - a list of target viewport props
1575
+ * @returns {Number} - transition duration in milliseconds
1576
+ */
1577
+ getDuration(startProps, endProps) {
1578
+ return endProps.transitionDuration;
1579
+ }
1580
+ _checkRequiredProps(props) {
1581
+ if (!this._requiredProps) {
1582
+ return;
1583
+ }
1584
+ this._requiredProps.forEach((propName) => {
1585
+ const value = props[propName];
1586
+ assert(
1587
+ Number.isFinite(value) || Array.isArray(value),
1588
+ `${propName} is required for transition`
1589
+ );
1590
+ });
1591
+ }
1592
+ };
1593
+
1594
+ // ../core/src/transitions/linear-interpolator.ts
1595
+ var import_core8 = require("@math.gl/core");
1596
+
1597
+ // ../core/src/viewports/globe-viewport.ts
1598
+ var import_core6 = require("@math.gl/core");
1599
+ var import_web_mercator3 = require("@math.gl/web-mercator");
1600
+ var import_web_mercator4 = require("@math.gl/web-mercator");
1601
+ var import_core7 = require("@math.gl/core");
1602
+ var DEGREES_TO_RADIANS2 = Math.PI / 180;
1603
+ var RADIANS_TO_DEGREES = 180 / Math.PI;
1604
+ var EARTH_RADIUS = 6370972;
1605
+ var GLOBE_RADIUS = 256;
1606
+ function getDistanceScales2() {
1607
+ const unitsPerMeter2 = GLOBE_RADIUS / EARTH_RADIUS;
1608
+ const unitsPerDegree = Math.PI / 180 * GLOBE_RADIUS;
1609
+ return {
1610
+ unitsPerMeter: [unitsPerMeter2, unitsPerMeter2, unitsPerMeter2],
1611
+ unitsPerMeter2: [0, 0, 0],
1612
+ metersPerUnit: [1 / unitsPerMeter2, 1 / unitsPerMeter2, 1 / unitsPerMeter2],
1613
+ unitsPerDegree: [unitsPerDegree, unitsPerDegree, unitsPerMeter2],
1614
+ unitsPerDegree2: [0, 0, 0],
1615
+ degreesPerUnit: [1 / unitsPerDegree, 1 / unitsPerDegree, 1 / unitsPerMeter2]
1616
+ };
1617
+ }
1618
+ var GlobeViewport = class extends Viewport {
1619
+ constructor(opts = {}) {
1620
+ const {
1621
+ longitude = 0,
1622
+ zoom = 0,
1623
+ // Matches Maplibre defaults
1624
+ // https://github.com/maplibre/maplibre-gl-js/blob/f8ab4b48d59ab8fe7b068b102538793bbdd4c848/src/geo/projection/globe_transform.ts#L632-L633
1625
+ nearZMultiplier = 0.5,
1626
+ farZMultiplier = 1,
1627
+ resolution = 10
1628
+ } = opts;
1629
+ let { latitude = 0, height, altitude = 1.5, fovy } = opts;
1630
+ latitude = Math.max(Math.min(latitude, import_web_mercator4.MAX_LATITUDE), -import_web_mercator4.MAX_LATITUDE);
1631
+ height = height || 1;
1632
+ if (fovy) {
1633
+ altitude = (0, import_web_mercator3.fovyToAltitude)(fovy);
1634
+ } else {
1635
+ fovy = (0, import_web_mercator3.altitudeToFovy)(altitude);
1636
+ }
1637
+ const scale = Math.pow(2, zoom - zoomAdjust(latitude));
1638
+ const nearZ = opts.nearZ ?? nearZMultiplier;
1639
+ const farZ = opts.farZ ?? (altitude + GLOBE_RADIUS * 2 * scale / height) * farZMultiplier;
1640
+ const viewMatrix = new import_core6.Matrix4().lookAt({ eye: [0, -altitude, 0], up: [0, 0, 1] });
1641
+ viewMatrix.rotateX(latitude * DEGREES_TO_RADIANS2);
1642
+ viewMatrix.rotateZ(-longitude * DEGREES_TO_RADIANS2);
1643
+ viewMatrix.scale(scale / height);
1644
+ super({
1645
+ ...opts,
1646
+ // x, y, width,
1647
+ height,
1648
+ // view matrix
1649
+ viewMatrix,
1650
+ longitude,
1651
+ latitude,
1652
+ zoom,
1653
+ // projection matrix parameters
1654
+ distanceScales: getDistanceScales2(),
1655
+ fovy,
1656
+ focalDistance: altitude,
1657
+ near: nearZ,
1658
+ far: farZ
1659
+ });
1660
+ this.scale = scale;
1661
+ this.latitude = latitude;
1662
+ this.longitude = longitude;
1663
+ this.fovy = fovy;
1664
+ this.resolution = resolution;
1665
+ }
1666
+ get projectionMode() {
1667
+ return PROJECTION_MODE.GLOBE;
1668
+ }
1669
+ getDistanceScales() {
1670
+ return this.distanceScales;
1671
+ }
1672
+ getBounds(options = {}) {
1673
+ const unprojectOption = { targetZ: options.z || 0 };
1674
+ const left = this.unproject([0, this.height / 2], unprojectOption);
1675
+ const top = this.unproject([this.width / 2, 0], unprojectOption);
1676
+ const right = this.unproject([this.width, this.height / 2], unprojectOption);
1677
+ const bottom = this.unproject([this.width / 2, this.height], unprojectOption);
1678
+ if (right[0] < this.longitude)
1679
+ right[0] += 360;
1680
+ if (left[0] > this.longitude)
1681
+ left[0] -= 360;
1682
+ return [
1683
+ Math.min(left[0], right[0], top[0], bottom[0]),
1684
+ Math.min(left[1], right[1], top[1], bottom[1]),
1685
+ Math.max(left[0], right[0], top[0], bottom[0]),
1686
+ Math.max(left[1], right[1], top[1], bottom[1])
1687
+ ];
1688
+ }
1689
+ unproject(xyz, { topLeft = true, targetZ } = {}) {
1690
+ const [x, y, z] = xyz;
1691
+ const y2 = topLeft ? y : this.height - y;
1692
+ const { pixelUnprojectionMatrix } = this;
1693
+ let coord;
1694
+ if (Number.isFinite(z)) {
1695
+ coord = transformVector(pixelUnprojectionMatrix, [x, y2, z, 1]);
1696
+ } else {
1697
+ const coord0 = transformVector(pixelUnprojectionMatrix, [x, y2, -1, 1]);
1698
+ const coord1 = transformVector(pixelUnprojectionMatrix, [x, y2, 1, 1]);
1699
+ const lt = ((targetZ || 0) / EARTH_RADIUS + 1) * GLOBE_RADIUS;
1700
+ const lSqr = import_core7.vec3.sqrLen(import_core7.vec3.sub([], coord0, coord1));
1701
+ const l0Sqr = import_core7.vec3.sqrLen(coord0);
1702
+ const l1Sqr = import_core7.vec3.sqrLen(coord1);
1703
+ const sSqr = (4 * l0Sqr * l1Sqr - (lSqr - l0Sqr - l1Sqr) ** 2) / 16;
1704
+ const dSqr = 4 * sSqr / lSqr;
1705
+ const r0 = Math.sqrt(l0Sqr - dSqr);
1706
+ const dr = Math.sqrt(Math.max(0, lt * lt - dSqr));
1707
+ const t = (r0 - dr) / Math.sqrt(lSqr);
1708
+ coord = import_core7.vec3.lerp([], coord0, coord1, t);
1709
+ }
1710
+ const [X, Y, Z] = this.unprojectPosition(coord);
1711
+ if (Number.isFinite(z)) {
1712
+ return [X, Y, Z];
1713
+ }
1714
+ return Number.isFinite(targetZ) ? [X, Y, targetZ] : [X, Y];
1715
+ }
1716
+ projectPosition(xyz) {
1717
+ const [lng, lat, Z = 0] = xyz;
1718
+ const lambda = lng * DEGREES_TO_RADIANS2;
1719
+ const phi = lat * DEGREES_TO_RADIANS2;
1720
+ const cosPhi = Math.cos(phi);
1721
+ const D = (Z / EARTH_RADIUS + 1) * GLOBE_RADIUS;
1722
+ return [Math.sin(lambda) * cosPhi * D, -Math.cos(lambda) * cosPhi * D, Math.sin(phi) * D];
1723
+ }
1724
+ unprojectPosition(xyz) {
1725
+ const [x, y, z] = xyz;
1726
+ const D = import_core7.vec3.len(xyz);
1727
+ const phi = Math.asin(z / D);
1728
+ const lambda = Math.atan2(x, -y);
1729
+ const lng = lambda * RADIANS_TO_DEGREES;
1730
+ const lat = phi * RADIANS_TO_DEGREES;
1731
+ const Z = (D / GLOBE_RADIUS - 1) * EARTH_RADIUS;
1732
+ return [lng, lat, Z];
1733
+ }
1734
+ projectFlat(xyz) {
1735
+ return xyz;
1736
+ }
1737
+ unprojectFlat(xyz) {
1738
+ return xyz;
1739
+ }
1740
+ /**
1741
+ * Pan the globe using delta-based movement
1742
+ * @param coords - the geographic coordinates where the pan started
1743
+ * @param pixel - the current screen position
1744
+ * @param startPixel - the screen position where the pan started
1745
+ * @returns updated viewport options with new longitude/latitude
1746
+ */
1747
+ panByPosition([startLng, startLat, startZoom], pixel, startPixel) {
1748
+ const scale = Math.pow(2, this.zoom - zoomAdjust(this.latitude));
1749
+ const rotationSpeed = 0.25 / scale;
1750
+ const longitude = startLng + rotationSpeed * (startPixel[0] - pixel[0]);
1751
+ let latitude = startLat - rotationSpeed * (startPixel[1] - pixel[1]);
1752
+ latitude = Math.max(Math.min(latitude, import_web_mercator4.MAX_LATITUDE), -import_web_mercator4.MAX_LATITUDE);
1753
+ const out = { longitude, latitude, zoom: startZoom - zoomAdjust(startLat) };
1754
+ out.zoom += zoomAdjust(out.latitude);
1755
+ return out;
1756
+ }
1757
+ };
1758
+ GlobeViewport.displayName = "GlobeViewport";
1759
+ function zoomAdjust(latitude) {
1760
+ const scaleAdjust = Math.PI * Math.cos(latitude * Math.PI / 180);
1761
+ return Math.log2(scaleAdjust);
1762
+ }
1763
+ function transformVector(matrix, vector) {
1764
+ const result = import_core7.vec4.transformMat4([], vector, matrix);
1765
+ import_core7.vec4.scale(result, result, 1 / result[3]);
1766
+ return result;
1767
+ }
1768
+
1769
+ // ../core/src/transitions/linear-interpolator.ts
1770
+ var DEFAULT_PROPS = ["longitude", "latitude", "zoom", "bearing", "pitch"];
1771
+ var DEFAULT_REQUIRED_PROPS = ["longitude", "latitude", "zoom"];
1772
+ var LinearInterpolator = class extends TransitionInterpolator {
1773
+ /**
1774
+ * @param {Object} opts
1775
+ * @param {Array} opts.transitionProps - list of props to apply linear transition to.
1776
+ * @param {Array} opts.around - a screen point to zoom/rotate around.
1777
+ * @param {Function} opts.makeViewport - construct a viewport instance with given props.
1778
+ */
1779
+ constructor(opts = {}) {
1780
+ const transitionProps = Array.isArray(opts) ? opts : opts.transitionProps;
1781
+ const normalizedOpts = Array.isArray(opts) ? {} : opts;
1782
+ normalizedOpts.transitionProps = Array.isArray(transitionProps) ? {
1783
+ compare: transitionProps,
1784
+ required: transitionProps
1785
+ } : transitionProps || {
1786
+ compare: DEFAULT_PROPS,
1787
+ required: DEFAULT_REQUIRED_PROPS
1788
+ };
1789
+ super(normalizedOpts.transitionProps);
1790
+ this.opts = normalizedOpts;
1791
+ }
1792
+ initializeProps(startProps, endProps) {
1793
+ const result = super.initializeProps(startProps, endProps);
1794
+ const { makeViewport, around } = this.opts;
1795
+ if (makeViewport && around) {
1796
+ const TestViewport = makeViewport(startProps);
1797
+ if (TestViewport instanceof GlobeViewport) {
1798
+ log_default.warn("around not supported in GlobeView")();
1799
+ } else {
1800
+ const startViewport = makeViewport(startProps);
1801
+ const endViewport = makeViewport(endProps);
1802
+ const aroundPosition = startViewport.unproject(around);
1803
+ result.start.around = around;
1804
+ Object.assign(result.end, {
1805
+ around: endViewport.project(aroundPosition),
1806
+ aroundPosition,
1807
+ width: endProps.width,
1808
+ height: endProps.height
1809
+ });
1810
+ }
1811
+ }
1812
+ return result;
1813
+ }
1814
+ interpolateProps(startProps, endProps, t) {
1815
+ const propsInTransition = {};
1816
+ for (const key of this._propsToExtract) {
1817
+ propsInTransition[key] = (0, import_core8.lerp)(startProps[key] || 0, endProps[key] || 0, t);
1818
+ }
1819
+ if (endProps.aroundPosition && this.opts.makeViewport) {
1820
+ const viewport = this.opts.makeViewport({ ...endProps, ...propsInTransition });
1821
+ Object.assign(
1822
+ propsInTransition,
1823
+ viewport.panByPosition(
1824
+ endProps.aroundPosition,
1825
+ // anchor point in current screen coordinates
1826
+ (0, import_core8.lerp)(startProps.around, endProps.around, t)
1827
+ )
1828
+ );
1829
+ }
1830
+ return propsInTransition;
1831
+ }
1832
+ };
1833
+
1834
+ // ../core/src/controllers/controller.ts
1835
+ var NO_TRANSITION_PROPS = {
1836
+ transitionDuration: 0
1837
+ };
1838
+ var DEFAULT_INERTIA = 300;
1839
+ var INERTIA_EASING = (t) => 1 - (1 - t) * (1 - t);
1840
+ var EVENT_TYPES = {
1841
+ WHEEL: ["wheel"],
1842
+ PAN: ["panstart", "panmove", "panend"],
1843
+ PINCH: ["pinchstart", "pinchmove", "pinchend"],
1844
+ MULTI_PAN: ["multipanstart", "multipanmove", "multipanend"],
1845
+ DOUBLE_CLICK: ["dblclick"],
1846
+ KEYBOARD: ["keydown"]
1847
+ };
1848
+ var pinchEventWorkaround = {};
1849
+ var Controller = class {
1850
+ constructor(opts) {
1851
+ this.state = {};
1852
+ this._events = {};
1853
+ this._interactionState = {
1854
+ isDragging: false
1855
+ };
1856
+ this._customEvents = [];
1857
+ this._eventStartBlocked = null;
1858
+ this._panMove = false;
1859
+ this.invertPan = false;
1860
+ this.dragMode = "rotate";
1861
+ this.inertia = 0;
1862
+ this.scrollZoom = true;
1863
+ this.dragPan = true;
1864
+ this.dragRotate = true;
1865
+ this.doubleClickZoom = true;
1866
+ this.touchZoom = true;
1867
+ this.touchRotate = false;
1868
+ this.keyboard = true;
1869
+ this.transitionManager = new TransitionManager({
1870
+ ...opts,
1871
+ getControllerState: (props) => new this.ControllerState(props),
1872
+ onViewStateChange: this._onTransition.bind(this),
1873
+ onStateChange: this._setInteractionState.bind(this)
1874
+ });
1875
+ this.handleEvent = this.handleEvent.bind(this);
1876
+ this.eventManager = opts.eventManager;
1877
+ this.onViewStateChange = opts.onViewStateChange || (() => {
1878
+ });
1879
+ this.onStateChange = opts.onStateChange || (() => {
1880
+ });
1881
+ this.makeViewport = opts.makeViewport;
1882
+ this.pickPosition = opts.pickPosition;
1883
+ }
1884
+ set events(customEvents) {
1885
+ this.toggleEvents(this._customEvents, false);
1886
+ this.toggleEvents(customEvents, true);
1887
+ this._customEvents = customEvents;
1888
+ if (this.props) {
1889
+ this.setProps(this.props);
1890
+ }
1891
+ }
1892
+ finalize() {
1893
+ var _a;
1894
+ for (const eventName in this._events) {
1895
+ if (this._events[eventName]) {
1896
+ (_a = this.eventManager) == null ? void 0 : _a.off(eventName, this.handleEvent);
1897
+ }
1898
+ }
1899
+ this.transitionManager.finalize();
1900
+ }
1901
+ /**
1902
+ * Callback for events
1903
+ */
1904
+ handleEvent(event) {
1905
+ this._controllerState = void 0;
1906
+ const eventStartBlocked = this._eventStartBlocked;
1907
+ switch (event.type) {
1908
+ case "panstart":
1909
+ return eventStartBlocked ? false : this._onPanStart(event);
1910
+ case "panmove":
1911
+ return this._onPan(event);
1912
+ case "panend":
1913
+ return this._onPanEnd(event);
1914
+ case "pinchstart":
1915
+ return eventStartBlocked ? false : this._onPinchStart(event);
1916
+ case "pinchmove":
1917
+ return this._onPinch(event);
1918
+ case "pinchend":
1919
+ return this._onPinchEnd(event);
1920
+ case "multipanstart":
1921
+ return eventStartBlocked ? false : this._onMultiPanStart(event);
1922
+ case "multipanmove":
1923
+ return this._onMultiPan(event);
1924
+ case "multipanend":
1925
+ return this._onMultiPanEnd(event);
1926
+ case "dblclick":
1927
+ return this._onDoubleClick(event);
1928
+ case "wheel":
1929
+ return this._onWheel(event);
1930
+ case "keydown":
1931
+ return this._onKeyDown(event);
1932
+ default:
1933
+ return false;
1934
+ }
1935
+ }
1936
+ /* Event utils */
1937
+ // Event object: http://hammerjs.github.io/api/#event-object
1938
+ get controllerState() {
1939
+ this._controllerState = this._controllerState || new this.ControllerState({
1940
+ makeViewport: this.makeViewport,
1941
+ ...this.props,
1942
+ ...this.state
1943
+ });
1944
+ return this._controllerState;
1945
+ }
1946
+ getCenter(event) {
1947
+ const { x, y } = this.props;
1948
+ const { offsetCenter } = event;
1949
+ return [offsetCenter.x - x, offsetCenter.y - y];
1950
+ }
1951
+ isPointInBounds(pos, event) {
1952
+ const { width, height } = this.props;
1953
+ if (event && event.handled) {
1954
+ return false;
1955
+ }
1956
+ const inside = pos[0] >= 0 && pos[0] <= width && pos[1] >= 0 && pos[1] <= height;
1957
+ if (inside && event) {
1958
+ event.stopPropagation();
1959
+ }
1960
+ return inside;
1961
+ }
1962
+ isFunctionKeyPressed(event) {
1963
+ const { srcEvent } = event;
1964
+ return Boolean(srcEvent.metaKey || srcEvent.altKey || srcEvent.ctrlKey || srcEvent.shiftKey);
1965
+ }
1966
+ isDragging() {
1967
+ return this._interactionState.isDragging || false;
1968
+ }
1969
+ // When a multi-touch event ends, e.g. pinch, not all pointers are lifted at the same time.
1970
+ // This triggers a brief `pan` event.
1971
+ // Calling this method will temporarily disable *start events to avoid conflicting transitions.
1972
+ blockEvents(timeout) {
1973
+ const timer = setTimeout(() => {
1974
+ if (this._eventStartBlocked === timer) {
1975
+ this._eventStartBlocked = null;
1976
+ }
1977
+ }, timeout);
1978
+ this._eventStartBlocked = timer;
1979
+ }
1980
+ /**
1981
+ * Extract interactivity options
1982
+ */
1983
+ setProps(props) {
1984
+ if (props.dragMode) {
1985
+ this.dragMode = props.dragMode;
1986
+ }
1987
+ const oldProps = this.props;
1988
+ this.props = props;
1989
+ if (!("transitionInterpolator" in props)) {
1990
+ props.transitionInterpolator = this._getTransitionProps().transitionInterpolator;
1991
+ }
1992
+ this.transitionManager.processViewStateChange(props);
1993
+ const { inertia } = props;
1994
+ this.inertia = Number.isFinite(inertia) ? inertia : inertia === true ? DEFAULT_INERTIA : 0;
1995
+ const {
1996
+ scrollZoom = true,
1997
+ dragPan = true,
1998
+ dragRotate = true,
1999
+ doubleClickZoom = true,
2000
+ touchZoom = true,
2001
+ touchRotate = false,
2002
+ keyboard = true
2003
+ } = props;
2004
+ const isInteractive = Boolean(this.onViewStateChange);
2005
+ this.toggleEvents(EVENT_TYPES.WHEEL, isInteractive && scrollZoom);
2006
+ this.toggleEvents(EVENT_TYPES.PAN, isInteractive);
2007
+ this.toggleEvents(EVENT_TYPES.PINCH, isInteractive && (touchZoom || touchRotate));
2008
+ this.toggleEvents(EVENT_TYPES.MULTI_PAN, isInteractive && touchRotate);
2009
+ this.toggleEvents(EVENT_TYPES.DOUBLE_CLICK, isInteractive && doubleClickZoom);
2010
+ this.toggleEvents(EVENT_TYPES.KEYBOARD, isInteractive && keyboard);
2011
+ this.scrollZoom = scrollZoom;
2012
+ this.dragPan = dragPan;
2013
+ this.dragRotate = dragRotate;
2014
+ this.doubleClickZoom = doubleClickZoom;
2015
+ this.touchZoom = touchZoom;
2016
+ this.touchRotate = touchRotate;
2017
+ this.keyboard = keyboard;
2018
+ const dimensionChanged = !oldProps || oldProps.height !== props.height || oldProps.width !== props.width || oldProps.maxBounds !== props.maxBounds;
2019
+ if (dimensionChanged && props.maxBounds) {
2020
+ const controllerState = new this.ControllerState({ ...props, makeViewport: this.makeViewport });
2021
+ const normalizedProps = controllerState.getViewportProps();
2022
+ const changed = Object.keys(normalizedProps).some((key) => !deepEqual(normalizedProps[key], props[key], 1));
2023
+ if (changed) {
2024
+ this.updateViewport(controllerState);
2025
+ }
2026
+ }
2027
+ }
2028
+ updateTransition() {
2029
+ this.transitionManager.updateTransition();
2030
+ }
2031
+ toggleEvents(eventNames, enabled) {
2032
+ if (this.eventManager) {
2033
+ eventNames.forEach((eventName) => {
2034
+ if (this._events[eventName] !== enabled) {
2035
+ this._events[eventName] = enabled;
2036
+ if (enabled) {
2037
+ this.eventManager.on(eventName, this.handleEvent);
2038
+ } else {
2039
+ this.eventManager.off(eventName, this.handleEvent);
2040
+ }
2041
+ }
2042
+ });
2043
+ }
2044
+ }
2045
+ // Private Methods
2046
+ /* Callback util */
2047
+ // formats map state and invokes callback function
2048
+ updateViewport(newControllerState, extraProps = null, interactionState = {}) {
2049
+ const viewState = { ...newControllerState.getViewportProps(), ...extraProps };
2050
+ const changed = this.controllerState !== newControllerState;
2051
+ this.state = newControllerState.getState();
2052
+ this._setInteractionState(interactionState);
2053
+ if (changed) {
2054
+ const oldViewState = this.controllerState && this.controllerState.getViewportProps();
2055
+ if (this.onViewStateChange) {
2056
+ this.onViewStateChange({ viewState, interactionState: this._interactionState, oldViewState, viewId: this.props.id });
2057
+ }
2058
+ }
2059
+ }
2060
+ _onTransition(params) {
2061
+ this.onViewStateChange({ ...params, interactionState: this._interactionState, viewId: this.props.id });
2062
+ }
2063
+ _setInteractionState(newStates) {
2064
+ Object.assign(this._interactionState, newStates);
2065
+ this.onStateChange(this._interactionState);
2066
+ }
2067
+ /* Event handlers */
2068
+ // Default handler for the `panstart` event.
2069
+ _onPanStart(event) {
2070
+ const pos = this.getCenter(event);
2071
+ if (!this.isPointInBounds(pos, event)) {
2072
+ return false;
2073
+ }
2074
+ let alternateMode = this.isFunctionKeyPressed(event) || event.rightButton || false;
2075
+ if (this.invertPan || this.dragMode === "pan") {
2076
+ alternateMode = !alternateMode;
2077
+ }
2078
+ const newControllerState = this.controllerState[alternateMode ? "panStart" : "rotateStart"]({
2079
+ pos
2080
+ });
2081
+ this._panMove = alternateMode;
2082
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, { isDragging: true });
2083
+ return true;
2084
+ }
2085
+ // Default handler for the `panmove` and `panend` event.
2086
+ _onPan(event) {
2087
+ if (!this.isDragging()) {
2088
+ return false;
2089
+ }
2090
+ return this._panMove ? this._onPanMove(event) : this._onPanRotate(event);
2091
+ }
2092
+ _onPanEnd(event) {
2093
+ if (!this.isDragging()) {
2094
+ return false;
2095
+ }
2096
+ return this._panMove ? this._onPanMoveEnd(event) : this._onPanRotateEnd(event);
2097
+ }
2098
+ // Default handler for panning to move.
2099
+ // Called by `_onPan` when panning without function key pressed.
2100
+ _onPanMove(event) {
2101
+ if (!this.dragPan) {
2102
+ return false;
2103
+ }
2104
+ const pos = this.getCenter(event);
2105
+ const newControllerState = this.controllerState.pan({ pos });
2106
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
2107
+ isDragging: true,
2108
+ isPanning: true
2109
+ });
2110
+ return true;
2111
+ }
2112
+ _onPanMoveEnd(event) {
2113
+ const { inertia } = this;
2114
+ if (this.dragPan && inertia && event.velocity) {
2115
+ const pos = this.getCenter(event);
2116
+ const endPos = [
2117
+ pos[0] + event.velocityX * inertia / 2,
2118
+ pos[1] + event.velocityY * inertia / 2
2119
+ ];
2120
+ const newControllerState = this.controllerState.pan({ pos: endPos }).panEnd();
2121
+ this.updateViewport(
2122
+ newControllerState,
2123
+ {
2124
+ ...this._getTransitionProps(),
2125
+ transitionDuration: inertia,
2126
+ transitionEasing: INERTIA_EASING
2127
+ },
2128
+ {
2129
+ isDragging: false,
2130
+ isPanning: true
2131
+ }
2132
+ );
2133
+ } else {
2134
+ const newControllerState = this.controllerState.panEnd();
2135
+ this.updateViewport(newControllerState, null, {
2136
+ isDragging: false,
2137
+ isPanning: false
2138
+ });
2139
+ }
2140
+ return true;
2141
+ }
2142
+ // Default handler for panning to rotate.
2143
+ // Called by `_onPan` when panning with function key pressed.
2144
+ _onPanRotate(event) {
2145
+ if (!this.dragRotate) {
2146
+ return false;
2147
+ }
2148
+ const pos = this.getCenter(event);
2149
+ const newControllerState = this.controllerState.rotate({ pos });
2150
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
2151
+ isDragging: true,
2152
+ isRotating: true
2153
+ });
2154
+ return true;
2155
+ }
2156
+ _onPanRotateEnd(event) {
2157
+ const { inertia } = this;
2158
+ if (this.dragRotate && inertia && event.velocity) {
2159
+ const pos = this.getCenter(event);
2160
+ const endPos = [
2161
+ pos[0] + event.velocityX * inertia / 2,
2162
+ pos[1] + event.velocityY * inertia / 2
2163
+ ];
2164
+ const newControllerState = this.controllerState.rotate({ pos: endPos }).rotateEnd();
2165
+ this.updateViewport(
2166
+ newControllerState,
2167
+ {
2168
+ ...this._getTransitionProps(),
2169
+ transitionDuration: inertia,
2170
+ transitionEasing: INERTIA_EASING
2171
+ },
2172
+ {
2173
+ isDragging: false,
2174
+ isRotating: true
2175
+ }
2176
+ );
2177
+ } else {
2178
+ const newControllerState = this.controllerState.rotateEnd();
2179
+ this.updateViewport(newControllerState, null, {
2180
+ isDragging: false,
2181
+ isRotating: false
2182
+ });
2183
+ }
2184
+ return true;
2185
+ }
2186
+ // Default handler for the `wheel` event.
2187
+ _onWheel(event) {
2188
+ if (!this.scrollZoom) {
2189
+ return false;
2190
+ }
2191
+ const pos = this.getCenter(event);
2192
+ if (!this.isPointInBounds(pos, event)) {
2193
+ return false;
2194
+ }
2195
+ event.srcEvent.preventDefault();
2196
+ const { speed = 0.01, smooth = false } = this.scrollZoom === true ? {} : this.scrollZoom;
2197
+ const { delta } = event;
2198
+ let scale = 2 / (1 + Math.exp(-Math.abs(delta * speed)));
2199
+ if (delta < 0 && scale !== 0) {
2200
+ scale = 1 / scale;
2201
+ }
2202
+ const transitionProps = smooth ? { ...this._getTransitionProps({ around: pos }), transitionDuration: 250 } : NO_TRANSITION_PROPS;
2203
+ const newControllerState = this.controllerState.zoom({ pos, scale });
2204
+ this.updateViewport(
2205
+ newControllerState,
2206
+ transitionProps,
2207
+ {
2208
+ isZooming: true,
2209
+ isPanning: true
2210
+ }
2211
+ );
2212
+ if (!smooth) {
2213
+ this._setInteractionState({ isZooming: false, isPanning: false });
2214
+ }
2215
+ return true;
2216
+ }
2217
+ _onMultiPanStart(event) {
2218
+ const pos = this.getCenter(event);
2219
+ if (!this.isPointInBounds(pos, event)) {
2220
+ return false;
2221
+ }
2222
+ const newControllerState = this.controllerState.rotateStart({ pos });
2223
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, { isDragging: true });
2224
+ return true;
2225
+ }
2226
+ _onMultiPan(event) {
2227
+ if (!this.touchRotate) {
2228
+ return false;
2229
+ }
2230
+ if (!this.isDragging()) {
2231
+ return false;
2232
+ }
2233
+ const pos = this.getCenter(event);
2234
+ pos[0] -= event.deltaX;
2235
+ const newControllerState = this.controllerState.rotate({ pos });
2236
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
2237
+ isDragging: true,
2238
+ isRotating: true
2239
+ });
2240
+ return true;
2241
+ }
2242
+ _onMultiPanEnd(event) {
2243
+ if (!this.isDragging()) {
2244
+ return false;
2245
+ }
2246
+ const { inertia } = this;
2247
+ if (this.touchRotate && inertia && event.velocityY) {
2248
+ const pos = this.getCenter(event);
2249
+ const endPos = [pos[0], pos[1] += event.velocityY * inertia / 2];
2250
+ const newControllerState = this.controllerState.rotate({ pos: endPos });
2251
+ this.updateViewport(
2252
+ newControllerState,
2253
+ {
2254
+ ...this._getTransitionProps(),
2255
+ transitionDuration: inertia,
2256
+ transitionEasing: INERTIA_EASING
2257
+ },
2258
+ {
2259
+ isDragging: false,
2260
+ isRotating: true
2261
+ }
2262
+ );
2263
+ this.blockEvents(inertia);
2264
+ } else {
2265
+ const newControllerState = this.controllerState.rotateEnd();
2266
+ this.updateViewport(newControllerState, null, {
2267
+ isDragging: false,
2268
+ isRotating: false
2269
+ });
2270
+ }
2271
+ return true;
2272
+ }
2273
+ // Default handler for the `pinchstart` event.
2274
+ _onPinchStart(event) {
2275
+ const pos = this.getCenter(event);
2276
+ if (!this.isPointInBounds(pos, event)) {
2277
+ return false;
2278
+ }
2279
+ const newControllerState = this.controllerState.zoomStart({ pos }).rotateStart({ pos });
2280
+ pinchEventWorkaround._startPinchRotation = event.rotation;
2281
+ pinchEventWorkaround._lastPinchEvent = event;
2282
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, { isDragging: true });
2283
+ return true;
2284
+ }
2285
+ // Default handler for the `pinchmove` and `pinchend` events.
2286
+ _onPinch(event) {
2287
+ if (!this.touchZoom && !this.touchRotate) {
2288
+ return false;
2289
+ }
2290
+ if (!this.isDragging()) {
2291
+ return false;
2292
+ }
2293
+ let newControllerState = this.controllerState;
2294
+ if (this.touchZoom) {
2295
+ const { scale } = event;
2296
+ const pos = this.getCenter(event);
2297
+ newControllerState = newControllerState.zoom({ pos, scale });
2298
+ }
2299
+ if (this.touchRotate) {
2300
+ const { rotation } = event;
2301
+ newControllerState = newControllerState.rotate({
2302
+ deltaAngleX: pinchEventWorkaround._startPinchRotation - rotation
2303
+ });
2304
+ }
2305
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
2306
+ isDragging: true,
2307
+ isPanning: this.touchZoom,
2308
+ isZooming: this.touchZoom,
2309
+ isRotating: this.touchRotate
2310
+ });
2311
+ pinchEventWorkaround._lastPinchEvent = event;
2312
+ return true;
2313
+ }
2314
+ _onPinchEnd(event) {
2315
+ if (!this.isDragging()) {
2316
+ return false;
2317
+ }
2318
+ const { inertia } = this;
2319
+ const { _lastPinchEvent } = pinchEventWorkaround;
2320
+ if (this.touchZoom && inertia && _lastPinchEvent && event.scale !== _lastPinchEvent.scale) {
2321
+ const pos = this.getCenter(event);
2322
+ let newControllerState = this.controllerState.rotateEnd();
2323
+ const z = Math.log2(event.scale);
2324
+ const velocityZ = (z - Math.log2(_lastPinchEvent.scale)) / (event.deltaTime - _lastPinchEvent.deltaTime);
2325
+ const endScale = Math.pow(2, z + velocityZ * inertia / 2);
2326
+ newControllerState = newControllerState.zoom({ pos, scale: endScale }).zoomEnd();
2327
+ this.updateViewport(
2328
+ newControllerState,
2329
+ {
2330
+ ...this._getTransitionProps({ around: pos }),
2331
+ transitionDuration: inertia,
2332
+ transitionEasing: INERTIA_EASING
2333
+ },
2334
+ {
2335
+ isDragging: false,
2336
+ isPanning: this.touchZoom,
2337
+ isZooming: this.touchZoom,
2338
+ isRotating: false
2339
+ }
2340
+ );
2341
+ this.blockEvents(inertia);
2342
+ } else {
2343
+ const newControllerState = this.controllerState.zoomEnd().rotateEnd();
2344
+ this.updateViewport(newControllerState, null, {
2345
+ isDragging: false,
2346
+ isPanning: false,
2347
+ isZooming: false,
2348
+ isRotating: false
2349
+ });
2350
+ }
2351
+ pinchEventWorkaround._startPinchRotation = null;
2352
+ pinchEventWorkaround._lastPinchEvent = null;
2353
+ return true;
2354
+ }
2355
+ // Default handler for the `dblclick` event.
2356
+ _onDoubleClick(event) {
2357
+ if (!this.doubleClickZoom) {
2358
+ return false;
2359
+ }
2360
+ const pos = this.getCenter(event);
2361
+ if (!this.isPointInBounds(pos, event)) {
2362
+ return false;
2363
+ }
2364
+ const isZoomOut = this.isFunctionKeyPressed(event);
2365
+ const newControllerState = this.controllerState.zoom({ pos, scale: isZoomOut ? 0.5 : 2 });
2366
+ this.updateViewport(newControllerState, this._getTransitionProps({ around: pos }), {
2367
+ isZooming: true,
2368
+ isPanning: true
2369
+ });
2370
+ this.blockEvents(100);
2371
+ return true;
2372
+ }
2373
+ // Default handler for the `keydown` event
2374
+ _onKeyDown(event) {
2375
+ if (!this.keyboard) {
2376
+ return false;
2377
+ }
2378
+ const funcKey = this.isFunctionKeyPressed(event);
2379
+ const { zoomSpeed, moveSpeed, rotateSpeedX, rotateSpeedY } = this.keyboard === true ? {} : this.keyboard;
2380
+ const { controllerState } = this;
2381
+ let newControllerState;
2382
+ const interactionState = {};
2383
+ switch (event.srcEvent.code) {
2384
+ case "Minus":
2385
+ newControllerState = funcKey ? controllerState.zoomOut(zoomSpeed).zoomOut(zoomSpeed) : controllerState.zoomOut(zoomSpeed);
2386
+ interactionState.isZooming = true;
2387
+ break;
2388
+ case "Equal":
2389
+ newControllerState = funcKey ? controllerState.zoomIn(zoomSpeed).zoomIn(zoomSpeed) : controllerState.zoomIn(zoomSpeed);
2390
+ interactionState.isZooming = true;
2391
+ break;
2392
+ case "ArrowLeft":
2393
+ if (funcKey) {
2394
+ newControllerState = controllerState.rotateLeft(rotateSpeedX);
2395
+ interactionState.isRotating = true;
2396
+ } else {
2397
+ newControllerState = controllerState.moveLeft(moveSpeed);
2398
+ interactionState.isPanning = true;
2399
+ }
2400
+ break;
2401
+ case "ArrowRight":
2402
+ if (funcKey) {
2403
+ newControllerState = controllerState.rotateRight(rotateSpeedX);
2404
+ interactionState.isRotating = true;
2405
+ } else {
2406
+ newControllerState = controllerState.moveRight(moveSpeed);
2407
+ interactionState.isPanning = true;
2408
+ }
2409
+ break;
2410
+ case "ArrowUp":
2411
+ if (funcKey) {
2412
+ newControllerState = controllerState.rotateUp(rotateSpeedY);
2413
+ interactionState.isRotating = true;
2414
+ } else {
2415
+ newControllerState = controllerState.moveUp(moveSpeed);
2416
+ interactionState.isPanning = true;
2417
+ }
2418
+ break;
2419
+ case "ArrowDown":
2420
+ if (funcKey) {
2421
+ newControllerState = controllerState.rotateDown(rotateSpeedY);
2422
+ interactionState.isRotating = true;
2423
+ } else {
2424
+ newControllerState = controllerState.moveDown(moveSpeed);
2425
+ interactionState.isPanning = true;
2426
+ }
2427
+ break;
2428
+ default:
2429
+ return false;
2430
+ }
2431
+ this.updateViewport(newControllerState, this._getTransitionProps(), interactionState);
2432
+ return true;
2433
+ }
2434
+ _getTransitionProps(opts) {
2435
+ const { transition } = this;
2436
+ if (!transition || !transition.transitionInterpolator) {
2437
+ return NO_TRANSITION_PROPS;
2438
+ }
2439
+ return opts ? {
2440
+ ...transition,
2441
+ transitionInterpolator: new LinearInterpolator({
2442
+ ...opts,
2443
+ ...transition.transitionInterpolator.opts,
2444
+ makeViewport: this.controllerState.makeViewport
2445
+ })
2446
+ } : transition;
2447
+ }
2448
+ };
2449
+
2450
+ // ../core/src/controllers/view-state.ts
2451
+ var ViewState = class {
2452
+ constructor(props, state, makeViewport) {
2453
+ this.makeViewport = makeViewport;
2454
+ this._viewportProps = this.applyConstraints(props);
2455
+ this._state = state;
2456
+ }
2457
+ getViewportProps() {
2458
+ return this._viewportProps;
2459
+ }
2460
+ getState() {
2461
+ return this._state;
2462
+ }
2463
+ };
2464
+
2465
+ // ../core/src/controllers/map-controller.ts
2466
+ var import_web_mercator5 = require("@math.gl/web-mercator");
2467
+ var PITCH_MOUSE_THRESHOLD = 5;
2468
+ var PITCH_ACCEL = 1.2;
2469
+ var WEB_MERCATOR_TILE_SIZE = 512;
2470
+ var WEB_MERCATOR_MAX_BOUNDS = [
2471
+ [-Infinity, -90],
2472
+ [Infinity, 90]
2473
+ ];
2474
+ function lngLatToWorld2([lng, lat]) {
2475
+ if (Math.abs(lat) > 90) {
2476
+ lat = Math.sign(lat) * 90;
2477
+ }
2478
+ if (Number.isFinite(lng)) {
2479
+ const [x, y2] = (0, import_web_mercator5.lngLatToWorld)([lng, lat]);
2480
+ return [x, (0, import_core9.clamp)(y2, 0, WEB_MERCATOR_TILE_SIZE)];
2481
+ }
2482
+ const [, y] = (0, import_web_mercator5.lngLatToWorld)([0, lat]);
2483
+ return [lng, (0, import_core9.clamp)(y, 0, WEB_MERCATOR_TILE_SIZE)];
2484
+ }
2485
+ var MapState = class extends ViewState {
2486
+ constructor(options) {
2487
+ const {
2488
+ /** Mapbox viewport properties */
2489
+ /** The width of the viewport */
2490
+ width,
2491
+ /** The height of the viewport */
2492
+ height,
2493
+ /** The latitude at the center of the viewport */
2494
+ latitude,
2495
+ /** The longitude at the center of the viewport */
2496
+ longitude,
2497
+ /** The tile zoom level of the map. */
2498
+ zoom,
2499
+ /** The bearing of the viewport in degrees */
2500
+ bearing = 0,
2501
+ /** The pitch of the viewport in degrees */
2502
+ pitch = 0,
2503
+ /**
2504
+ * Specify the altitude of the viewport camera
2505
+ * Unit: map heights, default 1.5
2506
+ * Non-public API, see https://github.com/mapbox/mapbox-gl-js/issues/1137
2507
+ */
2508
+ altitude = 1.5,
2509
+ /** Viewport position */
2510
+ position = [0, 0, 0],
2511
+ /** Viewport constraints */
2512
+ maxZoom = 20,
2513
+ minZoom = 0,
2514
+ maxPitch = 60,
2515
+ minPitch = 0,
2516
+ /** Interaction states, required to calculate change during transform */
2517
+ /* The point on map being grabbed when the operation first started */
2518
+ startPanLngLat,
2519
+ /* Center of the zoom when the operation first started */
2520
+ startZoomLngLat,
2521
+ /* Pointer position when rotation started */
2522
+ startRotatePos,
2523
+ /* The lng/lat point at the rotation pivot (where rotation started) */
2524
+ startRotateLngLat,
2525
+ /** Bearing when current perspective rotate operation started */
2526
+ startBearing,
2527
+ /** Pitch when current perspective rotate operation started */
2528
+ startPitch,
2529
+ /** Zoom when current zoom operation started */
2530
+ startZoom,
2531
+ /** Normalize viewport props to fit map height into viewport */
2532
+ normalize = true
2533
+ } = options;
2534
+ assert(Number.isFinite(longitude));
2535
+ assert(Number.isFinite(latitude));
2536
+ assert(Number.isFinite(zoom));
2537
+ const maxBounds = options.maxBounds || (normalize ? WEB_MERCATOR_MAX_BOUNDS : null);
2538
+ super(
2539
+ {
2540
+ width,
2541
+ height,
2542
+ latitude,
2543
+ longitude,
2544
+ zoom,
2545
+ bearing,
2546
+ pitch,
2547
+ altitude,
2548
+ maxZoom,
2549
+ minZoom,
2550
+ maxPitch,
2551
+ minPitch,
2552
+ normalize,
2553
+ position,
2554
+ maxBounds
2555
+ },
2556
+ {
2557
+ startPanLngLat,
2558
+ startZoomLngLat,
2559
+ startRotatePos,
2560
+ startRotateLngLat,
2561
+ startBearing,
2562
+ startPitch,
2563
+ startZoom
2564
+ },
2565
+ options.makeViewport
2566
+ );
2567
+ this.getAltitude = options.getAltitude;
2568
+ }
2569
+ /**
2570
+ * Start panning
2571
+ * @param {[Number, Number]} pos - position on screen where the pointer grabs
2572
+ */
2573
+ panStart({ pos }) {
2574
+ return this._getUpdatedState({
2575
+ startPanLngLat: this._unproject(pos)
2576
+ });
2577
+ }
2578
+ /**
2579
+ * Pan
2580
+ * @param {[Number, Number]} pos - position on screen where the pointer is
2581
+ * @param {[Number, Number], optional} startPos - where the pointer grabbed at
2582
+ * the start of the operation. Must be supplied of `panStart()` was not called
2583
+ */
2584
+ pan({ pos, startPos }) {
2585
+ const startPanLngLat = this.getState().startPanLngLat || this._unproject(startPos);
2586
+ if (!startPanLngLat) {
2587
+ return this;
2588
+ }
2589
+ const viewport = this.makeViewport(this.getViewportProps());
2590
+ const newProps = viewport.panByPosition(startPanLngLat, pos);
2591
+ return this._getUpdatedState(newProps);
2592
+ }
2593
+ /**
2594
+ * End panning
2595
+ * Must call if `panStart()` was called
2596
+ */
2597
+ panEnd() {
2598
+ return this._getUpdatedState({
2599
+ startPanLngLat: null
2600
+ });
2601
+ }
2602
+ /**
2603
+ * Start rotating
2604
+ * @param {[Number, Number]} pos - position on screen where the center is
2605
+ */
2606
+ rotateStart({ pos }) {
2607
+ var _a;
2608
+ const altitude = (_a = this.getAltitude) == null ? void 0 : _a.call(this, pos);
2609
+ return this._getUpdatedState({
2610
+ startRotatePos: pos,
2611
+ startRotateLngLat: altitude !== void 0 ? this._unproject3D(pos, altitude) : void 0,
2612
+ startBearing: this.getViewportProps().bearing,
2613
+ startPitch: this.getViewportProps().pitch
2614
+ });
2615
+ }
2616
+ /**
2617
+ * Rotate
2618
+ * @param {[Number, Number]} pos - position on screen where the center is
2619
+ */
2620
+ rotate({
2621
+ pos,
2622
+ deltaAngleX = 0,
2623
+ deltaAngleY = 0
2624
+ }) {
2625
+ const { startRotatePos, startRotateLngLat, startBearing, startPitch } = this.getState();
2626
+ if (!startRotatePos || startBearing === void 0 || startPitch === void 0) {
2627
+ return this;
2628
+ }
2629
+ let newRotation;
2630
+ if (pos) {
2631
+ newRotation = this._getNewRotation(pos, startRotatePos, startPitch, startBearing);
2632
+ } else {
2633
+ newRotation = {
2634
+ bearing: startBearing + deltaAngleX,
2635
+ pitch: startPitch + deltaAngleY
2636
+ };
2637
+ }
2638
+ if (startRotateLngLat) {
2639
+ const rotatedViewport = this.makeViewport({
2640
+ ...this.getViewportProps(),
2641
+ ...newRotation
2642
+ });
2643
+ const panMethod = "panByPosition3D" in rotatedViewport ? "panByPosition3D" : "panByPosition";
2644
+ return this._getUpdatedState({
2645
+ ...newRotation,
2646
+ ...rotatedViewport[panMethod](startRotateLngLat, startRotatePos)
2647
+ });
2648
+ }
2649
+ return this._getUpdatedState(newRotation);
2650
+ }
2651
+ /**
2652
+ * End rotating
2653
+ * Must call if `rotateStart()` was called
2654
+ */
2655
+ rotateEnd() {
2656
+ return this._getUpdatedState({
2657
+ startRotatePos: null,
2658
+ startRotateLngLat: null,
2659
+ startBearing: null,
2660
+ startPitch: null
2661
+ });
2662
+ }
2663
+ /**
2664
+ * Start zooming
2665
+ * @param {[Number, Number]} pos - position on screen where the center is
2666
+ */
2667
+ zoomStart({ pos }) {
2668
+ return this._getUpdatedState({
2669
+ startZoomLngLat: this._unproject(pos),
2670
+ startZoom: this.getViewportProps().zoom
2671
+ });
2672
+ }
2673
+ /**
2674
+ * Zoom
2675
+ * @param {[Number, Number]} pos - position on screen where the current center is
2676
+ * @param {[Number, Number]} startPos - the center position at
2677
+ * the start of the operation. Must be supplied of `zoomStart()` was not called
2678
+ * @param {Number} scale - a number between [0, 1] specifying the accumulated
2679
+ * relative scale.
2680
+ */
2681
+ zoom({
2682
+ pos,
2683
+ startPos,
2684
+ scale
2685
+ }) {
2686
+ let { startZoom, startZoomLngLat } = this.getState();
2687
+ if (!startZoomLngLat) {
2688
+ startZoom = this.getViewportProps().zoom;
2689
+ startZoomLngLat = this._unproject(startPos) || this._unproject(pos);
2690
+ }
2691
+ if (!startZoomLngLat) {
2692
+ return this;
2693
+ }
2694
+ const zoom = this._constrainZoom(startZoom + Math.log2(scale));
2695
+ const zoomedViewport = this.makeViewport({ ...this.getViewportProps(), zoom });
2696
+ return this._getUpdatedState({
2697
+ zoom,
2698
+ ...zoomedViewport.panByPosition(startZoomLngLat, pos)
2699
+ });
2700
+ }
2701
+ /**
2702
+ * End zooming
2703
+ * Must call if `zoomStart()` was called
2704
+ */
2705
+ zoomEnd() {
2706
+ return this._getUpdatedState({
2707
+ startZoomLngLat: null,
2708
+ startZoom: null
2709
+ });
2710
+ }
2711
+ zoomIn(speed = 2) {
2712
+ return this._zoomFromCenter(speed);
2713
+ }
2714
+ zoomOut(speed = 2) {
2715
+ return this._zoomFromCenter(1 / speed);
2716
+ }
2717
+ moveLeft(speed = 100) {
2718
+ return this._panFromCenter([speed, 0]);
2719
+ }
2720
+ moveRight(speed = 100) {
2721
+ return this._panFromCenter([-speed, 0]);
2722
+ }
2723
+ moveUp(speed = 100) {
2724
+ return this._panFromCenter([0, speed]);
2725
+ }
2726
+ moveDown(speed = 100) {
2727
+ return this._panFromCenter([0, -speed]);
2728
+ }
2729
+ rotateLeft(speed = 15) {
2730
+ return this._getUpdatedState({
2731
+ bearing: this.getViewportProps().bearing - speed
2732
+ });
2733
+ }
2734
+ rotateRight(speed = 15) {
2735
+ return this._getUpdatedState({
2736
+ bearing: this.getViewportProps().bearing + speed
2737
+ });
2738
+ }
2739
+ rotateUp(speed = 10) {
2740
+ return this._getUpdatedState({
2741
+ pitch: this.getViewportProps().pitch + speed
2742
+ });
2743
+ }
2744
+ rotateDown(speed = 10) {
2745
+ return this._getUpdatedState({
2746
+ pitch: this.getViewportProps().pitch - speed
2747
+ });
2748
+ }
2749
+ shortestPathFrom(viewState) {
2750
+ const fromProps = viewState.getViewportProps();
2751
+ const props = { ...this.getViewportProps() };
2752
+ const { bearing, longitude } = props;
2753
+ if (Math.abs(bearing - fromProps.bearing) > 180) {
2754
+ props.bearing = bearing < 0 ? bearing + 360 : bearing - 360;
2755
+ }
2756
+ if (Math.abs(longitude - fromProps.longitude) > 180) {
2757
+ props.longitude = longitude < 0 ? longitude + 360 : longitude - 360;
2758
+ }
2759
+ return props;
2760
+ }
2761
+ // Apply any constraints (mathematical or defined by _viewportProps) to map state
2762
+ applyConstraints(props) {
2763
+ const { maxPitch, minPitch, pitch, longitude, bearing, normalize, maxBounds } = props;
2764
+ if (normalize) {
2765
+ if (longitude < -180 || longitude > 180) {
2766
+ props.longitude = mod(longitude + 180, 360) - 180;
2767
+ }
2768
+ if (bearing < -180 || bearing > 180) {
2769
+ props.bearing = mod(bearing + 180, 360) - 180;
2770
+ }
2771
+ }
2772
+ props.pitch = (0, import_core9.clamp)(pitch, minPitch, maxPitch);
2773
+ props.zoom = this._constrainZoom(props.zoom, props);
2774
+ if (maxBounds) {
2775
+ const bl = lngLatToWorld2(maxBounds[0]);
2776
+ const tr = lngLatToWorld2(maxBounds[1]);
2777
+ const scale = 2 ** props.zoom;
2778
+ const halfWidth = props.width / 2 / scale;
2779
+ const halfHeight = props.height / 2 / scale;
2780
+ const [minLng, minLat] = (0, import_web_mercator5.worldToLngLat)([bl[0] + halfWidth, bl[1] + halfHeight]);
2781
+ const [maxLng, maxLat] = (0, import_web_mercator5.worldToLngLat)([tr[0] - halfWidth, tr[1] - halfHeight]);
2782
+ props.longitude = (0, import_core9.clamp)(props.longitude, minLng, maxLng);
2783
+ props.latitude = (0, import_core9.clamp)(props.latitude, minLat, maxLat);
2784
+ }
2785
+ return props;
2786
+ }
2787
+ /* Private methods */
2788
+ _constrainZoom(zoom, props) {
2789
+ props ||= this.getViewportProps();
2790
+ const { maxZoom, maxBounds } = props;
2791
+ const shouldApplyMaxBounds = maxBounds !== null && props.width > 0 && props.height > 0;
2792
+ let { minZoom } = props;
2793
+ if (shouldApplyMaxBounds) {
2794
+ const bl = lngLatToWorld2(maxBounds[0]);
2795
+ const tr = lngLatToWorld2(maxBounds[1]);
2796
+ const w = tr[0] - bl[0];
2797
+ const h = tr[1] - bl[1];
2798
+ if (Number.isFinite(w) && w > 0) {
2799
+ minZoom = Math.max(minZoom, Math.log2(props.width / w));
2800
+ }
2801
+ if (Number.isFinite(h) && h > 0) {
2802
+ minZoom = Math.max(minZoom, Math.log2(props.height / h));
2803
+ }
2804
+ if (minZoom > maxZoom)
2805
+ minZoom = maxZoom;
2806
+ }
2807
+ return (0, import_core9.clamp)(zoom, minZoom, maxZoom);
2808
+ }
2809
+ _zoomFromCenter(scale) {
2810
+ const { width, height } = this.getViewportProps();
2811
+ return this.zoom({
2812
+ pos: [width / 2, height / 2],
2813
+ scale
2814
+ });
2815
+ }
2816
+ _panFromCenter(offset) {
2817
+ const { width, height } = this.getViewportProps();
2818
+ return this.pan({
2819
+ startPos: [width / 2, height / 2],
2820
+ pos: [width / 2 + offset[0], height / 2 + offset[1]]
2821
+ });
2822
+ }
2823
+ _getUpdatedState(newProps) {
2824
+ return new this.constructor({
2825
+ makeViewport: this.makeViewport,
2826
+ ...this.getViewportProps(),
2827
+ ...this.getState(),
2828
+ ...newProps
2829
+ });
2830
+ }
2831
+ _unproject(pos) {
2832
+ const viewport = this.makeViewport(this.getViewportProps());
2833
+ return pos && viewport.unproject(pos);
2834
+ }
2835
+ _unproject3D(pos, altitude) {
2836
+ const viewport = this.makeViewport(this.getViewportProps());
2837
+ return viewport.unproject(pos, { targetZ: altitude });
2838
+ }
2839
+ _getNewRotation(pos, startPos, startPitch, startBearing) {
2840
+ const deltaX = pos[0] - startPos[0];
2841
+ const deltaY = pos[1] - startPos[1];
2842
+ const centerY = pos[1];
2843
+ const startY = startPos[1];
2844
+ const { width, height } = this.getViewportProps();
2845
+ const deltaScaleX = deltaX / width;
2846
+ let deltaScaleY = 0;
2847
+ if (deltaY > 0) {
2848
+ if (Math.abs(height - startY) > PITCH_MOUSE_THRESHOLD) {
2849
+ deltaScaleY = deltaY / (startY - height) * PITCH_ACCEL;
2850
+ }
2851
+ } else if (deltaY < 0) {
2852
+ if (startY > PITCH_MOUSE_THRESHOLD) {
2853
+ deltaScaleY = 1 - centerY / startY;
2854
+ }
2855
+ }
2856
+ deltaScaleY = (0, import_core9.clamp)(deltaScaleY, -1, 1);
2857
+ const { minPitch, maxPitch } = this.getViewportProps();
2858
+ const bearing = startBearing + 180 * deltaScaleX;
2859
+ let pitch = startPitch;
2860
+ if (deltaScaleY > 0) {
2861
+ pitch = startPitch + deltaScaleY * (maxPitch - startPitch);
2862
+ } else if (deltaScaleY < 0) {
2863
+ pitch = startPitch - deltaScaleY * (minPitch - startPitch);
2864
+ }
2865
+ return {
2866
+ pitch,
2867
+ bearing
2868
+ };
2869
+ }
2870
+ };
2871
+ var MapController = class extends Controller {
2872
+ constructor() {
2873
+ super(...arguments);
2874
+ this.ControllerState = MapState;
2875
+ this.transition = {
2876
+ transitionDuration: 300,
2877
+ transitionInterpolator: new LinearInterpolator({
2878
+ transitionProps: {
2879
+ compare: ["longitude", "latitude", "zoom", "bearing", "pitch", "position"],
2880
+ required: ["longitude", "latitude", "zoom"]
2881
+ }
2882
+ })
2883
+ };
2884
+ this.dragMode = "pan";
2885
+ /**
2886
+ * Rotation pivot behavior:
2887
+ * - 'center': Rotate around viewport center (default)
2888
+ * - '2d': Rotate around pointer position at ground level (z=0)
2889
+ * - '3d': Rotate around 3D picked point (requires pickPosition callback)
2890
+ */
2891
+ this.rotationPivot = "center";
2892
+ /** Add altitude to rotateStart params based on rotationPivot mode */
2893
+ this._getAltitude = (pos) => {
2894
+ if (this.rotationPivot === "2d") {
2895
+ return 0;
2896
+ } else if (this.rotationPivot === "3d") {
2897
+ if (this.pickPosition) {
2898
+ const { x, y } = this.props;
2899
+ const pickResult = this.pickPosition(x + pos[0], y + pos[1]);
2900
+ if (pickResult && pickResult.coordinate && pickResult.coordinate.length >= 3) {
2901
+ return pickResult.coordinate[2];
2902
+ }
2903
+ }
2904
+ }
2905
+ return void 0;
2906
+ };
2907
+ }
2908
+ setProps(props) {
2909
+ if ("rotationPivot" in props) {
2910
+ this.rotationPivot = props.rotationPivot || "center";
2911
+ }
2912
+ props.getAltitude = this._getAltitude;
2913
+ props.position = props.position || [0, 0, 0];
2914
+ props.maxBounds = props.maxBounds || (props.normalize === false ? null : WEB_MERCATOR_MAX_BOUNDS);
2915
+ super.setProps(props);
2916
+ }
2917
+ updateViewport(newControllerState, extraProps = null, interactionState = {}) {
2918
+ const state = newControllerState.getState();
2919
+ if (interactionState.isDragging && state.startRotateLngLat) {
2920
+ interactionState = {
2921
+ ...interactionState,
2922
+ rotationPivotPosition: state.startRotateLngLat
2923
+ };
2924
+ } else if (interactionState.isDragging === false) {
2925
+ interactionState = { ...interactionState, rotationPivotPosition: void 0 };
2926
+ }
2927
+ super.updateViewport(newControllerState, extraProps, interactionState);
2928
+ }
2929
+ };
2930
+
2931
+ // ../core/src/views/map-view.ts
2932
+ var MapView = class extends View {
2933
+ constructor(props = {}) {
2934
+ super(props);
2935
+ }
2936
+ getViewportType() {
2937
+ return WebMercatorViewport;
2938
+ }
2939
+ get ControllerType() {
2940
+ return MapController;
2941
+ }
2942
+ };
2943
+ MapView.displayName = "MapView";
2944
+
321
2945
  // dist/deck-renderer.js
322
- function arcgisFOVToDeckAltitude(fov, aspectRatio) {
323
- const D = Math.sqrt(1 + aspectRatio ** 2);
324
- const halfFOV = fov / 2 / 180 * Math.PI;
325
- return D / 2 / Math.tan(halfFOV);
2946
+ var ARCGIS_WEB_MERCATOR_SCALE_AT_ZOOM_0 = 5916575505e-1;
2947
+ var DECK_GROUND_MPP_AT_ZOOM_0 = 78271.484;
2948
+ var METERS_PER_DEG_LAT = 111320;
2949
+ var ARCGIS_DIAGONAL_FOV_RADIANS = 55 * Math.PI / 180;
2950
+ var ALTITUDE_BLEND_START_TILT = 65;
2951
+ var ALTITUDE_BLEND_END_TILT = 80;
2952
+ function getDistanceMeters(a, b) {
2953
+ const midLatRad = (a.latitude + b.latitude) / 2 * Math.PI / 180;
2954
+ const dLatM = (a.latitude - b.latitude) * METERS_PER_DEG_LAT;
2955
+ const dLngM = (a.longitude - b.longitude) * METERS_PER_DEG_LAT * Math.cos(midLatRad);
2956
+ return Math.sqrt(dLatM * dLatM + dLngM * dLngM);
326
2957
  }
327
- function createDeckRenderer(DeckProps2, externalRenderers2) {
2958
+ function getZoom(view, longitude, latitude, width, height) {
2959
+ const focalPoint = view.toMap({ x: width / 2, y: height / 2 });
2960
+ const focalPointRight = view.toMap({ x: width / 2 + 1, y: height / 2 });
2961
+ if (focalPoint && focalPointRight) {
2962
+ const horizontalMetersPerPixel = getDistanceMeters(focalPoint, focalPointRight);
2963
+ if (horizontalMetersPerPixel > 0) {
2964
+ const latitudeRad = latitude * Math.PI / 180;
2965
+ return Math.log2(DECK_GROUND_MPP_AT_ZOOM_0 * Math.cos(latitudeRad) / horizontalMetersPerPixel);
2966
+ }
2967
+ }
2968
+ return Math.log2(ARCGIS_WEB_MERCATOR_SCALE_AT_ZOOM_0 / view.scale) - 1;
2969
+ }
2970
+ function smoothstep(edge0, edge1, value) {
2971
+ const t = Math.max(0, Math.min(1, (value - edge0) / (edge1 - edge0)));
2972
+ return t * t * (3 - 2 * t);
2973
+ }
2974
+ function getFovMatchedAltitude(width, height) {
2975
+ const aspect = width / height;
2976
+ const verticalTan = Math.tan(ARCGIS_DIAGONAL_FOV_RADIANS / 2) / Math.sqrt(1 + aspect * aspect);
2977
+ return 0.5 / verticalTan;
2978
+ }
2979
+ function getAltitude(tilt, slantAltitude, width, height) {
2980
+ const fovAltitude = getFovMatchedAltitude(width, height);
2981
+ const blend = smoothstep(ALTITUDE_BLEND_START_TILT, ALTITUDE_BLEND_END_TILT, tilt);
2982
+ return slantAltitude * (1 - blend) + fovAltitude * blend;
2983
+ }
2984
+ function getArcGISMatrixViewState(view, longitude, latitude, zoom, resolution, altitude) {
2985
+ return {
2986
+ views: new MapView({ id: "arcgis-scene" }),
2987
+ viewState: {
2988
+ "arcgis-scene": {
2989
+ id: "arcgis-scene",
2990
+ longitude,
2991
+ latitude,
2992
+ zoom,
2993
+ pitch: view.camera.tilt,
2994
+ bearing: view.camera.heading,
2995
+ altitude,
2996
+ position: [0, 0, 0],
2997
+ resolution
2998
+ }
2999
+ }
3000
+ };
3001
+ }
3002
+ function createDeckRenderer(DeckProps2, RenderNode2) {
328
3003
  class DeckRenderer2 {
329
- constructor(view, props) {
3004
+ constructor(viewOrProps, props) {
330
3005
  this.resources = null;
331
3006
  this.cancelInitialization = null;
332
- this.view = view;
333
- this.deck = new DeckProps2(props);
334
- }
335
- async setup(context) {
336
- const gl = context.gl;
337
- let cancelled = false;
338
- this.cancelInitialization = () => cancelled = true;
339
- const resources = await initializeResources.call(this, gl);
340
- if (cancelled) {
341
- finalizeResources(resources);
342
- return;
3007
+ this.renderNode = null;
3008
+ if (viewOrProps && typeof viewOrProps === "object" && "view" in viewOrProps) {
3009
+ const { view, ...deckProps } = viewOrProps;
3010
+ this.view = view;
3011
+ this.deck = new DeckProps2(deckProps);
3012
+ } else {
3013
+ this.view = viewOrProps;
3014
+ this.deck = new DeckProps2(props);
343
3015
  }
344
- this.deck.on("change", (props) => resources.deck.setProps(props));
345
- resources.deck.setProps(this.deck.toJSON());
346
- this.resources = resources;
3016
+ let isInitializing = false;
3017
+ const self = this;
3018
+ const DeckRenderNode = RenderNode2.createSubclass({
3019
+ consumes: { required: ["composite-color"] },
3020
+ produces: "composite-color",
3021
+ initialize() {
3022
+ },
3023
+ render(inputs) {
3024
+ const renderNode = this;
3025
+ const passthrough = inputs.find((i) => i.name === "composite-color");
3026
+ if (!self.resources && !isInitializing) {
3027
+ const gl2 = renderNode.gl;
3028
+ if (gl2) {
3029
+ isInitializing = true;
3030
+ let cancelled = false;
3031
+ self.cancelInitialization = () => {
3032
+ cancelled = true;
3033
+ };
3034
+ initializeResources.call(self, gl2).then((resources) => {
3035
+ isInitializing = false;
3036
+ if (cancelled) {
3037
+ finalizeResources(resources);
3038
+ return;
3039
+ }
3040
+ self.deck.on("change", (deckProps) => resources.deck.setProps(deckProps));
3041
+ resources.deck.setProps(self.deck.toJSON());
3042
+ self.resources = resources;
3043
+ renderNode.requestRender();
3044
+ }).catch((err) => {
3045
+ isInitializing = false;
3046
+ console.error("DeckRenderer: failed to initialize resources", err);
3047
+ });
3048
+ }
3049
+ return passthrough;
3050
+ }
3051
+ if (!self.resources) {
3052
+ return passthrough;
3053
+ }
3054
+ const output = renderNode.bindRenderTarget();
3055
+ const gl = renderNode.gl;
3056
+ const dpr = window.devicePixelRatio || 1;
3057
+ const width = gl.drawingBufferWidth / dpr;
3058
+ const height = gl.drawingBufferHeight / dpr;
3059
+ const cameraPos = self.view.camera.position;
3060
+ const focalPoint = self.view.toMap({ x: width / 2, y: height / 2 });
3061
+ const latitude = focalPoint ? focalPoint.latitude : self.view.center.latitude;
3062
+ const longitude = focalPoint ? focalPoint.longitude : self.view.center.longitude;
3063
+ const midLatRad = (latitude + cameraPos.latitude) / 2 * Math.PI / 180;
3064
+ const dLatM = (cameraPos.latitude - latitude) * METERS_PER_DEG_LAT;
3065
+ const dLngM = (cameraPos.longitude - longitude) * METERS_PER_DEG_LAT * Math.cos(midLatRad);
3066
+ const horizM = Math.sqrt(dLatM * dLatM + dLngM * dLngM);
3067
+ const slantM = Math.sqrt(horizM * horizM + cameraPos.z * cameraPos.z);
3068
+ const zoom = getZoom(self.view, longitude, latitude, width, height);
3069
+ const viewportHeightM = height * self.view.resolution;
3070
+ const slantAltitude = slantM / viewportHeightM;
3071
+ const altitude = getAltitude(self.view.camera.tilt, slantAltitude, width, height);
3072
+ const arcgisMatrixView = getArcGISMatrixViewState(self.view, longitude, latitude, zoom, self.view.resolution, altitude);
3073
+ try {
3074
+ if (arcgisMatrixView) {
3075
+ render(self.resources, {
3076
+ width,
3077
+ height,
3078
+ latitude,
3079
+ longitude,
3080
+ altitude,
3081
+ zoom,
3082
+ bearing: self.view.camera.heading,
3083
+ pitch: self.view.camera.tilt,
3084
+ ...arcgisMatrixView
3085
+ });
3086
+ } else {
3087
+ render(self.resources, {
3088
+ width,
3089
+ height,
3090
+ latitude,
3091
+ longitude,
3092
+ altitude,
3093
+ zoom,
3094
+ bearing: self.view.camera.heading,
3095
+ pitch: self.view.camera.tilt
3096
+ });
3097
+ }
3098
+ } catch (e) {
3099
+ console.error("DeckRenderer: render error", e);
3100
+ }
3101
+ return output;
3102
+ }
3103
+ });
3104
+ this.renderNode = new DeckRenderNode({ view: this.view });
3105
+ }
3106
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3107
+ async setup(_context) {
347
3108
  }
348
3109
  dispose() {
349
3110
  var _a;
350
3111
  (_a = this.cancelInitialization) == null ? void 0 : _a.call(this);
351
3112
  if (this.resources) {
352
3113
  finalizeResources(this.resources);
3114
+ this.resources = null;
353
3115
  }
3116
+ this.renderNode = null;
354
3117
  }
355
3118
  redraw() {
356
- externalRenderers2.requestRender(this.view);
3119
+ var _a;
3120
+ (_a = this.renderNode) == null ? void 0 : _a.requestRender();
357
3121
  }
358
3122
  render() {
359
- const [width, height] = this.view.size;
360
- render(this.resources, {
361
- width,
362
- height,
363
- latitude: this.view.center.latitude,
364
- longitude: this.view.center.longitude,
365
- altitude: arcgisFOVToDeckAltitude(this.view.camera.fov, width / height),
366
- zoom: this.view.zoom,
367
- bearing: this.view.camera.heading,
368
- pitch: this.view.camera.tilt
369
- });
3123
+ var _a;
3124
+ (_a = this.renderNode) == null ? void 0 : _a.requestRender();
370
3125
  }
371
3126
  }
372
3127
  return DeckRenderer2;
@@ -376,7 +3131,7 @@ function createDeckRenderer(DeckProps2, externalRenderers2) {
376
3131
  var import_Accessor = __toESM(require("@arcgis/core/core/Accessor"), 1);
377
3132
  var import_Layer = __toESM(require("@arcgis/core/layers/Layer"), 1);
378
3133
  var import_BaseLayerViewGL2D = __toESM(require("@arcgis/core/views/2d/layers/BaseLayerViewGL2D"), 1);
379
- var externalRenderers = __toESM(require("@arcgis/core/views/3d/externalRenderers"), 1);
3134
+ var import_RenderNode = __toESM(require("@arcgis/core/views/3d/webgl/RenderNode"), 1);
380
3135
 
381
3136
  // dist/load-modules.js
382
3137
  var import_esri_loader = require("esri-loader");
@@ -399,22 +3154,22 @@ async function loadArcGISModule(esri, loadScriptOptions) {
399
3154
  const Layer3 = esri.layers.Layer;
400
3155
  const Accessor3 = esri.core.Accessor;
401
3156
  const BaseLayerViewGL2D3 = esri.views["2d"].layers.BaseLayerViewGL2D;
402
- const externalRenderers3 = esri.views["3d"].externalRenderers;
403
- return initialize(Layer3, Accessor3, BaseLayerViewGL2D3, externalRenderers3);
3157
+ const RenderNode3 = esri.views["3d"].webgl.RenderNode;
3158
+ return initialize(Layer3, Accessor3, BaseLayerViewGL2D3, RenderNode3);
404
3159
  }
405
- const [Layer2, Accessor2, BaseLayerViewGL2D2, externalRenderers2] = await (0, import_esri_loader.loadModules)([
3160
+ const [Layer2, Accessor2, BaseLayerViewGL2D2, RenderNode2] = await (0, import_esri_loader.loadModules)([
406
3161
  "esri/layers/Layer",
407
3162
  "esri/core/Accessor",
408
3163
  "esri/views/2d/layers/BaseLayerViewGL2D",
409
- "esri/views/3d/externalRenderers"
3164
+ "esri/views/3d/webgl/RenderNode"
410
3165
  ], loadScriptOptions);
411
- return initialize(Layer2, Accessor2, BaseLayerViewGL2D2, externalRenderers2);
3166
+ return initialize(Layer2, Accessor2, BaseLayerViewGL2D2, RenderNode2);
412
3167
  }
413
- function initialize(Layer2, Accessor2, BaseLayerViewGL2D2, externalRenderers2) {
3168
+ function initialize(Layer2, Accessor2, BaseLayerViewGL2D2, RenderNode2) {
414
3169
  const DeckProps2 = createDeckProps(Accessor2);
415
3170
  const DeckLayerView2D2 = createDeckLayerView2D(BaseLayerViewGL2D2);
416
3171
  const DeckLayer2 = createDeckLayer(DeckProps2, Layer2, DeckLayerView2D2);
417
- const DeckRenderer2 = createDeckRenderer(DeckProps2, externalRenderers2);
3172
+ const DeckRenderer2 = createDeckRenderer(DeckProps2, RenderNode2);
418
3173
  arcGIS = { DeckLayer: DeckLayer2, DeckRenderer: DeckRenderer2 };
419
3174
  return arcGIS;
420
3175
  }
@@ -423,5 +3178,5 @@ function initialize(Layer2, Accessor2, BaseLayerViewGL2D2, externalRenderers2) {
423
3178
  var DeckProps = createDeckProps(import_Accessor.default);
424
3179
  var DeckLayerView2D = createDeckLayerView2D(import_BaseLayerViewGL2D.default);
425
3180
  var DeckLayer = createDeckLayer(DeckProps, import_Layer.default, DeckLayerView2D);
426
- var DeckRenderer = createDeckRenderer(DeckProps, externalRenderers);
3181
+ var DeckRenderer = createDeckRenderer(DeckProps, import_RenderNode.default);
427
3182
  //# sourceMappingURL=index.cjs.map