@deck.gl/arcgis 9.4.0-beta.4 → 9.4.1

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