@deck.gl/arcgis 9.3.7 → 9.4.0-alpha.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/dist.dev.js CHANGED
@@ -12143,6 +12143,179 @@ void main(void) {
12143
12143
  }
12144
12144
  };
12145
12145
 
12146
+ // ../../node_modules/mjolnir.js/dist/hammerjs/recognizers/double-click-drag.js
12147
+ var EVENT_NAMES = ["", "start", "move", "end", "cancel"];
12148
+ var DoubleClickDragRecognizer = class extends Recognizer {
12149
+ constructor(options = {}) {
12150
+ super({
12151
+ enable: true,
12152
+ event: "doubleclickdrag",
12153
+ pointers: 1,
12154
+ interval: 500,
12155
+ time: 350,
12156
+ threshold: 28,
12157
+ dragThreshold: 1,
12158
+ pixelsPerScale: 120,
12159
+ ...options
12160
+ });
12161
+ this._tapStart = null;
12162
+ this._lastTap = null;
12163
+ this._drag = null;
12164
+ this._emittedStart = false;
12165
+ }
12166
+ getTouchAction() {
12167
+ return [TOUCH_ACTION_MANIPULATION];
12168
+ }
12169
+ getEventNames() {
12170
+ return EVENT_NAMES.map((suffix) => this.options.event + suffix);
12171
+ }
12172
+ process(input) {
12173
+ const { options } = this;
12174
+ const validPointers = input.pointers.length === options.pointers;
12175
+ if (!validPointers) {
12176
+ this.reset();
12177
+ return RecognizerState.Failed;
12178
+ }
12179
+ if (input.eventType & InputEvent.Start) {
12180
+ return this._handleStart(input);
12181
+ }
12182
+ if (input.eventType & InputEvent.Move) {
12183
+ return this._handleMove(input);
12184
+ }
12185
+ if (input.eventType & InputEvent.Cancel) {
12186
+ return this._handleEnd(input, true);
12187
+ }
12188
+ if (input.eventType & InputEvent.End) {
12189
+ return this._handleEnd(input, false);
12190
+ }
12191
+ return RecognizerState.Failed;
12192
+ }
12193
+ reset() {
12194
+ this._tapStart = null;
12195
+ this._lastTap = null;
12196
+ this._drag = null;
12197
+ this._emittedStart = false;
12198
+ }
12199
+ emit(input) {
12200
+ if (!input) {
12201
+ return;
12202
+ }
12203
+ if (this.state === RecognizerState.Began) {
12204
+ if (!this._drag?.active || this._emittedStart) {
12205
+ return;
12206
+ }
12207
+ this._emittedStart = true;
12208
+ this.manager.emit(`${this.options.event}start`, input);
12209
+ this.manager.emit(this.options.event, input);
12210
+ return;
12211
+ }
12212
+ if (this.state === RecognizerState.Changed) {
12213
+ if (!this._emittedStart) {
12214
+ return;
12215
+ }
12216
+ this.manager.emit(`${this.options.event}move`, input);
12217
+ this.manager.emit(this.options.event, input);
12218
+ return;
12219
+ }
12220
+ if (this.state === RecognizerState.Ended) {
12221
+ if (!this._emittedStart) {
12222
+ return;
12223
+ }
12224
+ this.manager.emit(this.options.event, input);
12225
+ this.manager.emit(`${this.options.event}end`, input);
12226
+ this._emittedStart = false;
12227
+ return;
12228
+ }
12229
+ if (this.state === RecognizerState.Cancelled) {
12230
+ if (!this._emittedStart) {
12231
+ return;
12232
+ }
12233
+ this.manager.emit(this.options.event, input);
12234
+ this.manager.emit(`${this.options.event}cancel`, input);
12235
+ this._emittedStart = false;
12236
+ }
12237
+ }
12238
+ _handleStart(input) {
12239
+ const pointerId = this._getPointerId(input);
12240
+ if (this._lastTap && this._isTapMatch(input, this._lastTap)) {
12241
+ this._tapStart = null;
12242
+ this._lastTap = null;
12243
+ this._drag = {
12244
+ startCenter: input.center,
12245
+ pointerId,
12246
+ active: false
12247
+ };
12248
+ this._emittedStart = false;
12249
+ return RecognizerState.Began;
12250
+ }
12251
+ this._tapStart = {
12252
+ center: input.center,
12253
+ timeStamp: input.timeStamp,
12254
+ pointerId
12255
+ };
12256
+ this._lastTap = null;
12257
+ this._drag = null;
12258
+ this._emittedStart = false;
12259
+ return RecognizerState.Failed;
12260
+ }
12261
+ _handleMove(input) {
12262
+ if (!this._drag || !this._isSamePointer(input, this._drag.pointerId)) {
12263
+ return RecognizerState.Failed;
12264
+ }
12265
+ const dy = this._drag.startCenter.y - input.center.y;
12266
+ if (!this._drag.active && Math.abs(dy) < this.options.dragThreshold) {
12267
+ return RecognizerState.Began;
12268
+ }
12269
+ this._drag.active = true;
12270
+ input.scale = Math.pow(2, dy / this.options.pixelsPerScale);
12271
+ return this._emittedStart ? RecognizerState.Changed : RecognizerState.Began;
12272
+ }
12273
+ _handleEnd(input, cancelled) {
12274
+ if (this._drag && this._isSamePointer(input, this._drag.pointerId)) {
12275
+ const { active, startCenter } = this._drag;
12276
+ this._drag = null;
12277
+ this._tapStart = null;
12278
+ this._lastTap = null;
12279
+ if (!active) {
12280
+ this._emittedStart = false;
12281
+ return RecognizerState.Failed;
12282
+ }
12283
+ const dy = startCenter.y - input.center.y;
12284
+ input.scale = Math.pow(2, dy / this.options.pixelsPerScale);
12285
+ return cancelled ? RecognizerState.Cancelled : RecognizerState.Ended;
12286
+ }
12287
+ if (!this._tapStart || !this._isSamePointer(input, this._tapStart.pointerId)) {
12288
+ if (cancelled) {
12289
+ this.reset();
12290
+ }
12291
+ return RecognizerState.Failed;
12292
+ }
12293
+ if (this._isValidTap(input)) {
12294
+ this._lastTap = {
12295
+ center: input.center,
12296
+ timeStamp: input.timeStamp,
12297
+ pointerId: this._tapStart.pointerId
12298
+ };
12299
+ } else {
12300
+ this._lastTap = null;
12301
+ }
12302
+ this._tapStart = null;
12303
+ return RecognizerState.Failed;
12304
+ }
12305
+ _isTapMatch(input, tap) {
12306
+ return input.timeStamp - tap.timeStamp <= this.options.interval && getPointDistance(input.center, tap.center) <= this.options.threshold;
12307
+ }
12308
+ _isValidTap(input) {
12309
+ return input.deltaTime <= this.options.time && input.distance <= this.options.threshold;
12310
+ }
12311
+ _getPointerId(input) {
12312
+ return "pointerId" in input.srcEvent ? input.srcEvent.pointerId : null;
12313
+ }
12314
+ _isSamePointer(input, pointerId) {
12315
+ return pointerId === null || this._getPointerId(input) === pointerId;
12316
+ }
12317
+ };
12318
+
12146
12319
  // ../../node_modules/mjolnir.js/dist/hammerjs/recognizers/tap.js
12147
12320
  var TapRecognizer = class extends Recognizer {
12148
12321
  constructor(options = {}) {
@@ -12221,7 +12394,7 @@ void main(void) {
12221
12394
  };
12222
12395
 
12223
12396
  // ../../node_modules/mjolnir.js/dist/hammerjs/recognizers/pan.js
12224
- var EVENT_NAMES = ["", "start", "move", "end", "cancel", "up", "down", "left", "right"];
12397
+ var EVENT_NAMES2 = ["", "start", "move", "end", "cancel", "up", "down", "left", "right"];
12225
12398
  var PanRecognizer = class extends AttrRecognizer {
12226
12399
  constructor(options = {}) {
12227
12400
  super({
@@ -12247,7 +12420,7 @@ void main(void) {
12247
12420
  return actions;
12248
12421
  }
12249
12422
  getEventNames() {
12250
- return EVENT_NAMES.map((suffix) => this.options.event + suffix);
12423
+ return EVENT_NAMES2.map((suffix) => this.options.event + suffix);
12251
12424
  }
12252
12425
  directionTest(input) {
12253
12426
  const { options } = this;
@@ -12285,7 +12458,7 @@ void main(void) {
12285
12458
  };
12286
12459
 
12287
12460
  // ../../node_modules/mjolnir.js/dist/hammerjs/recognizers/pinch.js
12288
- var EVENT_NAMES2 = ["", "start", "move", "end", "cancel", "in", "out"];
12461
+ var EVENT_NAMES3 = ["", "start", "move", "end", "cancel", "in", "out"];
12289
12462
  var PinchRecognizer = class extends AttrRecognizer {
12290
12463
  constructor(options = {}) {
12291
12464
  super({
@@ -12300,7 +12473,7 @@ void main(void) {
12300
12473
  return [TOUCH_ACTION_NONE];
12301
12474
  }
12302
12475
  getEventNames() {
12303
- return EVENT_NAMES2.map((suffix) => this.options.event + suffix);
12476
+ return EVENT_NAMES3.map((suffix) => this.options.event + suffix);
12304
12477
  }
12305
12478
  attrTest(input) {
12306
12479
  return super.attrTest(input) && (Math.abs(input.scale - 1) > this.options.threshold || Boolean(this.state & RecognizerState.Began));
@@ -12377,8 +12550,9 @@ void main(void) {
12377
12550
  multipan: [PanRecognizer, { threshold: 10, direction: InputDirection.Vertical, pointers: 2 }],
12378
12551
  pinch: [PinchRecognizer, {}, null, ["multipan"]],
12379
12552
  pan: [PanRecognizer, { threshold: 1 }, ["pinch"], ["multipan"]],
12380
- dblclick: [TapRecognizer, { event: "dblclick", taps: 2 }],
12381
- click: [TapRecognizer, { event: "click" }, null, ["dblclick"]]
12553
+ dblclick: [TapRecognizer, { event: "dblclick", taps: 2, enable: false }],
12554
+ dblclickdrag: [DoubleClickDragRecognizer, { event: "dblclickdrag", enable: false }, ["dblclick"], null],
12555
+ click: [TapRecognizer, { event: "click" }, ["dblclickdrag"], ["dblclick", "dblclickdrag"]]
12382
12556
  };
12383
12557
 
12384
12558
  // ../core/src/viewports/viewport.ts
@@ -13176,6 +13350,8 @@ void main(void) {
13176
13350
  constructor(opts = {}) {
13177
13351
  const {
13178
13352
  longitude = 0,
13353
+ bearing = 0,
13354
+ pitch = 0,
13179
13355
  zoom = 0,
13180
13356
  // Matches Maplibre defaults
13181
13357
  // https://github.com/maplibre/maplibre-gl-js/blob/f8ab4b48d59ab8fe7b068b102538793bbdd4c848/src/geo/projection/globe_transform.ts#L632-L633
@@ -13184,20 +13360,19 @@ void main(void) {
13184
13360
  resolution = 10
13185
13361
  } = opts;
13186
13362
  let { latitude = 0, height, altitude = 1.5, fovy } = opts;
13187
- latitude = Math.max(Math.min(latitude, MAX_LATITUDE), -MAX_LATITUDE);
13363
+ latitude = Math.max(Math.min(latitude, 90), -90);
13188
13364
  height = height || 1;
13189
13365
  if (fovy) {
13190
13366
  altitude = fovyToAltitude(fovy);
13191
13367
  } else {
13192
13368
  fovy = altitudeToFovy(altitude);
13193
13369
  }
13194
- const scale5 = Math.pow(2, zoom - zoomAdjust(latitude));
13370
+ const scaleLatitude = Math.max(Math.min(latitude, MAX_LATITUDE), -MAX_LATITUDE);
13371
+ const scale5 = Math.pow(2, zoom - zoomAdjust(scaleLatitude));
13372
+ const pitchRadians = pitch * DEGREES_TO_RADIANS5;
13195
13373
  const nearZ = opts.nearZ ?? nearZMultiplier;
13196
- const farZ = opts.farZ ?? (altitude + GLOBE_RADIUS * 2 * scale5 / height) * farZMultiplier;
13197
- const viewMatrix = new Matrix4().lookAt({ eye: [0, -altitude, 0], up: [0, 0, 1] });
13198
- viewMatrix.rotateX(latitude * DEGREES_TO_RADIANS5);
13199
- viewMatrix.rotateZ(-longitude * DEGREES_TO_RADIANS5);
13200
- viewMatrix.scale(scale5 / height);
13374
+ const farZ = opts.farZ ?? (altitude + GLOBE_RADIUS * 2 * scale5 / height / Math.max(Math.cos(pitchRadians), 0.1)) * farZMultiplier;
13375
+ const viewMatrix = new Matrix4().lookAt({ eye: [0, -altitude, 0], up: [0, 0, 1] }).rotateX(-pitchRadians).rotateY(-bearing * DEGREES_TO_RADIANS5).rotateX(latitude * DEGREES_TO_RADIANS5).rotateZ(-longitude * DEGREES_TO_RADIANS5).scale(scale5 / height);
13201
13376
  super({
13202
13377
  ...opts,
13203
13378
  // x, y, width,
@@ -13217,6 +13392,8 @@ void main(void) {
13217
13392
  this.scale = scale5;
13218
13393
  this.latitude = latitude;
13219
13394
  this.longitude = longitude;
13395
+ this.bearing = bearing;
13396
+ this.pitch = pitch;
13220
13397
  this.fovy = fovy;
13221
13398
  this.resolution = resolution;
13222
13399
  }
@@ -13306,14 +13483,17 @@ void main(void) {
13306
13483
  const rotationSpeed = 0.25 / scale5;
13307
13484
  const longitude = startLng + rotationSpeed * (startPixel[0] - pixel[0]);
13308
13485
  let latitude = startLat - rotationSpeed * (startPixel[1] - pixel[1]);
13309
- latitude = Math.max(Math.min(latitude, MAX_LATITUDE), -MAX_LATITUDE);
13486
+ latitude = Math.max(Math.min(latitude, 90), -90);
13310
13487
  const out = { longitude, latitude, zoom: startZoom - zoomAdjust(startLat) };
13311
13488
  out.zoom += zoomAdjust(out.latitude);
13312
13489
  return out;
13313
13490
  }
13314
13491
  };
13315
13492
  GlobeViewport.displayName = "GlobeViewport";
13316
- function zoomAdjust(latitude) {
13493
+ function zoomAdjust(latitude, clampToPoles) {
13494
+ if (clampToPoles) {
13495
+ latitude = Math.max(Math.min(latitude, MAX_LATITUDE), -MAX_LATITUDE);
13496
+ }
13317
13497
  const scaleAdjust = Math.PI * Math.cos(latitude * Math.PI / 180);
13318
13498
  return Math.log2(scaleAdjust);
13319
13499
  }
@@ -13400,6 +13580,7 @@ void main(void) {
13400
13580
  PINCH: ["pinchstart", "pinchmove", "pinchend"],
13401
13581
  MULTI_PAN: ["multipanstart", "multipanmove", "multipanend"],
13402
13582
  DOUBLE_CLICK: ["dblclick"],
13583
+ DOUBLE_CLICK_DRAG: ["dblclickdragstart", "dblclickdragmove", "dblclickdragend", "dblclickdragcancel"],
13403
13584
  KEYBOARD: ["keydown"]
13404
13585
  };
13405
13586
  var pinchEventWorkaround = {};
@@ -13413,6 +13594,8 @@ void main(void) {
13413
13594
  this._customEvents = [];
13414
13595
  this._eventStartBlocked = null;
13415
13596
  this._panMove = false;
13597
+ this._doubleClickDragAnchor = null;
13598
+ this._suppressDoubleClickUntil = 0;
13416
13599
  this.invertPan = false;
13417
13600
  this.dragMode = "rotate";
13418
13601
  this.inertia = 0;
@@ -13420,6 +13603,7 @@ void main(void) {
13420
13603
  this.dragPan = true;
13421
13604
  this.dragRotate = true;
13422
13605
  this.doubleClickZoom = true;
13606
+ this.doubleClickDragZoom = true;
13423
13607
  this.touchZoom = true;
13424
13608
  this.touchRotate = false;
13425
13609
  this.keyboard = true;
@@ -13481,6 +13665,13 @@ void main(void) {
13481
13665
  return this._onMultiPanEnd(event);
13482
13666
  case "dblclick":
13483
13667
  return this._onDoubleClick(event);
13668
+ case "dblclickdragstart":
13669
+ return eventStartBlocked ? false : this._onDoubleClickDragStart(event);
13670
+ case "dblclickdragmove":
13671
+ return this._onDoubleClickDrag(event);
13672
+ case "dblclickdragend":
13673
+ case "dblclickdragcancel":
13674
+ return this._onDoubleClickDragEnd(event);
13484
13675
  case "wheel":
13485
13676
  return this._onWheel(event);
13486
13677
  case "keydown":
@@ -13553,6 +13744,7 @@ void main(void) {
13553
13744
  dragPan = true,
13554
13745
  dragRotate = true,
13555
13746
  doubleClickZoom = true,
13747
+ doubleClickDragZoom = false,
13556
13748
  touchZoom = true,
13557
13749
  touchRotate = false,
13558
13750
  keyboard = true
@@ -13563,11 +13755,13 @@ void main(void) {
13563
13755
  this.toggleEvents(EVENT_TYPES.PINCH, isInteractive && (touchZoom || touchRotate));
13564
13756
  this.toggleEvents(EVENT_TYPES.MULTI_PAN, isInteractive && touchRotate);
13565
13757
  this.toggleEvents(EVENT_TYPES.DOUBLE_CLICK, isInteractive && doubleClickZoom);
13758
+ this.toggleEvents(EVENT_TYPES.DOUBLE_CLICK_DRAG, isInteractive && doubleClickDragZoom);
13566
13759
  this.toggleEvents(EVENT_TYPES.KEYBOARD, isInteractive && keyboard);
13567
13760
  this.scrollZoom = scrollZoom;
13568
13761
  this.dragPan = dragPan;
13569
13762
  this.dragRotate = dragRotate;
13570
13763
  this.doubleClickZoom = doubleClickZoom;
13764
+ this.doubleClickDragZoom = doubleClickDragZoom;
13571
13765
  this.touchZoom = touchZoom;
13572
13766
  this.touchRotate = touchRotate;
13573
13767
  this.keyboard = keyboard;
@@ -13828,6 +14022,7 @@ void main(void) {
13828
14022
  }
13829
14023
  // Default handler for the `pinchstart` event.
13830
14024
  _onPinchStart(event) {
14025
+ this._doubleClickDragAnchor = null;
13831
14026
  const pos = this.getCenter(event);
13832
14027
  if (!this.isPointInBounds(pos, event)) {
13833
14028
  return false;
@@ -13913,6 +14108,9 @@ void main(void) {
13913
14108
  if (!this.doubleClickZoom) {
13914
14109
  return false;
13915
14110
  }
14111
+ if (Date.now() < this._suppressDoubleClickUntil) {
14112
+ return false;
14113
+ }
13916
14114
  const pos = this.getCenter(event);
13917
14115
  if (!this.isPointInBounds(pos, event)) {
13918
14116
  return false;
@@ -13926,6 +14124,56 @@ void main(void) {
13926
14124
  this.blockEvents(100);
13927
14125
  return true;
13928
14126
  }
14127
+ _onDoubleClickDragStart(event) {
14128
+ if (!this.doubleClickDragZoom) {
14129
+ this._doubleClickDragAnchor = null;
14130
+ return false;
14131
+ }
14132
+ const pos = this.getCenter(event);
14133
+ if (!this.isPointInBounds(pos, event)) {
14134
+ this._doubleClickDragAnchor = null;
14135
+ return false;
14136
+ }
14137
+ this._doubleClickDragAnchor = pos;
14138
+ let newControllerState = this.controllerState.zoomStart({ pos });
14139
+ if (event.scale !== 1) {
14140
+ newControllerState = newControllerState.zoom({ pos, scale: event.scale });
14141
+ }
14142
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
14143
+ isDragging: true,
14144
+ isPanning: true,
14145
+ isZooming: true
14146
+ });
14147
+ return true;
14148
+ }
14149
+ _onDoubleClickDrag(event) {
14150
+ const pos = this._doubleClickDragAnchor;
14151
+ if (!pos) {
14152
+ return false;
14153
+ }
14154
+ const newControllerState = this.controllerState.zoom({ pos, scale: event.scale });
14155
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
14156
+ isDragging: true,
14157
+ isPanning: true,
14158
+ isZooming: true
14159
+ });
14160
+ return true;
14161
+ }
14162
+ _onDoubleClickDragEnd(_event) {
14163
+ if (!this._doubleClickDragAnchor) {
14164
+ return false;
14165
+ }
14166
+ this._doubleClickDragAnchor = null;
14167
+ const newControllerState = this.controllerState.zoomEnd();
14168
+ this.updateViewport(newControllerState, null, {
14169
+ isDragging: false,
14170
+ isPanning: false,
14171
+ isZooming: false
14172
+ });
14173
+ this._suppressDoubleClickUntil = Date.now() + 100;
14174
+ this.blockEvents(100);
14175
+ return true;
14176
+ }
13929
14177
  // Default handler for the `keydown` event
13930
14178
  _onKeyDown(event) {
13931
14179
  if (!this.keyboard) {
package/dist/index.cjs CHANGED
@@ -801,8 +801,9 @@ var RECOGNIZERS = {
801
801
  multipan: [import_mjolnir.Pan, { threshold: 10, direction: import_mjolnir.InputDirection.Vertical, pointers: 2 }],
802
802
  pinch: [import_mjolnir.Pinch, {}, null, ["multipan"]],
803
803
  pan: [import_mjolnir.Pan, { threshold: 1 }, ["pinch"], ["multipan"]],
804
- dblclick: [import_mjolnir.Tap, { event: "dblclick", taps: 2 }],
805
- click: [import_mjolnir.Tap, { event: "click" }, null, ["dblclick"]]
804
+ dblclick: [import_mjolnir.Tap, { event: "dblclick", taps: 2, enable: false }],
805
+ dblclickdrag: [import_mjolnir.DoubleClickDrag, { event: "dblclickdrag", enable: false }, ["dblclick"], null],
806
+ click: [import_mjolnir.Tap, { event: "click" }, ["dblclickdrag"], ["dblclick", "dblclickdrag"]]
806
807
  };
807
808
 
808
809
  // ../core/src/viewports/viewport.ts
@@ -1597,8 +1598,8 @@ var import_core8 = require("@math.gl/core");
1597
1598
  // ../core/src/viewports/globe-viewport.ts
1598
1599
  var import_core6 = require("@math.gl/core");
1599
1600
  var import_web_mercator3 = require("@math.gl/web-mercator");
1600
- var import_web_mercator4 = require("@math.gl/web-mercator");
1601
1601
  var import_core7 = require("@math.gl/core");
1602
+ var import_web_mercator4 = require("@math.gl/web-mercator");
1602
1603
  var DEGREES_TO_RADIANS2 = Math.PI / 180;
1603
1604
  var RADIANS_TO_DEGREES = 180 / Math.PI;
1604
1605
  var EARTH_RADIUS = 6370972;
@@ -1619,6 +1620,8 @@ var GlobeViewport = class extends Viewport {
1619
1620
  constructor(opts = {}) {
1620
1621
  const {
1621
1622
  longitude = 0,
1623
+ bearing = 0,
1624
+ pitch = 0,
1622
1625
  zoom = 0,
1623
1626
  // Matches Maplibre defaults
1624
1627
  // https://github.com/maplibre/maplibre-gl-js/blob/f8ab4b48d59ab8fe7b068b102538793bbdd4c848/src/geo/projection/globe_transform.ts#L632-L633
@@ -1627,20 +1630,19 @@ var GlobeViewport = class extends Viewport {
1627
1630
  resolution = 10
1628
1631
  } = opts;
1629
1632
  let { latitude = 0, height, altitude = 1.5, fovy } = opts;
1630
- latitude = Math.max(Math.min(latitude, import_web_mercator4.MAX_LATITUDE), -import_web_mercator4.MAX_LATITUDE);
1633
+ latitude = Math.max(Math.min(latitude, 90), -90);
1631
1634
  height = height || 1;
1632
1635
  if (fovy) {
1633
1636
  altitude = (0, import_web_mercator3.fovyToAltitude)(fovy);
1634
1637
  } else {
1635
1638
  fovy = (0, import_web_mercator3.altitudeToFovy)(altitude);
1636
1639
  }
1637
- const scale = Math.pow(2, zoom - zoomAdjust(latitude));
1640
+ const scaleLatitude = Math.max(Math.min(latitude, import_web_mercator4.MAX_LATITUDE), -import_web_mercator4.MAX_LATITUDE);
1641
+ const scale = Math.pow(2, zoom - zoomAdjust(scaleLatitude));
1642
+ const pitchRadians = pitch * DEGREES_TO_RADIANS2;
1638
1643
  const nearZ = opts.nearZ ?? nearZMultiplier;
1639
- const farZ = opts.farZ ?? (altitude + GLOBE_RADIUS * 2 * scale / height) * farZMultiplier;
1640
- const viewMatrix = new import_core6.Matrix4().lookAt({ eye: [0, -altitude, 0], up: [0, 0, 1] });
1641
- viewMatrix.rotateX(latitude * DEGREES_TO_RADIANS2);
1642
- viewMatrix.rotateZ(-longitude * DEGREES_TO_RADIANS2);
1643
- viewMatrix.scale(scale / height);
1644
+ const farZ = opts.farZ ?? (altitude + GLOBE_RADIUS * 2 * scale / height / Math.max(Math.cos(pitchRadians), 0.1)) * farZMultiplier;
1645
+ const viewMatrix = new import_core6.Matrix4().lookAt({ eye: [0, -altitude, 0], up: [0, 0, 1] }).rotateX(-pitchRadians).rotateY(-bearing * DEGREES_TO_RADIANS2).rotateX(latitude * DEGREES_TO_RADIANS2).rotateZ(-longitude * DEGREES_TO_RADIANS2).scale(scale / height);
1644
1646
  super({
1645
1647
  ...opts,
1646
1648
  // x, y, width,
@@ -1660,6 +1662,8 @@ var GlobeViewport = class extends Viewport {
1660
1662
  this.scale = scale;
1661
1663
  this.latitude = latitude;
1662
1664
  this.longitude = longitude;
1665
+ this.bearing = bearing;
1666
+ this.pitch = pitch;
1663
1667
  this.fovy = fovy;
1664
1668
  this.resolution = resolution;
1665
1669
  }
@@ -1749,14 +1753,17 @@ var GlobeViewport = class extends Viewport {
1749
1753
  const rotationSpeed = 0.25 / scale;
1750
1754
  const longitude = startLng + rotationSpeed * (startPixel[0] - pixel[0]);
1751
1755
  let latitude = startLat - rotationSpeed * (startPixel[1] - pixel[1]);
1752
- latitude = Math.max(Math.min(latitude, import_web_mercator4.MAX_LATITUDE), -import_web_mercator4.MAX_LATITUDE);
1756
+ latitude = Math.max(Math.min(latitude, 90), -90);
1753
1757
  const out = { longitude, latitude, zoom: startZoom - zoomAdjust(startLat) };
1754
1758
  out.zoom += zoomAdjust(out.latitude);
1755
1759
  return out;
1756
1760
  }
1757
1761
  };
1758
1762
  GlobeViewport.displayName = "GlobeViewport";
1759
- function zoomAdjust(latitude) {
1763
+ function zoomAdjust(latitude, clampToPoles) {
1764
+ if (clampToPoles) {
1765
+ latitude = Math.max(Math.min(latitude, import_web_mercator4.MAX_LATITUDE), -import_web_mercator4.MAX_LATITUDE);
1766
+ }
1760
1767
  const scaleAdjust = Math.PI * Math.cos(latitude * Math.PI / 180);
1761
1768
  return Math.log2(scaleAdjust);
1762
1769
  }
@@ -1843,6 +1850,7 @@ var EVENT_TYPES = {
1843
1850
  PINCH: ["pinchstart", "pinchmove", "pinchend"],
1844
1851
  MULTI_PAN: ["multipanstart", "multipanmove", "multipanend"],
1845
1852
  DOUBLE_CLICK: ["dblclick"],
1853
+ DOUBLE_CLICK_DRAG: ["dblclickdragstart", "dblclickdragmove", "dblclickdragend", "dblclickdragcancel"],
1846
1854
  KEYBOARD: ["keydown"]
1847
1855
  };
1848
1856
  var pinchEventWorkaround = {};
@@ -1856,6 +1864,8 @@ var Controller = class {
1856
1864
  this._customEvents = [];
1857
1865
  this._eventStartBlocked = null;
1858
1866
  this._panMove = false;
1867
+ this._doubleClickDragAnchor = null;
1868
+ this._suppressDoubleClickUntil = 0;
1859
1869
  this.invertPan = false;
1860
1870
  this.dragMode = "rotate";
1861
1871
  this.inertia = 0;
@@ -1863,6 +1873,7 @@ var Controller = class {
1863
1873
  this.dragPan = true;
1864
1874
  this.dragRotate = true;
1865
1875
  this.doubleClickZoom = true;
1876
+ this.doubleClickDragZoom = true;
1866
1877
  this.touchZoom = true;
1867
1878
  this.touchRotate = false;
1868
1879
  this.keyboard = true;
@@ -1925,6 +1936,13 @@ var Controller = class {
1925
1936
  return this._onMultiPanEnd(event);
1926
1937
  case "dblclick":
1927
1938
  return this._onDoubleClick(event);
1939
+ case "dblclickdragstart":
1940
+ return eventStartBlocked ? false : this._onDoubleClickDragStart(event);
1941
+ case "dblclickdragmove":
1942
+ return this._onDoubleClickDrag(event);
1943
+ case "dblclickdragend":
1944
+ case "dblclickdragcancel":
1945
+ return this._onDoubleClickDragEnd(event);
1928
1946
  case "wheel":
1929
1947
  return this._onWheel(event);
1930
1948
  case "keydown":
@@ -1997,6 +2015,7 @@ var Controller = class {
1997
2015
  dragPan = true,
1998
2016
  dragRotate = true,
1999
2017
  doubleClickZoom = true,
2018
+ doubleClickDragZoom = false,
2000
2019
  touchZoom = true,
2001
2020
  touchRotate = false,
2002
2021
  keyboard = true
@@ -2007,11 +2026,13 @@ var Controller = class {
2007
2026
  this.toggleEvents(EVENT_TYPES.PINCH, isInteractive && (touchZoom || touchRotate));
2008
2027
  this.toggleEvents(EVENT_TYPES.MULTI_PAN, isInteractive && touchRotate);
2009
2028
  this.toggleEvents(EVENT_TYPES.DOUBLE_CLICK, isInteractive && doubleClickZoom);
2029
+ this.toggleEvents(EVENT_TYPES.DOUBLE_CLICK_DRAG, isInteractive && doubleClickDragZoom);
2010
2030
  this.toggleEvents(EVENT_TYPES.KEYBOARD, isInteractive && keyboard);
2011
2031
  this.scrollZoom = scrollZoom;
2012
2032
  this.dragPan = dragPan;
2013
2033
  this.dragRotate = dragRotate;
2014
2034
  this.doubleClickZoom = doubleClickZoom;
2035
+ this.doubleClickDragZoom = doubleClickDragZoom;
2015
2036
  this.touchZoom = touchZoom;
2016
2037
  this.touchRotate = touchRotate;
2017
2038
  this.keyboard = keyboard;
@@ -2272,6 +2293,7 @@ var Controller = class {
2272
2293
  }
2273
2294
  // Default handler for the `pinchstart` event.
2274
2295
  _onPinchStart(event) {
2296
+ this._doubleClickDragAnchor = null;
2275
2297
  const pos = this.getCenter(event);
2276
2298
  if (!this.isPointInBounds(pos, event)) {
2277
2299
  return false;
@@ -2357,6 +2379,9 @@ var Controller = class {
2357
2379
  if (!this.doubleClickZoom) {
2358
2380
  return false;
2359
2381
  }
2382
+ if (Date.now() < this._suppressDoubleClickUntil) {
2383
+ return false;
2384
+ }
2360
2385
  const pos = this.getCenter(event);
2361
2386
  if (!this.isPointInBounds(pos, event)) {
2362
2387
  return false;
@@ -2370,6 +2395,56 @@ var Controller = class {
2370
2395
  this.blockEvents(100);
2371
2396
  return true;
2372
2397
  }
2398
+ _onDoubleClickDragStart(event) {
2399
+ if (!this.doubleClickDragZoom) {
2400
+ this._doubleClickDragAnchor = null;
2401
+ return false;
2402
+ }
2403
+ const pos = this.getCenter(event);
2404
+ if (!this.isPointInBounds(pos, event)) {
2405
+ this._doubleClickDragAnchor = null;
2406
+ return false;
2407
+ }
2408
+ this._doubleClickDragAnchor = pos;
2409
+ let newControllerState = this.controllerState.zoomStart({ pos });
2410
+ if (event.scale !== 1) {
2411
+ newControllerState = newControllerState.zoom({ pos, scale: event.scale });
2412
+ }
2413
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
2414
+ isDragging: true,
2415
+ isPanning: true,
2416
+ isZooming: true
2417
+ });
2418
+ return true;
2419
+ }
2420
+ _onDoubleClickDrag(event) {
2421
+ const pos = this._doubleClickDragAnchor;
2422
+ if (!pos) {
2423
+ return false;
2424
+ }
2425
+ const newControllerState = this.controllerState.zoom({ pos, scale: event.scale });
2426
+ this.updateViewport(newControllerState, NO_TRANSITION_PROPS, {
2427
+ isDragging: true,
2428
+ isPanning: true,
2429
+ isZooming: true
2430
+ });
2431
+ return true;
2432
+ }
2433
+ _onDoubleClickDragEnd(_event) {
2434
+ if (!this._doubleClickDragAnchor) {
2435
+ return false;
2436
+ }
2437
+ this._doubleClickDragAnchor = null;
2438
+ const newControllerState = this.controllerState.zoomEnd();
2439
+ this.updateViewport(newControllerState, null, {
2440
+ isDragging: false,
2441
+ isPanning: false,
2442
+ isZooming: false
2443
+ });
2444
+ this._suppressDoubleClickUntil = Date.now() + 100;
2445
+ this.blockEvents(100);
2446
+ return true;
2447
+ }
2373
2448
  // Default handler for the `keydown` event
2374
2449
  _onKeyDown(event) {
2375
2450
  if (!this.keyboard) {