cesium-xs-sdk 1.0.16 → 1.0.17

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.
@@ -3566,6 +3566,58 @@ class EventModule {
3566
3566
  }
3567
3567
  }
3568
3568
 
3569
+ /**
3570
+ * 双击判定器
3571
+ *
3572
+ * 背景:Cesium 的 ScreenSpaceEventType.LEFT_DOUBLE_CLICK 唯一来源是 canvas 上的
3573
+ * DOM dblclick 事件,而 DOM dblclick 依赖浏览器/操作系统的双击合成
3574
+ * (时间阈值 + 位移阈值 + 触屏 touch slop + 双击缩放启发式),移动场景下经常
3575
+ * 不触发,导致"双击结束绘制/测量"在移动端静默失效。
3576
+ *
3577
+ * 本判定器在 SDK 自己的 LEFT_CLICK(mouse:click)流水上自维护双击判定:
3578
+ * 连续两次 click 间隔 < 时间阈值 且 屏幕位移 < 位移阈值,即判定为双击。
3579
+ * 如此双击收尾在鼠标、触屏、任何浏览器上行为一致,彻底移除对 DOM dblclick
3580
+ * 合成的依赖(桌面端 DOM dblclick 路径保留作为冗余,二者靠
3581
+ * _isDrawing / _isMeasuring 守卫天然防重)。
3582
+ *
3583
+ * 阈值取向:宁可漏判(用户多点一下),不可误判(把正常快速加点误判成双击收尾)。
3584
+ */
3585
+ const DOUBLE_CLICK_INTERVAL_MS = 300; // 时间阈值(ms)
3586
+ const DOUBLE_CLICK_DISTANCE_PX = 10; // 屏幕位移阈值(px)
3587
+
3588
+ class DoubleClickDetector {
3589
+ constructor() {
3590
+ /** @type {{timestamp: number, screenPos: {x: number, y: number}} | null} */
3591
+ this._last = null;
3592
+ }
3593
+
3594
+ /**
3595
+ * 清空内部状态。工具 activate / deactivate / 绘制会话结束 / 取消时调用,
3596
+ * 避免跨工具、跨绘制会话的脏状态污染下一次判定。
3597
+ */
3598
+ reset() {
3599
+ this._last = null;
3600
+ }
3601
+
3602
+ /**
3603
+ * 喂入一次 click,返回是否构成双击。
3604
+ * 注意:无论是否构成双击,本次点击都会成为下次判定的"上一次点击"。
3605
+ *
3606
+ * @param {number} timestamp performance.now()
3607
+ * @param {{x: number, y: number}} screenPos 屏幕坐标(取 movement.position)
3608
+ * @returns {boolean} 是否构成双击
3609
+ */
3610
+ feed(timestamp, screenPos) {
3611
+ const prev = this._last;
3612
+ this._last = { timestamp, screenPos };
3613
+ if (!prev) return false;
3614
+ if (timestamp - prev.timestamp > DOUBLE_CLICK_INTERVAL_MS) return false;
3615
+ const dx = screenPos.x - prev.screenPos.x;
3616
+ const dy = screenPos.y - prev.screenPos.y;
3617
+ return Math.hypot(dx, dy) <= DOUBLE_CLICK_DISTANCE_PX;
3618
+ }
3619
+ }
3620
+
3569
3621
  const Cesium$d = getCesium();
3570
3622
 
3571
3623
  /**
@@ -3581,6 +3633,8 @@ class BaseTool {
3581
3633
  this._options = options;
3582
3634
  this._isActive = false;
3583
3635
  this._handlers = []; // 注册的事件处理器 ID
3636
+ // 自维护双击判定器(DOM dblclick 在移动端经常不合成,见 DoubleClickDetector 注释)
3637
+ this._doubleClickDetector = new DoubleClickDetector();
3584
3638
  }
3585
3639
 
3586
3640
  /**
@@ -3589,6 +3643,8 @@ class BaseTool {
3589
3643
  activate() {
3590
3644
  if (this._isActive) return;
3591
3645
  this._isActive = true;
3646
+ // 防止跨工具切换时残留上次会话的末次点击,污染本次双击判定
3647
+ this._doubleClickDetector.reset();
3592
3648
  this.onActivate();
3593
3649
  }
3594
3650
 
@@ -3598,6 +3654,7 @@ class BaseTool {
3598
3654
  deactivate() {
3599
3655
  if (!this._isActive) return;
3600
3656
  this._isActive = false;
3657
+ this._doubleClickDetector.reset();
3601
3658
  this.onDeactivate();
3602
3659
  this.clearHandlers();
3603
3660
  }
@@ -3612,6 +3669,19 @@ class BaseTool {
3612
3669
  */
3613
3670
  onDeactivate() { }
3614
3671
 
3672
+ /**
3673
+ * 判定本次 mouse:click 是否构成"双击"(自维护判定,不依赖 DOM dblclick 合成)。
3674
+ * 子类应在"绘制 / 测量进行中"才调用本方法,避免把开启新会话的首次点击误判为双击。
3675
+ * @param {object} movement Cesium click 事件 movement(取 movement.position 作为屏幕坐标)
3676
+ * @returns {boolean}
3677
+ * @protected
3678
+ */
3679
+ _isDoubleClick(movement) {
3680
+ const pos = movement && movement.position;
3681
+ if (!pos) return false;
3682
+ return this._doubleClickDetector.feed(performance.now(), { x: pos.x, y: pos.y });
3683
+ }
3684
+
3615
3685
  /**
3616
3686
  * 注册事件观察者
3617
3687
  * @param {string} eventType 事件类型
@@ -3941,8 +4011,30 @@ class DrawTool extends BaseTool {
3941
4011
  // lngLat 已经是经纬度数组 [lon, lat, height]
3942
4012
  if (!lngLat) return;
3943
4013
 
3944
- // 优先处理标绘类型
3945
4014
  const plotConfig = PLOT_DRAW_CONFIG[this._drawType];
4015
+
4016
+ // === 自维护双击收尾判定 ===
4017
+ // DOM dblclick 在移动端/触屏经常不被浏览器合成(见 change-log),这里在
4018
+ // LEFT_CLICK 流水上自行判定:绘制中 + 类型支持双击收尾 + 两次 click
4019
+ // 时间/位移在阈值内 → 收尾。本次(双击第二次)点击不加点——双击第一次
4020
+ // 点击已把最后顶点加入 _tempPositions,直接收尾的结果与 DOM dblclick
4021
+ // 路径(_onDoubleClick pop 掉重叠点)逐点一致。
4022
+ // 不满足最小点数时降级为普通加点,落到下方正常逻辑。
4023
+ if (this._isDrawing && this._supportsDoubleClickFinish() && this._isDoubleClick(movement)) {
4024
+ const minPoints = plotConfig ? plotConfig.minPoints
4025
+ : (this._drawType === DrawType.POLYGON ? 3 : 2); // 线 2 / 面 3
4026
+ if (this._tempPositions.length >= minPoints) {
4027
+ if (plotConfig) {
4028
+ this._finishPlotDrawing(plotConfig);
4029
+ } else {
4030
+ this.finishDrawing();
4031
+ }
4032
+ return;
4033
+ }
4034
+ // 不满足最小点数:本次点击降级为普通加点(落到下方逻辑)
4035
+ }
4036
+
4037
+ // 优先处理标绘类型
3946
4038
  if (plotConfig) {
3947
4039
  this._handlePlotClick(lngLat, plotConfig);
3948
4040
  return;
@@ -4082,6 +4174,18 @@ class DrawTool extends BaseTool {
4082
4174
  }
4083
4175
  }
4084
4176
 
4177
+ /**
4178
+ * 当前绘制类型是否支持"双击收尾":
4179
+ * 仅线 / 面 / 声明了 finishOnDoubleClick 的标绘类型支持;
4180
+ * 点 / 矩形 / 圆保持不响应(与 _onDoubleClick 的语义一致)。
4181
+ * @private
4182
+ */
4183
+ _supportsDoubleClickFinish() {
4184
+ if (this._drawType === DrawType.LINE || this._drawType === DrawType.POLYGON) return true;
4185
+ const plotConfig = PLOT_DRAW_CONFIG[this._drawType];
4186
+ return !!(plotConfig && plotConfig.finishOnDoubleClick);
4187
+ }
4188
+
4085
4189
  /**
4086
4190
  * 双击结束绘制(移动端用:移动端没有右键;桌面端:避免绘制过程中双击误触发放大)
4087
4191
  * 与 _onRightClick 等价,仅线 / 面 / 标绘(声明了 finishOnDoubleClick 的)响应;
@@ -4747,6 +4851,9 @@ class DrawTool extends BaseTool {
4747
4851
  this._tempPositions = [];
4748
4852
  this._previewPlot = null;
4749
4853
 
4854
+ // 绘制会话结束:清空双击判定器,避免下次绘制的开头点击与本次末次点击构成误判
4855
+ this._doubleClickDetector.reset();
4856
+
4750
4857
  this._emitGraphicCreated(config.plotType, id);
4751
4858
  }
4752
4859
 
@@ -4778,6 +4885,8 @@ class DrawTool extends BaseTool {
4778
4885
  this._clickCount = 0;
4779
4886
  this._startPos = null;
4780
4887
  this._currentMousePos = null;
4888
+ // 绘制会话取消:清空双击判定器,避免下次绘制受本次末次点击污染
4889
+ this._doubleClickDetector.reset();
4781
4890
  this._emitDrawCancel();
4782
4891
  }
4783
4892
 
@@ -4833,6 +4942,9 @@ class DrawTool extends BaseTool {
4833
4942
  this._clickCount = 0;
4834
4943
  this._currentMousePos = null;
4835
4944
 
4945
+ // 绘制会话结束:清空双击判定器,避免下次绘制的开头点击与本次末次点击构成误判
4946
+ this._doubleClickDetector.reset();
4947
+
4836
4948
  if (deferredPreviewLine) {
4837
4949
  requestAnimationFrame(() => this.removeTempEntity(deferredPreviewLine));
4838
4950
  }
@@ -7734,7 +7846,7 @@ class MeasureTool extends BaseTool {
7734
7846
  controller.enableRotate = this._originalEnableRotate;
7735
7847
  }
7736
7848
 
7737
- _onClick(lngLat, _pickedEntity, _movement) {
7849
+ _onClick(lngLat, _pickedEntity, movement) {
7738
7850
  if (!lngLat) return;
7739
7851
 
7740
7852
  // 拖拽刚结束:吞掉紧跟 mouseup 的 click,避免误开新测量
@@ -7743,6 +7855,21 @@ class MeasureTool extends BaseTool {
7743
7855
  return;
7744
7856
  }
7745
7857
 
7858
+ // === 自维护双击收尾判定 ===
7859
+ // DOM dblclick 在移动端/触屏经常不被浏览器合成(见 change-log),这里在
7860
+ // LEFT_CLICK 流水上自行判定:测量中(非拖拽中)+ 两次 click 时间/位移在
7861
+ // 阈值内 → 收尾。本次(双击第二次)点击不加点——双击第一次点击已把最后
7862
+ // 顶点加入 _positions,直接收尾的结果与 DOM dblclick 路径(_onDoubleClick
7863
+ // pop 掉重叠点)逐点一致。不满足最小点数时降级为普通加点。
7864
+ if (this._isMeasuring && !this._isDragging && this._isDoubleClick(movement)) {
7865
+ const minPoints = this._measureType === MeasureType.AREA ? 3 : 2;
7866
+ if (this._positions.length >= minPoints) {
7867
+ this._finishMeasurement();
7868
+ return;
7869
+ }
7870
+ // 不满足最小点数:本次点击降级为普通加点(落到下方逻辑)
7871
+ }
7872
+
7746
7873
  // 同步鼠标位置为本次 click 的经纬度:修复"地图拖动后原地点击 → 预览线
7747
7874
  // 自动连接到旧鼠标位置"的 bug(主要暴露在移动端双击完成测量后)。
7748
7875
  //
@@ -7981,6 +8108,9 @@ class MeasureTool extends BaseTool {
7981
8108
  // 测量已完成 → 恢复地图拖动 / 旋转
7982
8109
  this._restoreCameraAfterMeasuring();
7983
8110
 
8111
+ // 测量会话结束:清空双击判定器,避免下次测量受本次末次点击污染
8112
+ this._doubleClickDetector.reset();
8113
+
7984
8114
  this._emitMeasureComplete(result);
7985
8115
  }
7986
8116
 
@@ -8082,6 +8212,8 @@ class MeasureTool extends BaseTool {
8082
8212
  this.clearMeasurements();
8083
8213
  // 取消时也要恢复地图拖动(与 _finishMeasurement 对称)
8084
8214
  this._restoreCameraAfterMeasuring();
8215
+ // 测量会话取消:清空双击判定器,避免下次测量受本次末次点击污染
8216
+ this._doubleClickDetector.reset();
8085
8217
  this._emitMeasureCancel();
8086
8218
  }
8087
8219