cesium-xs-sdk 1.0.17 → 1.0.18

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.
@@ -9088,6 +9088,9 @@ class EditorModule {
9088
9088
  this.currentToolName = name;
9089
9089
  this.currentTool.activate();
9090
9090
  this._isActive = true;
9091
+ // 供其他组件(如 Zoom 双击缩放)感知"编辑器工具激活中",
9092
+ // 工具激活期间双击/右键有工具自身语义,缩放等全局交互应让行
9093
+ this.viewer.xs3dEditorActive = true;
9091
9094
 
9092
9095
  console.log(`工具 ${name} 已激活`);
9093
9096
  return this;
@@ -9104,6 +9107,9 @@ class EditorModule {
9104
9107
  this.currentTool = null;
9105
9108
  this.currentToolName = null;
9106
9109
  this._isActive = false;
9110
+ if (this.viewer) {
9111
+ this.viewer.xs3dEditorActive = false;
9112
+ }
9107
9113
 
9108
9114
  return this;
9109
9115
  }
@@ -9734,10 +9740,13 @@ class LocationBar extends BaseControl {
9734
9740
  // 鼠标移动:更新鼠标位置信息
9735
9741
  const canvas = this._viewer.scene.canvas;
9736
9742
  this._addDomEvent(canvas, 'mousemove', this._onMouseMove.bind(this));
9737
- this._addDomEvent(canvas, 'mouseleave', this._onMouseLeave.bind(this));
9743
+ // 鼠标移出画布不再重置为 '-':保留最后拾取的坐标(见 _onMouseMove 说明)
9738
9744
 
9739
9745
  // 相机变化:更新方向/俯仰/视高/层级
9740
9746
  this._addCesiumHandler(this._viewer.camera.changed, this._onCameraChanged.bind(this));
9747
+ // flyTo 动画尾段每帧位移小于 percentageChanged 阈值后 changed 不再触发,
9748
+ // 信息栏会滞后一级;相机停止移动时强制刷新一次
9749
+ this._addCesiumHandler(this._viewer.camera.moveEnd, this._onCameraChanged.bind(this));
9741
9750
 
9742
9751
  // FPS
9743
9752
  if (this._showFPS) {
@@ -9776,16 +9785,10 @@ class LocationBar extends BaseControl {
9776
9785
  lat: Cesium$6.Math.toDegrees(cartographic.latitude).toFixed(this._latDecimal),
9777
9786
  alt: cartographic.height.toFixed(2)
9778
9787
  };
9779
- } else {
9780
- this._lastMouseData = { lng: '-', lat: '-', alt: '-' };
9788
+ this._updateContent();
9781
9789
  }
9782
-
9783
- this._updateContent();
9784
- }
9785
-
9786
- _onMouseLeave() {
9787
- this._lastMouseData = { lng: '-', lat: '-', alt: '-' };
9788
- this._updateContent();
9790
+ // 拾取不到(鼠标指向太空/地球未加载等)时不刷新,
9791
+ // 保留最后一次成功拾取的坐标,避免信息栏闪现"-"
9789
9792
  }
9790
9793
 
9791
9794
  _onCameraChanged() {
@@ -9867,6 +9870,8 @@ class Zoom extends BaseControl {
9867
9870
  /**
9868
9871
  * @param {object} options
9869
9872
  * @param {number} [options.duration=0.5] 缩放动画时长(秒)
9873
+ * @param {boolean} [options.doubleClickZoomIn=false] 左键双击放大一级(桌面端)
9874
+ * @param {boolean} [options.doubleClickZoomOut=false] 右键双击缩小一级(桌面端)
9870
9875
  */
9871
9876
  constructor(options = {}) {
9872
9877
  super({
@@ -9875,6 +9880,19 @@ class Zoom extends BaseControl {
9875
9880
  });
9876
9881
 
9877
9882
  this._duration = options.duration ?? 0.5;
9883
+ // 本控件发起的缩放飞行目标层级;飞行进行中(含动画尾段)点击按钮时,
9884
+ // 以它而不是相机瞬时位置作为基准层级
9885
+ this._pendingLevel = null;
9886
+ // 双击缩放(默认关闭;开启后会替换 Cesium Viewer 默认的左键双击动作)
9887
+ this._doubleClickZoomIn = options.doubleClickZoomIn ?? false;
9888
+ this._doubleClickZoomOut = options.doubleClickZoomOut ?? false;
9889
+ this._doubleClickEnabled = this._doubleClickZoomIn || this._doubleClickZoomOut;
9890
+ this._doubleClickInstalled = false;
9891
+ this._savedDoubleClickActions = null;
9892
+ // 右键双击判定器:Cesium 的 RIGHT_DOUBLE_CLICK 在桌面端没有任何触发源
9893
+ // (ScreenSpaceEventHandler 的 dblclick 监听只映射左键),
9894
+ // 因此右键双击在 RIGHT_CLICK 流水上自维护(复用工具的 DoubleClickDetector)
9895
+ this._rightDoubleClickDetector = new DoubleClickDetector();
9878
9896
  }
9879
9897
 
9880
9898
  _createContainer() {
@@ -9935,6 +9953,118 @@ class Zoom extends BaseControl {
9935
9953
  e.stopPropagation();
9936
9954
  this._zoomOut();
9937
9955
  });
9956
+
9957
+ // 双击缩放注册到 viewer.screenSpaceEventHandler(而不是 DOM 事件):
9958
+ // 绘制/量测工具激活时会保存-移除-恢复当前的左键双击动作,
9959
+ // 注册在这里可以让工具自动接管,无需额外协调
9960
+ if (this._doubleClickEnabled) {
9961
+ this._installDoubleClickZoom();
9962
+ }
9963
+ }
9964
+
9965
+ /**
9966
+ * 开启双击缩放(运行期可随时调用,只切换内部开关,不重建事件)
9967
+ * 若初始化时未指定任何方向(两个选项均 false),默认只开左键双击放大
9968
+ * @returns {Zoom}
9969
+ */
9970
+ enableDoubleClickZoom() {
9971
+ this._doubleClickEnabled = true;
9972
+ if (!this._doubleClickZoomIn && !this._doubleClickZoomOut) {
9973
+ this._doubleClickZoomIn = true;
9974
+ }
9975
+ // 初始化时未安装过(选项均为 false)则补注册;
9976
+ // 编辑器工具激活期间不抢占工具的左键双击,等工具结束恢复动作后即可用
9977
+ if (!this._doubleClickInstalled && this._viewer && !this._viewer.xs3dEditorActive) {
9978
+ this._installDoubleClickZoom();
9979
+ }
9980
+ return this;
9981
+ }
9982
+
9983
+ /**
9984
+ * 关闭双击缩放(运行期可随时调用;放大/缩小按钮不受影响)
9985
+ * @returns {Zoom}
9986
+ */
9987
+ disableDoubleClickZoom() {
9988
+ this._doubleClickEnabled = false;
9989
+ return this;
9990
+ }
9991
+
9992
+ /**
9993
+ * 安装左键双击 / 右键双击缩放的输入动作,并保存被替换的原始动作供移除时恢复。
9994
+ * 左键走 Cesium 的 LEFT_DOUBLE_CLICK(桌面端 DOM dblclick);
9995
+ * 右键 Cesium 无 RIGHT_DOUBLE_CLICK 触发源,改在 RIGHT_CLICK 上用
9996
+ * DoubleClickDetector 自维护判定(连续两次右键间隔 < 300ms 且位移 < 10px)。
9997
+ */
9998
+ _installDoubleClickZoom() {
9999
+ if (this._doubleClickInstalled || !this._viewer) return;
10000
+ const handler = this._viewer.screenSpaceEventHandler;
10001
+ if (!handler) return;
10002
+
10003
+ const EventType = Cesium$5.ScreenSpaceEventType;
10004
+ const saved = {};
10005
+ if (this._doubleClickZoomIn) {
10006
+ saved.left = handler.getInputAction(EventType.LEFT_DOUBLE_CLICK);
10007
+ handler.setInputAction(
10008
+ (movement) => this._onDoubleClickZoom(1, movement),
10009
+ EventType.LEFT_DOUBLE_CLICK
10010
+ );
10011
+ }
10012
+ if (this._doubleClickZoomOut) {
10013
+ saved.right = handler.getInputAction(EventType.RIGHT_CLICK);
10014
+ handler.setInputAction(
10015
+ (movement) => this._onRightClickForDoubleClick(movement),
10016
+ EventType.RIGHT_CLICK
10017
+ );
10018
+ }
10019
+ this._savedDoubleClickActions = saved;
10020
+ this._doubleClickInstalled = true;
10021
+ }
10022
+
10023
+ /**
10024
+ * 右键单击喂入双击判定器,构成双击时缩小一级
10025
+ * @param {object} movement Cesium 右键事件对象
10026
+ */
10027
+ _onRightClickForDoubleClick(movement) {
10028
+ if (!this._doubleClickEnabled || !this._viewer) return;
10029
+ // 编辑器工具激活期间:右键是工具的撤销/结束语义,清状态不喂入,
10030
+ // 避免把两次撤销误判成双击缩放,或把脏状态带到工具结束后
10031
+ if (this._viewer.xs3dEditorActive) {
10032
+ this._rightDoubleClickDetector.reset();
10033
+ return;
10034
+ }
10035
+ const pos = movement?.position;
10036
+ if (!pos) return;
10037
+ if (this._rightDoubleClickDetector.feed(performance.now(), { x: pos.x, y: pos.y })) {
10038
+ this._rightDoubleClickDetector.reset();
10039
+ this._onDoubleClickZoom(-1, movement);
10040
+ }
10041
+ }
10042
+
10043
+ /**
10044
+ * 双击缩放处理:以双击拾取位置为中心步进一级
10045
+ * @param {number} levelDelta +1 放大一级,-1 缩小一级
10046
+ * @param {object} movement Cesium 双击事件对象
10047
+ */
10048
+ _onDoubleClickZoom(levelDelta, movement) {
10049
+ if (!this._doubleClickEnabled || !this._viewer) return;
10050
+ // 绘制/量测/编辑工具激活期间禁用:左键双击是工具的收尾语义,
10051
+ // 右键单击是工具的撤销/结束语义,右键双击不能叠加缩放
10052
+ if (this._viewer.xs3dEditorActive) return;
10053
+
10054
+ const camera = this._viewer.camera;
10055
+ // 以双击位置拾取到的地表点为缩放中心;拾取不到退回相机正下方
10056
+ let cartographic = camera.positionCartographic;
10057
+ if (movement?.position && this._viewer.scene?.globe) {
10058
+ const ray = camera.getPickRay(movement.position);
10059
+ const cartesian = ray ? this._viewer.scene.globe.pick(ray, this._viewer.scene) : null;
10060
+ if (cartesian) {
10061
+ cartographic = Cesium$5.Cartographic.fromCartesian(cartesian);
10062
+ }
10063
+ }
10064
+
10065
+ const currentLevel = this._pendingLevel ?? this._getZoomLevel();
10066
+ const targetLevel = Math.max(0, Math.min(24, currentLevel + levelDelta));
10067
+ this._flyToLevel(targetLevel, cartographic);
9938
10068
  }
9939
10069
 
9940
10070
  _zoomIn() {
@@ -9950,12 +10080,21 @@ class Zoom extends BaseControl {
9950
10080
  * @param {number} levelDelta 层级变化量,+1 放大一级,-1 缩小一级
9951
10081
  */
9952
10082
  _zoomBy(levelDelta) {
9953
- const camera = this._viewer.camera;
9954
- const cartographic = camera.positionCartographic;
9955
- const currentLevel = this._getZoomLevel();
10083
+ const currentLevel = this._pendingLevel ?? this._getZoomLevel();
9956
10084
  const targetLevel = Math.max(0, Math.min(24, currentLevel + levelDelta));
10085
+ this._flyToLevel(targetLevel, this._viewer.camera.positionCartographic);
10086
+ }
10087
+
10088
+ /**
10089
+ * 飞到指定层级(以给定经纬度为中心),并记录 _pendingLevel
10090
+ * @param {number} targetLevel 目标层级
10091
+ * @param {Cesium.Cartographic} cartographic 目的地中心
10092
+ */
10093
+ _flyToLevel(targetLevel, cartographic) {
10094
+ const camera = this._viewer.camera;
9957
10095
  const targetHeight = this._getHeightByZoomLevel(targetLevel);
9958
10096
 
10097
+ this._pendingLevel = targetLevel;
9959
10098
  camera.flyTo({
9960
10099
  destination: Cesium$5.Cartesian3.fromRadians(
9961
10100
  cartographic.longitude,
@@ -9967,7 +10106,13 @@ class Zoom extends BaseControl {
9967
10106
  pitch: camera.pitch,
9968
10107
  roll: camera.roll
9969
10108
  },
9970
- duration: this._duration
10109
+ duration: this._duration,
10110
+ complete: () => {
10111
+ if (this._pendingLevel === targetLevel) this._pendingLevel = null;
10112
+ },
10113
+ cancel: () => {
10114
+ if (this._pendingLevel === targetLevel) this._pendingLevel = null;
10115
+ }
9971
10116
  });
9972
10117
  }
9973
10118
 
@@ -9986,7 +10131,36 @@ class Zoom extends BaseControl {
9986
10131
 
9987
10132
  _getHeightByZoomLevel(level) {
9988
10133
  const equatorCircumference = 6378137 * 2 * Math.PI;
9989
- return equatorCircumference / Math.pow(2, Math.max(0, level - 1));
10134
+ // 取层级几何带中心(C / 2^(L-0.5)),而不是分界线高度 C / 2^(L-1):
10135
+ // 分界线上浮点误差会导致层级反推差一级(实测约 1/3 经纬度位置),
10136
+ // 且动画尾段相机 changed 事件不再触发,信息栏会滞后一级显示。
10137
+ return equatorCircumference / Math.pow(2, Math.max(0, level - 0.5));
10138
+ }
10139
+
10140
+ /**
10141
+ * 销毁:恢复安装双击缩放前的输入动作
10142
+ * 编辑器工具激活期间不恢复(当前动作归工具所有,由工具的恢复链处理;
10143
+ * 工具结束后会放回本控件的 handler,其中 _viewer 已置空,调用即 no-op)
10144
+ */
10145
+ _destroy() {
10146
+ if (this._doubleClickInstalled && this._viewer?.screenSpaceEventHandler) {
10147
+ const handler = this._viewer.screenSpaceEventHandler;
10148
+ const EventType = Cesium$5.ScreenSpaceEventType;
10149
+ const saved = this._savedDoubleClickActions || {};
10150
+ [
10151
+ ['left', EventType.LEFT_DOUBLE_CLICK],
10152
+ ['right', EventType.RIGHT_CLICK]
10153
+ ].forEach(([key, eventType]) => {
10154
+ if (!(key in saved)) return;
10155
+ if (typeof saved[key] === 'function') {
10156
+ handler.setInputAction(saved[key], eventType);
10157
+ } else {
10158
+ handler.removeInputAction(eventType);
10159
+ }
10160
+ });
10161
+ }
10162
+ this._doubleClickInstalled = false;
10163
+ this._savedDoubleClickActions = null;
9990
10164
  }
9991
10165
  }
9992
10166