cesium-xs-sdk 1.0.18 → 1.0.20
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/cesium-xs-sdk.cjs.js +436 -271
- package/dist/cesium-xs-sdk.cjs.js.map +1 -1
- package/dist/cesium-xs-sdk.esm.js +436 -271
- package/dist/cesium-xs-sdk.esm.js.map +1 -1
- package/dist/cesium-xs-sdk.umd.js +1 -1
- package/dist/cesium-xs-sdk.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/controls/Zoom.js +96 -23
- package/src/core/LabelDepthConfig.js +15 -0
- package/src/index.d.ts +14 -0
- package/src/index.js +2 -0
- package/src/modules/GraphicModule.js +4 -3
- package/src/modules/SceneModule.js +18 -0
- package/src/modules/tools/BaseTool.js +34 -6
- package/src/modules/tools/DeleteTool.js +8 -7
- package/src/modules/tools/DrawTool.js +129 -174
- package/src/modules/tools/EditTool.js +90 -34
- package/src/modules/tools/MeasureTool.js +46 -21
- package/src/modules/tools/SelectTool.js +4 -3
- package/dist/assets/point-marker.png +0 -0
|
@@ -845,6 +845,24 @@ class SceneModule {
|
|
|
845
845
|
}
|
|
846
846
|
});
|
|
847
847
|
}
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* 是否开启南北极轴约束
|
|
851
|
+
* 开启时(Cesium 默认行为)鼠标旋转/缩放无法让相机越过南北极点;
|
|
852
|
+
* 关闭时(viewer.camera.constrainedAxis = undefined)相机可穿越极点。
|
|
853
|
+
* @param {boolean} [enabled=true] true 开启约束,false 关闭约束
|
|
854
|
+
*/
|
|
855
|
+
setPolarAxisConstraint(enabled = true) {
|
|
856
|
+
this.viewer.camera.constrainedAxis = enabled ? Cesium$h.Cartesian3.UNIT_Z : undefined;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* 查询南北极轴约束是否开启
|
|
861
|
+
* @returns {boolean} true 已开启(相机不可穿越极点),false 已关闭
|
|
862
|
+
*/
|
|
863
|
+
isPolarAxisConstraintEnabled() {
|
|
864
|
+
return Cesium$h.defined(this.viewer.camera.constrainedAxis);
|
|
865
|
+
}
|
|
848
866
|
}
|
|
849
867
|
|
|
850
868
|
const Cesium$g = getCesium();
|
|
@@ -2032,6 +2050,22 @@ function isLinePlotType(plotType) {
|
|
|
2032
2050
|
].includes(plotType);
|
|
2033
2051
|
}
|
|
2034
2052
|
|
|
2053
|
+
/**
|
|
2054
|
+
* 控制 SDK 内 LabelGraphics / BillboardGraphics / PointPrimitive 的
|
|
2055
|
+
* disableDepthTestDistance 默认值。
|
|
2056
|
+
*
|
|
2057
|
+
* 语义:相机距离图元小于等于 distance(米)时不进行深度测试,
|
|
2058
|
+
* 即近处观察时图元始终绘制在前景,避免被地形/建筑局部遮挡;
|
|
2059
|
+
* 大于 distance 时恢复正常深度测试,避免地球背面透视。
|
|
2060
|
+
*
|
|
2061
|
+
* 默认 8000 米;可在运行时改写:
|
|
2062
|
+
* import { LabelDepthConfig } from 'cesium-xs-sdk'
|
|
2063
|
+
* LabelDepthConfig.distance = 4000
|
|
2064
|
+
*/
|
|
2065
|
+
const LabelDepthConfig = {
|
|
2066
|
+
distance: 8000,
|
|
2067
|
+
};
|
|
2068
|
+
|
|
2035
2069
|
const Cesium$f = getCesium();
|
|
2036
2070
|
|
|
2037
2071
|
/**
|
|
@@ -2069,7 +2103,7 @@ class PointWrapper {
|
|
|
2069
2103
|
}
|
|
2070
2104
|
|
|
2071
2105
|
setDisableDepthTestDistance(distance) {
|
|
2072
|
-
this._entity.point.disableDepthTestDistance = distance;
|
|
2106
|
+
this._entity.point.disableDepthTestDistance = LabelDepthConfig.distance;
|
|
2073
2107
|
return this;
|
|
2074
2108
|
}
|
|
2075
2109
|
|
|
@@ -2105,7 +2139,7 @@ class PointWrapper {
|
|
|
2105
2139
|
this._entity.label.text = text;
|
|
2106
2140
|
|
|
2107
2141
|
// 应用配置选项
|
|
2108
|
-
this._entity.label.disableDepthTestDistance = options.disableDepthTestDistance ??
|
|
2142
|
+
this._entity.label.disableDepthTestDistance = options.disableDepthTestDistance ?? LabelDepthConfig.distance;
|
|
2109
2143
|
this._entity.label.verticalOrigin = options.verticalOrigin ?? Cesium$f.VerticalOrigin.BOTTOM;
|
|
2110
2144
|
this._entity.label.eyeOffset = options.eyeOffset ?? new Cesium$f.Cartesian3(0, 0, -10);
|
|
2111
2145
|
this._entity.label.heightReference = options.heightReference ?? Cesium$f.HeightReference.RELATIVE_TO_GROUND;
|
|
@@ -2694,7 +2728,7 @@ class BillboardWrapper {
|
|
|
2694
2728
|
}
|
|
2695
2729
|
|
|
2696
2730
|
setDisableDepthTestDistance(distance) {
|
|
2697
|
-
this._entity.billboard.disableDepthTestDistance = distance;
|
|
2731
|
+
this._entity.billboard.disableDepthTestDistance = LabelDepthConfig.distance;
|
|
2698
2732
|
return this;
|
|
2699
2733
|
}
|
|
2700
2734
|
|
|
@@ -3635,6 +3669,9 @@ class BaseTool {
|
|
|
3635
3669
|
this._handlers = []; // 注册的事件处理器 ID
|
|
3636
3670
|
// 自维护双击判定器(DOM dblclick 在移动端经常不合成,见 DoubleClickDetector 注释)
|
|
3637
3671
|
this._doubleClickDetector = new DoubleClickDetector();
|
|
3672
|
+
// mousemove rAF 节流状态:多次 move 之间只保留最新一次,与 render 帧同步
|
|
3673
|
+
this._moveRafId = null;
|
|
3674
|
+
this._movePendingCb = null;
|
|
3638
3675
|
}
|
|
3639
3676
|
|
|
3640
3677
|
/**
|
|
@@ -3655,6 +3692,12 @@ class BaseTool {
|
|
|
3655
3692
|
if (!this._isActive) return;
|
|
3656
3693
|
this._isActive = false;
|
|
3657
3694
|
this._doubleClickDetector.reset();
|
|
3695
|
+
// 取消 pending 的 mousemove rAF,避免停用后仍执行预览逻辑
|
|
3696
|
+
if (this._moveRafId != null) {
|
|
3697
|
+
cancelAnimationFrame(this._moveRafId);
|
|
3698
|
+
this._moveRafId = null;
|
|
3699
|
+
this._movePendingCb = null;
|
|
3700
|
+
}
|
|
3658
3701
|
this.onDeactivate();
|
|
3659
3702
|
this.clearHandlers();
|
|
3660
3703
|
}
|
|
@@ -3690,17 +3733,36 @@ class BaseTool {
|
|
|
3690
3733
|
*/
|
|
3691
3734
|
registerObserver(eventType, callback) {
|
|
3692
3735
|
const observerId = this._eventModule.registerObserver(eventType, (lngLat, entity, movement) => {
|
|
3693
|
-
// mouse:move
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
} else {
|
|
3697
|
-
callback(lngLat, entity, movement);
|
|
3698
|
-
}
|
|
3736
|
+
// 统一转发:mouse:move 也带上 EventModule 已计算的 lngLat / pickedEntity,
|
|
3737
|
+
// 避免工具层再调 scene.pickPosition / scene.pick 造成 2× 调用。
|
|
3738
|
+
callback(lngLat, entity, movement);
|
|
3699
3739
|
});
|
|
3700
3740
|
this._handlers.push({ eventType, observerId });
|
|
3701
3741
|
return observerId;
|
|
3702
3742
|
}
|
|
3703
3743
|
|
|
3744
|
+
/**
|
|
3745
|
+
* 将高频 mousemove 处理合并到下一帧:多次调用之间只保留最新一次的回调,
|
|
3746
|
+
* 与 Cesium render 帧对齐(~60Hz),避免全球视角下 pickPosition / CallbackProperty
|
|
3747
|
+
* 在 100+ Hz 浏览器原生频率下成为热点。
|
|
3748
|
+
*
|
|
3749
|
+
* 使用方式(仅对"非交互关键 + 计算密集"的预览路径):
|
|
3750
|
+
* this._scheduleMoveWork(() => this._updatePreview(this._mousePos));
|
|
3751
|
+
*
|
|
3752
|
+
* 注意:callback 应在闭包里读取 this 上的最新字段(_currentMousePos 等),
|
|
3753
|
+
* 不要传参;参数会被合并掉的多次调用的中间值覆盖。
|
|
3754
|
+
*/
|
|
3755
|
+
_scheduleMoveWork(callback) {
|
|
3756
|
+
this._movePendingCb = callback;
|
|
3757
|
+
if (this._moveRafId != null) return;
|
|
3758
|
+
this._moveRafId = requestAnimationFrame(() => {
|
|
3759
|
+
const cb = this._movePendingCb;
|
|
3760
|
+
this._moveRafId = null;
|
|
3761
|
+
this._movePendingCb = null;
|
|
3762
|
+
if (cb) cb();
|
|
3763
|
+
});
|
|
3764
|
+
}
|
|
3765
|
+
|
|
3704
3766
|
/**
|
|
3705
3767
|
* 清除所有已注册的事件处理器
|
|
3706
3768
|
*/
|
|
@@ -4059,39 +4121,66 @@ class DrawTool extends BaseTool {
|
|
|
4059
4121
|
}
|
|
4060
4122
|
}
|
|
4061
4123
|
|
|
4062
|
-
_onMove(
|
|
4063
|
-
|
|
4064
|
-
const screenPos = data.position || data.endPosition;
|
|
4124
|
+
_onMove(lngLat, entity, movement) {
|
|
4125
|
+
const screenPos = movement.position || movement.endPosition;
|
|
4065
4126
|
if (!screenPos) return;
|
|
4066
|
-
|
|
4127
|
+
// 优先使用 EventModule 已计算的 lngLat(避免重复 scene.pickPosition);
|
|
4128
|
+
// 拾取失败(如鼠标移到地球外)时回退到 screenToLonLat。
|
|
4129
|
+
const lonLat = lngLat || this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
|
|
4067
4130
|
if (!lonLat) return;
|
|
4068
4131
|
|
|
4069
4132
|
this._currentMousePos = lonLat;
|
|
4070
4133
|
|
|
4071
4134
|
if (this._drawType === DrawType.POINT) return;
|
|
4072
4135
|
|
|
4136
|
+
// 预览几何更新是计算密集路径(CallbackProperty / 经纬度→ECEF / 标绘算法),
|
|
4137
|
+
// 在全球视角下每帧都跑成本高,合并到下一帧(~60Hz),丢弃中间 move 事件。
|
|
4138
|
+
this._scheduleMoveWork(() => this._applyPreviewUpdate());
|
|
4139
|
+
|
|
4140
|
+
// 鼠标光标类反馈保持同步(每次 mousemove 都要响应,不走 rAF 合并)
|
|
4141
|
+
if (
|
|
4142
|
+
(this._drawType === DrawType.LINE || this._drawType === DrawType.POLYGON) &&
|
|
4143
|
+
this._isDrawing
|
|
4144
|
+
) {
|
|
4145
|
+
this._updatePreviewCursor();
|
|
4146
|
+
}
|
|
4147
|
+
}
|
|
4148
|
+
|
|
4149
|
+
/**
|
|
4150
|
+
* 真正执行预览更新:由 _scheduleMoveWork 在下一帧调用一次,读取
|
|
4151
|
+
* this._currentMousePos / _startPos / _tempPositions 等最新字段。
|
|
4152
|
+
*/
|
|
4153
|
+
_applyPreviewUpdate() {
|
|
4154
|
+
const lonLat = this._currentMousePos;
|
|
4155
|
+
if (!lonLat) return;
|
|
4156
|
+
|
|
4073
4157
|
// 标绘类型预览
|
|
4074
4158
|
const plotConfig = PLOT_DRAW_CONFIG[this._drawType];
|
|
4075
4159
|
if (plotConfig) {
|
|
4076
4160
|
if (this._isDrawing && this._tempPositions.length >= plotConfig.minPoints - 1) {
|
|
4077
|
-
this._updatePlotPreview(plotConfig
|
|
4161
|
+
this._updatePlotPreview(plotConfig);
|
|
4078
4162
|
}
|
|
4079
4163
|
return;
|
|
4080
4164
|
}
|
|
4081
4165
|
|
|
4082
4166
|
if (this._isDrawing) {
|
|
4083
4167
|
if (this._drawType === DrawType.LINE) {
|
|
4084
|
-
this._updateTempLine(
|
|
4168
|
+
this._updateTempLine();
|
|
4085
4169
|
} else if (this._drawType === DrawType.POLYGON) {
|
|
4086
|
-
this._updateTempPolygon(
|
|
4170
|
+
this._updateTempPolygon();
|
|
4087
4171
|
}
|
|
4088
4172
|
}
|
|
4089
4173
|
|
|
4090
4174
|
if (this._startPos) {
|
|
4091
|
-
this._updateRectOrCirclePreview(
|
|
4175
|
+
this._updateRectOrCirclePreview();
|
|
4092
4176
|
}
|
|
4093
4177
|
}
|
|
4094
4178
|
|
|
4179
|
+
_updatePreviewCursor() {
|
|
4180
|
+
// 简化占位:原 _onMove 中没有显式 cursor 处理,保留 hook 以备后用。
|
|
4181
|
+
// 真正的鼠标光标样式由 _onMove 主流程维护,这里无副作用。
|
|
4182
|
+
}
|
|
4183
|
+
|
|
4095
4184
|
_onKeyDown(data) {
|
|
4096
4185
|
// ESC 取消绘制
|
|
4097
4186
|
if (data.key === 'Escape') {
|
|
@@ -4238,7 +4327,7 @@ class DrawTool extends BaseTool {
|
|
|
4238
4327
|
.setScale(0.5)
|
|
4239
4328
|
.setVerticalOrigin(Cesium$c.VerticalOrigin.BOTTOM)
|
|
4240
4329
|
.setHeightReference(Cesium$c.HeightReference.CLAMP_TO_GROUND)
|
|
4241
|
-
.setDisableDepthTestDistance(
|
|
4330
|
+
.setDisableDepthTestDistance(LabelDepthConfig.distance);
|
|
4242
4331
|
|
|
4243
4332
|
// 选择图片来源:自定义 URL 优先,否则使用 SDK 内置 base64 图标
|
|
4244
4333
|
const imageSource = (typeof imgUrl === 'string' && imgUrl.trim() !== '')
|
|
@@ -4347,25 +4436,23 @@ class DrawTool extends BaseTool {
|
|
|
4347
4436
|
}
|
|
4348
4437
|
}
|
|
4349
4438
|
|
|
4350
|
-
_updateTempLine(
|
|
4351
|
-
//
|
|
4352
|
-
|
|
4353
|
-
if (mousePos) {
|
|
4354
|
-
previewPositions.push(mousePos);
|
|
4355
|
-
}
|
|
4356
|
-
|
|
4357
|
-
// 计算 Cartesian3 数组
|
|
4358
|
-
const flatCoords = [];
|
|
4359
|
-
for (const c of previewPositions) {
|
|
4360
|
-
flatCoords.push(c[0], c[1], c[2] || 0);
|
|
4361
|
-
}
|
|
4362
|
-
const cartesians = Cesium$c.Cartesian3.fromDegreesArrayHeights(flatCoords);
|
|
4363
|
-
|
|
4439
|
+
_updateTempLine() {
|
|
4440
|
+
// 第一次创建时建立稳定的 CallbackProperty,回调内部读 this._tempPositions +
|
|
4441
|
+
// this._currentMousePos(与 _updateTempPolygon 同模式),避免每次 move 都重建。
|
|
4364
4442
|
if (!this._previewLine) {
|
|
4365
4443
|
// 首次创建预览线(黑白相间的斑马纹路)
|
|
4366
4444
|
this._previewLine = this.createTempEntity(this.generateId('temp_line'), {
|
|
4367
4445
|
polyline: {
|
|
4368
|
-
positions:
|
|
4446
|
+
positions: new Cesium$c.CallbackProperty(() => {
|
|
4447
|
+
const previewPositions = [...this._tempPositions];
|
|
4448
|
+
if (this._currentMousePos) previewPositions.push(this._currentMousePos);
|
|
4449
|
+
if (previewPositions.length < 2) return [];
|
|
4450
|
+
const flatCoords = [];
|
|
4451
|
+
for (const c of previewPositions) {
|
|
4452
|
+
flatCoords.push(c[0], c[1], c[2] || 0);
|
|
4453
|
+
}
|
|
4454
|
+
return Cesium$c.Cartesian3.fromDegreesArrayHeights(flatCoords);
|
|
4455
|
+
}, false),
|
|
4369
4456
|
material: new Cesium$c.PolylineDashMaterialProperty({
|
|
4370
4457
|
color: Cesium$c.Color.WHITE,
|
|
4371
4458
|
gapColor: Cesium$c.Color.BLACK,
|
|
@@ -4376,12 +4463,6 @@ class DrawTool extends BaseTool {
|
|
|
4376
4463
|
}
|
|
4377
4464
|
});
|
|
4378
4465
|
this._tempEntities.push(this._previewLine);
|
|
4379
|
-
} else {
|
|
4380
|
-
// 直接更新位置属性,避免重建实体
|
|
4381
|
-
// this._previewLine.polyline.positions = cartesians;
|
|
4382
|
-
this._previewLine.polyline.positions = new Cesium$c.CallbackProperty(() => {
|
|
4383
|
-
return cartesians;
|
|
4384
|
-
}, false);
|
|
4385
4466
|
}
|
|
4386
4467
|
}
|
|
4387
4468
|
|
|
@@ -4429,116 +4510,87 @@ class DrawTool extends BaseTool {
|
|
|
4429
4510
|
}
|
|
4430
4511
|
}
|
|
4431
4512
|
|
|
4432
|
-
_updateRectOrCirclePreview(
|
|
4513
|
+
_updateRectOrCirclePreview() {
|
|
4433
4514
|
if (!this._startPos) return;
|
|
4434
4515
|
|
|
4435
4516
|
if (this._drawType === DrawType.RECTANGLE) {
|
|
4436
|
-
this._updateRectPreview(
|
|
4517
|
+
this._updateRectPreview();
|
|
4437
4518
|
} else if (this._drawType === DrawType.CIRCLE) {
|
|
4438
|
-
this._updateCirclePreview(
|
|
4519
|
+
this._updateCirclePreview();
|
|
4439
4520
|
}
|
|
4440
4521
|
}
|
|
4441
4522
|
|
|
4442
|
-
_updateRectPreview(
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
// 计算矩形四个角
|
|
4447
|
-
const positions = [
|
|
4448
|
-
[corner1[0], corner1[1]],
|
|
4449
|
-
[corner2[0], corner1[1]],
|
|
4450
|
-
[corner2[0], corner2[1]],
|
|
4451
|
-
[corner1[0], corner2[1]],
|
|
4452
|
-
[corner1[0], corner1[1]]
|
|
4453
|
-
];
|
|
4454
|
-
|
|
4455
|
-
const flatCoords = [];
|
|
4456
|
-
for (const c of positions) {
|
|
4457
|
-
flatCoords.push(c[0], c[1], 0);
|
|
4458
|
-
}
|
|
4459
|
-
const cartesians = Cesium$c.Cartesian3.fromDegreesArrayHeights(flatCoords);
|
|
4460
|
-
|
|
4523
|
+
_updateRectPreview() {
|
|
4524
|
+
// 第一次创建时建立稳定的 CallbackProperty,回调内部读 this._startPos / _currentMousePos,
|
|
4525
|
+
// 避免每个 mousemove 都 new CallbackProperty + 重绑几何(参见 polygon preview 同模式)。
|
|
4461
4526
|
if (!this._previewRect) {
|
|
4527
|
+
const polylinePositions = new Cesium$c.CallbackProperty(() => this._computeRectCornersFlat(2), false);
|
|
4528
|
+
const polygonHierarchy = new Cesium$c.CallbackProperty(() => {
|
|
4529
|
+
const cartesians = this._computeRectCornersFlat(2);
|
|
4530
|
+
return new Cesium$c.PolygonHierarchy(cartesians);
|
|
4531
|
+
}, false);
|
|
4462
4532
|
this._previewRect = this.createTempEntity(this.generateId('temp_rect'), {
|
|
4463
4533
|
polyline: {
|
|
4464
|
-
positions:
|
|
4534
|
+
positions: polylinePositions,
|
|
4465
4535
|
material: Cesium$c.Color.YELLOW.withAlpha(0.7),
|
|
4466
4536
|
width: 2
|
|
4467
4537
|
},
|
|
4468
4538
|
polygon: {
|
|
4469
|
-
hierarchy:
|
|
4539
|
+
hierarchy: polygonHierarchy,
|
|
4470
4540
|
material: Cesium$c.Color.YELLOW.withAlpha(0.2),
|
|
4471
4541
|
outline: false
|
|
4472
4542
|
}
|
|
4473
4543
|
});
|
|
4474
4544
|
this._previewRect._isPreview = true;
|
|
4475
4545
|
this._tempEntities.push(this._previewRect);
|
|
4476
|
-
} else {
|
|
4477
|
-
// 直接更新位置属性
|
|
4478
|
-
this._previewRect.polyline.positions = new Cesium$c.CallbackProperty(() => {
|
|
4479
|
-
const c1 = this._startPos;
|
|
4480
|
-
const c2 = this._currentMousePos;
|
|
4481
|
-
if (!c1 || !c2) return cartesians;
|
|
4482
|
-
const pos = [
|
|
4483
|
-
[c1[0], c1[1]],
|
|
4484
|
-
[c2[0], c1[1]],
|
|
4485
|
-
[c2[0], c2[1]],
|
|
4486
|
-
[c1[0], c2[1]],
|
|
4487
|
-
[c1[0], c1[1]]
|
|
4488
|
-
];
|
|
4489
|
-
const flat = [];
|
|
4490
|
-
for (const p of pos) {
|
|
4491
|
-
flat.push(p[0], p[1], 0);
|
|
4492
|
-
}
|
|
4493
|
-
return Cesium$c.Cartesian3.fromDegreesArrayHeights(flat);
|
|
4494
|
-
}, false);
|
|
4495
|
-
this._previewRect.polygon.hierarchy = new Cesium$c.CallbackProperty(() => {
|
|
4496
|
-
const c1 = this._startPos;
|
|
4497
|
-
const c2 = this._currentMousePos;
|
|
4498
|
-
if (!c1 || !c2) return new Cesium$c.PolygonHierarchy(cartesians);
|
|
4499
|
-
const pos = [
|
|
4500
|
-
[c1[0], c1[1]],
|
|
4501
|
-
[c2[0], c1[1]],
|
|
4502
|
-
[c2[0], c2[1]],
|
|
4503
|
-
[c1[0], c2[1]],
|
|
4504
|
-
[c1[0], c1[1]]
|
|
4505
|
-
];
|
|
4506
|
-
const flat = [];
|
|
4507
|
-
for (const p of pos) {
|
|
4508
|
-
flat.push(p[0], p[1], 0);
|
|
4509
|
-
}
|
|
4510
|
-
return new Cesium$c.PolygonHierarchy(Cesium$c.Cartesian3.fromDegreesArrayHeights(flat));
|
|
4511
|
-
}, false);
|
|
4512
4546
|
}
|
|
4513
4547
|
}
|
|
4514
4548
|
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4549
|
+
/**
|
|
4550
|
+
* 计算矩形四个角点的 Cartesian3[](含起末闭合点):
|
|
4551
|
+
* [start, (currLon, startLat), curr, (startLon, currLat), start]
|
|
4552
|
+
* 返回数组便于 polyline 与 polygon 共用;调用方负责包装 PolygonHierarchy。
|
|
4553
|
+
*/
|
|
4554
|
+
_computeRectCornersFlat() {
|
|
4555
|
+
const c1 = this._startPos;
|
|
4556
|
+
const c2 = this._currentMousePos;
|
|
4557
|
+
if (!c1 || !c2) {
|
|
4558
|
+
return [Cesium$c.Cartesian3.fromDegrees(0, 0, 0)];
|
|
4559
|
+
}
|
|
4560
|
+
const flat = [
|
|
4561
|
+
c1[0], c1[1], 0,
|
|
4562
|
+
c2[0], c1[1], 0,
|
|
4563
|
+
c2[0], c2[1], 0,
|
|
4564
|
+
c1[0], c2[1], 0,
|
|
4565
|
+
c1[0], c1[1], 0
|
|
4566
|
+
];
|
|
4567
|
+
return Cesium$c.Cartesian3.fromDegreesArrayHeights(flat);
|
|
4568
|
+
}
|
|
4519
4569
|
|
|
4570
|
+
_updateCirclePreview() {
|
|
4571
|
+
// 第一次创建时建立稳定的 CallbackProperty,回调内部读 this._startPos / _currentMousePos,
|
|
4572
|
+
// 避免每个 mousemove 都 new CallbackProperty 并重建几何。
|
|
4573
|
+
const segments = 64;
|
|
4520
4574
|
if (!this._previewCircle) {
|
|
4575
|
+
const hierarchy = new Cesium$c.CallbackProperty(() => {
|
|
4576
|
+
const center = this._startPos;
|
|
4577
|
+
const r = this._calcDistance(center, this._currentMousePos);
|
|
4578
|
+
if (!center || !this._currentMousePos) {
|
|
4579
|
+
return new Cesium$c.PolygonHierarchy([]);
|
|
4580
|
+
}
|
|
4581
|
+
const pos = this._generateCirclePositions(center, r, segments);
|
|
4582
|
+
const flat = pos.flatMap(c => [c[0], c[1], 0]);
|
|
4583
|
+
return new Cesium$c.PolygonHierarchy(Cesium$c.Cartesian3.fromDegreesArrayHeights(flat));
|
|
4584
|
+
}, false);
|
|
4521
4585
|
this._previewCircle = this.createTempEntity(this.generateId('temp_circle'), {
|
|
4522
4586
|
polygon: {
|
|
4523
|
-
hierarchy
|
|
4524
|
-
const positions = this._generateCirclePositions(center, radius, segments);
|
|
4525
|
-
const flat = positions.flatMap(c => [c[0], c[1], 0]);
|
|
4526
|
-
return new Cesium$c.PolygonHierarchy(Cesium$c.Cartesian3.fromDegreesArrayHeights(flat));
|
|
4527
|
-
}, false),
|
|
4587
|
+
hierarchy,
|
|
4528
4588
|
material: Cesium$c.Color.YELLOW.withAlpha(0.2),
|
|
4529
4589
|
outline: false // 地形贴合时不支持 outline,设为 false 避免警告
|
|
4530
4590
|
}
|
|
4531
4591
|
});
|
|
4532
4592
|
this._previewCircle._isPreview = true;
|
|
4533
4593
|
this._tempEntities.push(this._previewCircle);
|
|
4534
|
-
} else {
|
|
4535
|
-
// 直接更新
|
|
4536
|
-
this._previewCircle.polygon.hierarchy = new Cesium$c.CallbackProperty(() => {
|
|
4537
|
-
const r = this._calcDistance(this._startPos, this._currentMousePos);
|
|
4538
|
-
const pos = this._generateCirclePositions(this._startPos, r, 64);
|
|
4539
|
-
const flat = pos.flatMap(c => [c[0], c[1], 0]);
|
|
4540
|
-
return new Cesium$c.PolygonHierarchy(Cesium$c.Cartesian3.fromDegreesArrayHeights(flat));
|
|
4541
|
-
}, false);
|
|
4542
4594
|
}
|
|
4543
4595
|
}
|
|
4544
4596
|
|
|
@@ -4706,37 +4758,39 @@ class DrawTool extends BaseTool {
|
|
|
4706
4758
|
* @param {object} config 标绘配置
|
|
4707
4759
|
* @param {Array} mousePos 当前鼠标位置 [lon, lat, height]
|
|
4708
4760
|
*/
|
|
4709
|
-
_updatePlotPreview(config
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
if (mousePos) {
|
|
4715
|
-
previewPositions.push(mousePos);
|
|
4716
|
-
}
|
|
4717
|
-
|
|
4718
|
-
if (previewPositions.length < config.minPoints) return;
|
|
4719
|
-
|
|
4761
|
+
_updatePlotPreview(config) {
|
|
4762
|
+
// 标绘预览整体思路:
|
|
4763
|
+
// 第一次调用时建立稳定的 CallbackProperty,回调内部读取 this._tempPositions +
|
|
4764
|
+
// this._currentMousePos 重新生成几何。这样 mouve 之间的预览更新只是一帧一次的
|
|
4765
|
+
// 几何重算,没有 CallbackProperty 重建开销。
|
|
4720
4766
|
const factoryName = `create${this._capitalizePlotType(config.plotType)}`;
|
|
4721
4767
|
if (!PlotGeometryUtil[factoryName]) {
|
|
4722
4768
|
console.warn(`未知标绘类型: ${config.plotType}`);
|
|
4723
4769
|
return;
|
|
4724
4770
|
}
|
|
4725
|
-
|
|
4726
|
-
const
|
|
4727
|
-
const positions = PlotGeometryUtil[factoryName](geometryPositions);
|
|
4771
|
+
const isEllipse = config.plotType === PlotGraphicType.ELLIPSE;
|
|
4772
|
+
const normalizeForEllipse = (pts) => isEllipse ? this._normalizeEllipseControlPoints(pts) : pts;
|
|
4728
4773
|
const isLine = config.category === 'line';
|
|
4729
|
-
const
|
|
4730
|
-
for (const c of positions) {
|
|
4731
|
-
flatCoords.push(c[0], c[1], c[2] || 0);
|
|
4732
|
-
}
|
|
4733
|
-
const cartesians = Cesium$c.Cartesian3.fromDegreesArrayHeights(flatCoords);
|
|
4774
|
+
const minPoints = config.minPoints;
|
|
4734
4775
|
|
|
4735
4776
|
if (!this._previewPlot) {
|
|
4777
|
+
// 标绘预览几何工厂:把"读 this._tempPositions + this._currentMousePos 并生成
|
|
4778
|
+
// 标绘几何"的逻辑抽到一个内部方法,由稳定的 CallbackProperty 在每帧调用。
|
|
4779
|
+
// 避免每次 mousemove 都重建 CallbackProperty + 重新计算整个几何。
|
|
4780
|
+
const computePlotGeometry = () => {
|
|
4781
|
+
const dynamicPositions = [...this._tempPositions];
|
|
4782
|
+
if (this._currentMousePos) dynamicPositions.push(this._currentMousePos);
|
|
4783
|
+
if (dynamicPositions.length < minPoints) return null;
|
|
4784
|
+
const pos = PlotGeometryUtil[factoryName](normalizeForEllipse(dynamicPositions));
|
|
4785
|
+
const flat = [];
|
|
4786
|
+
for (const c of pos) flat.push(c[0], c[1], c[2] || 0);
|
|
4787
|
+
return Cesium$c.Cartesian3.fromDegreesArrayHeights(flat);
|
|
4788
|
+
};
|
|
4789
|
+
|
|
4736
4790
|
if (isLine) {
|
|
4737
4791
|
this._previewPlot = this.createTempEntity(this.generateId('temp_plot'), {
|
|
4738
4792
|
polyline: {
|
|
4739
|
-
positions: new Cesium$c.CallbackProperty(() =>
|
|
4793
|
+
positions: new Cesium$c.CallbackProperty(() => computePlotGeometry() || [], false),
|
|
4740
4794
|
material: Cesium$c.Color.YELLOW,
|
|
4741
4795
|
width: 2,
|
|
4742
4796
|
clampToGround: true
|
|
@@ -4745,12 +4799,19 @@ class DrawTool extends BaseTool {
|
|
|
4745
4799
|
} else {
|
|
4746
4800
|
this._previewPlot = this.createTempEntity(this.generateId('temp_plot'), {
|
|
4747
4801
|
polygon: {
|
|
4748
|
-
hierarchy: new Cesium$c.CallbackProperty(() =>
|
|
4802
|
+
hierarchy: new Cesium$c.CallbackProperty(() => {
|
|
4803
|
+
const c = computePlotGeometry();
|
|
4804
|
+
return new Cesium$c.PolygonHierarchy(c || []);
|
|
4805
|
+
}, false),
|
|
4749
4806
|
material: Cesium$c.Color.YELLOW.withAlpha(0.3),
|
|
4750
4807
|
outline: false
|
|
4751
4808
|
},
|
|
4752
4809
|
polyline: {
|
|
4753
|
-
positions: new Cesium$c.CallbackProperty(() =>
|
|
4810
|
+
positions: new Cesium$c.CallbackProperty(() => {
|
|
4811
|
+
const c = computePlotGeometry();
|
|
4812
|
+
if (!c || c.length === 0) return [];
|
|
4813
|
+
return [...c, c[0]];
|
|
4814
|
+
}, false),
|
|
4754
4815
|
material: Cesium$c.Color.YELLOW,
|
|
4755
4816
|
width: 1
|
|
4756
4817
|
}
|
|
@@ -4758,51 +4819,6 @@ class DrawTool extends BaseTool {
|
|
|
4758
4819
|
}
|
|
4759
4820
|
this._previewPlot._isPreview = true;
|
|
4760
4821
|
this._tempEntities.push(this._previewPlot);
|
|
4761
|
-
} else {
|
|
4762
|
-
const self = this;
|
|
4763
|
-
if (isLine) {
|
|
4764
|
-
this._previewPlot.polyline.positions = new Cesium$c.CallbackProperty(() => {
|
|
4765
|
-
const dynamicPositions = [...self._tempPositions];
|
|
4766
|
-
if (self._currentMousePos) {
|
|
4767
|
-
dynamicPositions.push(self._currentMousePos);
|
|
4768
|
-
}
|
|
4769
|
-
if (dynamicPositions.length < config.minPoints) return [];
|
|
4770
|
-
const pos = PlotGeometryUtil[factoryName](normalizeForEllipse(dynamicPositions));
|
|
4771
|
-
const flat = [];
|
|
4772
|
-
for (const c of pos) {
|
|
4773
|
-
flat.push(c[0], c[1], c[2] || 0);
|
|
4774
|
-
}
|
|
4775
|
-
return Cesium$c.Cartesian3.fromDegreesArrayHeights(flat);
|
|
4776
|
-
}, false);
|
|
4777
|
-
} else {
|
|
4778
|
-
this._previewPlot.polygon.hierarchy = new Cesium$c.CallbackProperty(() => {
|
|
4779
|
-
const dynamicPositions = [...self._tempPositions];
|
|
4780
|
-
if (self._currentMousePos) {
|
|
4781
|
-
dynamicPositions.push(self._currentMousePos);
|
|
4782
|
-
}
|
|
4783
|
-
if (dynamicPositions.length < config.minPoints) return new Cesium$c.PolygonHierarchy([]);
|
|
4784
|
-
const pos = PlotGeometryUtil[factoryName](normalizeForEllipse(dynamicPositions));
|
|
4785
|
-
const flat = [];
|
|
4786
|
-
for (const c of pos) {
|
|
4787
|
-
flat.push(c[0], c[1], c[2] || 0);
|
|
4788
|
-
}
|
|
4789
|
-
return new Cesium$c.PolygonHierarchy(Cesium$c.Cartesian3.fromDegreesArrayHeights(flat));
|
|
4790
|
-
}, false);
|
|
4791
|
-
this._previewPlot.polyline.positions = new Cesium$c.CallbackProperty(() => {
|
|
4792
|
-
const dynamicPositions = [...self._tempPositions];
|
|
4793
|
-
if (self._currentMousePos) {
|
|
4794
|
-
dynamicPositions.push(self._currentMousePos);
|
|
4795
|
-
}
|
|
4796
|
-
if (dynamicPositions.length < config.minPoints) return [];
|
|
4797
|
-
const pos = PlotGeometryUtil[factoryName](normalizeForEllipse(dynamicPositions));
|
|
4798
|
-
const flat = [];
|
|
4799
|
-
for (const c of pos) {
|
|
4800
|
-
flat.push(c[0], c[1], c[2] || 0);
|
|
4801
|
-
}
|
|
4802
|
-
const cart = Cesium$c.Cartesian3.fromDegreesArrayHeights(flat);
|
|
4803
|
-
return [...cart, cart[0]];
|
|
4804
|
-
}, false);
|
|
4805
|
-
}
|
|
4806
4822
|
}
|
|
4807
4823
|
}
|
|
4808
4824
|
|
|
@@ -5225,9 +5241,9 @@ class EditTool extends BaseTool {
|
|
|
5225
5241
|
}
|
|
5226
5242
|
}
|
|
5227
5243
|
|
|
5228
|
-
_onMove(
|
|
5229
|
-
//
|
|
5230
|
-
const screenPos =
|
|
5244
|
+
_onMove(_lngLat, _entity, movement) {
|
|
5245
|
+
// BaseTool.registerObserver 现在统一转发 (lngLat, entity, movement)
|
|
5246
|
+
const screenPos = movement.position || movement.endPosition;
|
|
5231
5247
|
if (!screenPos) return;
|
|
5232
5248
|
|
|
5233
5249
|
// 非拖拽时做节流,避免 hover 检测过于频繁
|
|
@@ -5435,7 +5451,7 @@ class EditTool extends BaseTool {
|
|
|
5435
5451
|
pixelSize: 12,
|
|
5436
5452
|
outlineColor: Cesium$b.Color.BLACK,
|
|
5437
5453
|
outlineWidth: 2,
|
|
5438
|
-
disableDepthTestDistance:
|
|
5454
|
+
disableDepthTestDistance: LabelDepthConfig.distance,
|
|
5439
5455
|
heightReference: Cesium$b.HeightReference.CLAMP_TO_GROUND
|
|
5440
5456
|
}
|
|
5441
5457
|
});
|
|
@@ -5483,7 +5499,7 @@ class EditTool extends BaseTool {
|
|
|
5483
5499
|
pixelSize: 14,
|
|
5484
5500
|
outlineColor: Cesium$b.Color.BLUE,
|
|
5485
5501
|
outlineWidth: 2,
|
|
5486
|
-
disableDepthTestDistance:
|
|
5502
|
+
disableDepthTestDistance: LabelDepthConfig.distance,
|
|
5487
5503
|
heightReference: Cesium$b.HeightReference.CLAMP_TO_GROUND
|
|
5488
5504
|
}
|
|
5489
5505
|
});
|
|
@@ -5650,7 +5666,7 @@ class EditTool extends BaseTool {
|
|
|
5650
5666
|
pixelSize: 12,
|
|
5651
5667
|
outlineColor: Cesium$b.Color.BLACK,
|
|
5652
5668
|
outlineWidth: 2,
|
|
5653
|
-
disableDepthTestDistance:
|
|
5669
|
+
disableDepthTestDistance: LabelDepthConfig.distance,
|
|
5654
5670
|
heightReference: Cesium$b.HeightReference.CLAMP_TO_GROUND,
|
|
5655
5671
|
}
|
|
5656
5672
|
});
|
|
@@ -5676,7 +5692,7 @@ class EditTool extends BaseTool {
|
|
|
5676
5692
|
pixelSize: 14,
|
|
5677
5693
|
outlineColor: Cesium$b.Color.BLUE,
|
|
5678
5694
|
outlineWidth: 2,
|
|
5679
|
-
disableDepthTestDistance:
|
|
5695
|
+
disableDepthTestDistance: LabelDepthConfig.distance,
|
|
5680
5696
|
heightReference: Cesium$b.HeightReference.CLAMP_TO_GROUND
|
|
5681
5697
|
}
|
|
5682
5698
|
});
|
|
@@ -5690,7 +5706,7 @@ class EditTool extends BaseTool {
|
|
|
5690
5706
|
pixelSize: 12,
|
|
5691
5707
|
outlineColor: Cesium$b.Color.YELLOW,
|
|
5692
5708
|
outlineWidth: 2,
|
|
5693
|
-
disableDepthTestDistance:
|
|
5709
|
+
disableDepthTestDistance: LabelDepthConfig.distance,
|
|
5694
5710
|
heightReference: Cesium$b.HeightReference.CLAMP_TO_GROUND
|
|
5695
5711
|
}
|
|
5696
5712
|
});
|
|
@@ -5715,7 +5731,7 @@ class EditTool extends BaseTool {
|
|
|
5715
5731
|
pixelSize: 12,
|
|
5716
5732
|
outlineColor: Cesium$b.Color.BLACK,
|
|
5717
5733
|
outlineWidth: 2,
|
|
5718
|
-
disableDepthTestDistance:
|
|
5734
|
+
disableDepthTestDistance: LabelDepthConfig.distance,
|
|
5719
5735
|
// heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
5720
5736
|
}
|
|
5721
5737
|
});
|
|
@@ -5747,7 +5763,7 @@ class EditTool extends BaseTool {
|
|
|
5747
5763
|
pixelSize: 10,
|
|
5748
5764
|
outlineColor: Cesium$b.Color.RED,
|
|
5749
5765
|
outlineWidth: 2,
|
|
5750
|
-
disableDepthTestDistance:
|
|
5766
|
+
disableDepthTestDistance: LabelDepthConfig.distance
|
|
5751
5767
|
}
|
|
5752
5768
|
}
|
|
5753
5769
|
);
|
|
@@ -5815,7 +5831,7 @@ class EditTool extends BaseTool {
|
|
|
5815
5831
|
pixelSize: 14,
|
|
5816
5832
|
outlineColor: Cesium$b.Color.BLUE,
|
|
5817
5833
|
outlineWidth: 2,
|
|
5818
|
-
disableDepthTestDistance:
|
|
5834
|
+
disableDepthTestDistance: LabelDepthConfig.distance,
|
|
5819
5835
|
heightReference: Cesium$b.HeightReference.CLAMP_TO_GROUND
|
|
5820
5836
|
}
|
|
5821
5837
|
});
|
|
@@ -6018,24 +6034,43 @@ class EditTool extends BaseTool {
|
|
|
6018
6034
|
return this._clampPositionToGround(newPos);
|
|
6019
6035
|
});
|
|
6020
6036
|
this._selectedEntity.polyline.positions = newPositions;
|
|
6021
|
-
|
|
6022
|
-
//
|
|
6037
|
+
|
|
6038
|
+
// 修复:更新所有顶点和中点控制点位置
|
|
6023
6039
|
this._editHandles.forEach((handle) => {
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6040
|
+
if (!handle.id || handle.id.includes('center')) return;
|
|
6041
|
+
// 顶点 handle:__edit_handle_<index>
|
|
6042
|
+
const vertexMatch = handle.id.match(/__edit_handle_(\d+)$/);
|
|
6043
|
+
if (vertexMatch) {
|
|
6044
|
+
const index = parseInt(vertexMatch[1], 10);
|
|
6045
|
+
if (newPositions[index]) {
|
|
6046
|
+
const posProp = handle.position;
|
|
6047
|
+
if (posProp && typeof posProp.setValue === 'function') {
|
|
6048
|
+
posProp.setValue(newPositions[index]);
|
|
6049
|
+
} else {
|
|
6050
|
+
handle.position = new Cesium$b.ConstantPositionProperty(newPositions[index]);
|
|
6051
|
+
}
|
|
6052
|
+
}
|
|
6027
6053
|
return;
|
|
6028
6054
|
}
|
|
6029
|
-
//
|
|
6030
|
-
const
|
|
6031
|
-
if (
|
|
6032
|
-
const
|
|
6033
|
-
|
|
6034
|
-
|
|
6055
|
+
// 中点 handle:__edit_handle_mid_<li>_<ri>
|
|
6056
|
+
const midMatch = handle.id.match(/__edit_handle_mid_(\d+)_(\d+)/);
|
|
6057
|
+
if (midMatch) {
|
|
6058
|
+
const li = parseInt(midMatch[1], 10);
|
|
6059
|
+
const ri = parseInt(midMatch[2], 10);
|
|
6060
|
+
const left = newPositions[li];
|
|
6061
|
+
const right = newPositions[ri];
|
|
6062
|
+
if (!left || !right) return;
|
|
6063
|
+
const midCart = Cesium$b.Cartesian3.midpoint(left, right, new Cesium$b.Cartesian3());
|
|
6064
|
+
const clamped = this._clampPositionToGround(midCart);
|
|
6065
|
+
const posProp = handle.position;
|
|
6066
|
+
if (posProp && typeof posProp.setValue === 'function') {
|
|
6067
|
+
posProp.setValue(clamped);
|
|
6068
|
+
} else {
|
|
6069
|
+
handle.position = new Cesium$b.ConstantPositionProperty(clamped);
|
|
6035
6070
|
}
|
|
6036
6071
|
}
|
|
6037
6072
|
});
|
|
6038
|
-
|
|
6073
|
+
|
|
6039
6074
|
// 更新原始位置缓存
|
|
6040
6075
|
this._originalPositions = newPositions;
|
|
6041
6076
|
} else if (Cesium$b.defined(this._selectedEntity.polygon)) {
|
|
@@ -6086,18 +6121,40 @@ class EditTool extends BaseTool {
|
|
|
6086
6121
|
return this._clampPositionToGround(newPos);
|
|
6087
6122
|
});
|
|
6088
6123
|
|
|
6089
|
-
//
|
|
6124
|
+
// 修复:更新顶点和中点控制点位置。
|
|
6125
|
+
// 注意:正则 `/__edit_handle_(\d+)$/` 只匹配顶点 handle;
|
|
6126
|
+
// 中点 handle 的 ID 是 `__edit_handle_mid_<li>_<ri>`,需要单独处理。
|
|
6090
6127
|
this._editHandles.forEach((handle) => {
|
|
6091
|
-
|
|
6092
|
-
|
|
6128
|
+
if (!handle.id || handle.id.includes('center')) return;
|
|
6129
|
+
// 顶点 handle:__edit_handle_<index>
|
|
6130
|
+
const vertexMatch = handle.id.match(/__edit_handle_(\d+)$/);
|
|
6131
|
+
if (vertexMatch) {
|
|
6132
|
+
const index = parseInt(vertexMatch[1], 10);
|
|
6133
|
+
if (newPositions[index]) {
|
|
6134
|
+
const posProp = handle.position;
|
|
6135
|
+
if (posProp && typeof posProp.setValue === 'function') {
|
|
6136
|
+
posProp.setValue(newPositions[index]);
|
|
6137
|
+
} else {
|
|
6138
|
+
handle.position = new Cesium$b.ConstantPositionProperty(newPositions[index]);
|
|
6139
|
+
}
|
|
6140
|
+
}
|
|
6093
6141
|
return;
|
|
6094
6142
|
}
|
|
6095
|
-
//
|
|
6096
|
-
const
|
|
6097
|
-
if (
|
|
6098
|
-
const
|
|
6099
|
-
|
|
6100
|
-
|
|
6143
|
+
// 中点 handle:__edit_handle_mid_<li>_<ri>
|
|
6144
|
+
const midMatch = handle.id.match(/__edit_handle_mid_(\d+)_(\d+)/);
|
|
6145
|
+
if (midMatch) {
|
|
6146
|
+
const li = parseInt(midMatch[1], 10);
|
|
6147
|
+
const ri = parseInt(midMatch[2], 10);
|
|
6148
|
+
const left = newPositions[li];
|
|
6149
|
+
const right = newPositions[ri];
|
|
6150
|
+
if (!left || !right) return;
|
|
6151
|
+
const midCart = Cesium$b.Cartesian3.midpoint(left, right, new Cesium$b.Cartesian3());
|
|
6152
|
+
const clamped = this._clampPositionToGround(midCart);
|
|
6153
|
+
const posProp = handle.position;
|
|
6154
|
+
if (posProp && typeof posProp.setValue === 'function') {
|
|
6155
|
+
posProp.setValue(clamped);
|
|
6156
|
+
} else {
|
|
6157
|
+
handle.position = new Cesium$b.ConstantPositionProperty(clamped);
|
|
6101
6158
|
}
|
|
6102
6159
|
}
|
|
6103
6160
|
});
|
|
@@ -6658,7 +6715,14 @@ class EditTool extends BaseTool {
|
|
|
6658
6715
|
// 多边形顶点拖动:通过 CallbackProperty 让 Cesium 直接从 handle 位置读,
|
|
6659
6716
|
// 这里只需要更新 handle.position 即可,几何会跟着弯折,
|
|
6660
6717
|
// 远比每帧 newPositions + new PolygonHierarchy 顺滑。
|
|
6661
|
-
|
|
6718
|
+
// 复用现有 Property 实例并 setValue:避免替换 Property 引用导致
|
|
6719
|
+
// Cesium 某些情况下不重新渲染。
|
|
6720
|
+
const dragPosProp = this._dragHandle.position;
|
|
6721
|
+
if (dragPosProp && typeof dragPosProp.setValue === 'function') {
|
|
6722
|
+
dragPosProp.setValue(newCartesian);
|
|
6723
|
+
} else {
|
|
6724
|
+
this._dragHandle.position = new Cesium$b.ConstantPositionProperty(newCartesian);
|
|
6725
|
+
}
|
|
6662
6726
|
|
|
6663
6727
|
// 修复:多边形编辑后重新计算并更新中心控制点位置
|
|
6664
6728
|
this._updateCenterHandlePosition();
|
|
@@ -6701,7 +6765,14 @@ class EditTool extends BaseTool {
|
|
|
6701
6765
|
if (!left || !right) return;
|
|
6702
6766
|
const midCart = Cesium$b.Cartesian3.midpoint(left, right, new Cesium$b.Cartesian3());
|
|
6703
6767
|
const clamped = this._clampPositionToGround(midCart);
|
|
6704
|
-
|
|
6768
|
+
// 复用现有 Property 实例并 setValue:避免替换 Property 引用导致
|
|
6769
|
+
// Cesium 某些情况下不重新渲染。
|
|
6770
|
+
const posProp = handle.position;
|
|
6771
|
+
if (posProp && typeof posProp.setValue === 'function') {
|
|
6772
|
+
posProp.setValue(clamped);
|
|
6773
|
+
} else {
|
|
6774
|
+
handle.position = new Cesium$b.ConstantPositionProperty(clamped);
|
|
6775
|
+
}
|
|
6705
6776
|
});
|
|
6706
6777
|
}
|
|
6707
6778
|
|
|
@@ -6924,14 +6995,15 @@ class SelectTool extends BaseTool {
|
|
|
6924
6995
|
}
|
|
6925
6996
|
}
|
|
6926
6997
|
|
|
6927
|
-
_onMove(
|
|
6998
|
+
_onMove(lngLat, _entity, movement) {
|
|
6928
6999
|
// mouse:move passes movement object from BaseTool
|
|
6929
|
-
const screenPos =
|
|
7000
|
+
const screenPos = movement.position || movement.endPosition;
|
|
6930
7001
|
if (!screenPos) return;
|
|
6931
7002
|
|
|
6932
7003
|
if (!this._isSelecting || !this._startPos) return;
|
|
6933
7004
|
|
|
6934
|
-
|
|
7005
|
+
// 优先使用 EventModule 已计算的 lngLat(避免重复 scene.pickPosition)。
|
|
7006
|
+
const lonLat = lngLat || this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
|
|
6935
7007
|
if (!lonLat) return;
|
|
6936
7008
|
|
|
6937
7009
|
this._updateSelectionRectPreview(lonLat);
|
|
@@ -7423,17 +7495,18 @@ class DeleteTool extends BaseTool {
|
|
|
7423
7495
|
}
|
|
7424
7496
|
}
|
|
7425
7497
|
|
|
7426
|
-
_onMove(
|
|
7427
|
-
const screenPos =
|
|
7498
|
+
_onMove(_lngLat, pickedEntity, movement) {
|
|
7499
|
+
const screenPos = movement.position || movement.endPosition;
|
|
7428
7500
|
if (!screenPos) return;
|
|
7429
7501
|
|
|
7430
|
-
|
|
7431
|
-
|
|
7502
|
+
// 优先使用 EventModule 已计算的 pickedEntity(避免重复 scene.pick)。
|
|
7503
|
+
// EventModule 已经做过 pickedEntity.id(Pick 对象 → Entity 实例)取一次,
|
|
7504
|
+
// 这里直接取 Entity.id(字符串)即可。
|
|
7432
7505
|
let hoveredId = null;
|
|
7433
7506
|
|
|
7434
|
-
if (Cesium$9.defined(
|
|
7435
|
-
const entityId =
|
|
7436
|
-
if (!entityId.startsWith('__temp_') && !entityId.startsWith('__edit_handle_')) {
|
|
7507
|
+
if (Cesium$9.defined(pickedEntity) && Cesium$9.defined(pickedEntity.id)) {
|
|
7508
|
+
const entityId = pickedEntity.id;
|
|
7509
|
+
if (typeof entityId === 'string' && !entityId.startsWith('__temp_') && !entityId.startsWith('__edit_handle_')) {
|
|
7437
7510
|
hoveredId = entityId;
|
|
7438
7511
|
}
|
|
7439
7512
|
}
|
|
@@ -7716,6 +7789,24 @@ const LABEL_BORDER_COLOR = '#FB120E';
|
|
|
7716
7789
|
const LABEL_BACKGROUND_COLOR = '#ffffff';
|
|
7717
7790
|
const LABEL_TEXT_COLOR = '#000000';
|
|
7718
7791
|
|
|
7792
|
+
// 模块级 measure canvas 单例:测量标签每次重绘文字宽度时复用,避免
|
|
7793
|
+
// 每次都 document.createElement + getContext(之前在 _createLabelImage 中是热路径)。
|
|
7794
|
+
// 延迟到首次调用时再创建:jsdom 等环境顶层 document.createElement('canvas').getContext 不可用。
|
|
7795
|
+
let _measureCanvas = null;
|
|
7796
|
+
let _measureCtx = null;
|
|
7797
|
+
function _measureTextWidth(text, font) {
|
|
7798
|
+
if (!_measureCanvas) {
|
|
7799
|
+
try {
|
|
7800
|
+
_measureCanvas = document.createElement('canvas');
|
|
7801
|
+
_measureCtx = _measureCanvas.getContext('2d');
|
|
7802
|
+
} catch (e) {
|
|
7803
|
+
return Math.max(1, text.length * 8);
|
|
7804
|
+
}
|
|
7805
|
+
}
|
|
7806
|
+
_measureCtx.font = font;
|
|
7807
|
+
return Math.max(1, Math.ceil(_measureCtx.measureText(text).width));
|
|
7808
|
+
}
|
|
7809
|
+
|
|
7719
7810
|
/**
|
|
7720
7811
|
* 测量类型枚举
|
|
7721
7812
|
*/
|
|
@@ -7903,8 +7994,8 @@ class MeasureTool extends BaseTool {
|
|
|
7903
7994
|
this._updateMeasurement();
|
|
7904
7995
|
}
|
|
7905
7996
|
|
|
7906
|
-
_onMove(
|
|
7907
|
-
const screenPos =
|
|
7997
|
+
_onMove(lngLat, entity, movement) {
|
|
7998
|
+
const screenPos = movement.position || movement.endPosition;
|
|
7908
7999
|
if (!screenPos) return;
|
|
7909
8000
|
|
|
7910
8001
|
// 拖拽顶点中:节流更新该顶点位置与对应几何/标注
|
|
@@ -7913,7 +8004,8 @@ class MeasureTool extends BaseTool {
|
|
|
7913
8004
|
if (now - this._lastDragMoveTime < this._dragThrottleMs) return;
|
|
7914
8005
|
this._lastDragMoveTime = now;
|
|
7915
8006
|
|
|
7916
|
-
|
|
8007
|
+
// 拖动路径优先用 EventModule 已计算的 lngLat;否则 fallback。
|
|
8008
|
+
const lonLat = lngLat || this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
|
|
7917
8009
|
if (lonLat) {
|
|
7918
8010
|
this._updateVertexDuringDrag(this._dragVertexIndex, lonLat, this._dragResult);
|
|
7919
8011
|
|
|
@@ -7927,25 +8019,27 @@ class MeasureTool extends BaseTool {
|
|
|
7927
8019
|
return;
|
|
7928
8020
|
}
|
|
7929
8021
|
|
|
7930
|
-
// 非拖拽:检测悬停,更新光标(与 EditTool
|
|
8022
|
+
// 非拖拽:检测悬停,更新光标(与 EditTool 风格一致)。优先用 EventModule 给的 entity。
|
|
7931
8023
|
let isOverFinishedVertex = false;
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
|
|
7936
|
-
|
|
8024
|
+
if (Cesium$7.defined(entity)) {
|
|
8025
|
+
try {
|
|
8026
|
+
// EventModule 传过来的是 Cesium Entity 实例(不是 Pick 对象),直接用于命中判定
|
|
8027
|
+
isOverFinishedVertex = !!this._findFinishedPointHit(entity);
|
|
8028
|
+
} catch (e) {
|
|
8029
|
+
// ignore
|
|
7937
8030
|
}
|
|
7938
|
-
} catch (e) {
|
|
7939
|
-
// ignore
|
|
7940
8031
|
}
|
|
7941
8032
|
// 悬停在角点上:CSS `grab`(开放的手)暗示"可拖动";无浏览器支持时回退 `default`
|
|
7942
8033
|
this._setCanvasCursor(isOverFinishedVertex ? 'grab' : 'default');
|
|
7943
8034
|
|
|
7944
|
-
const lonLat = this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
|
|
8035
|
+
const lonLat = lngLat || this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
|
|
7945
8036
|
if (!lonLat) return;
|
|
7946
8037
|
this._mousePos = lonLat;
|
|
8038
|
+
|
|
8039
|
+
// 非拖拽预览路径:用 rAF 合并 mousemove,与 render 帧同步,避免全球视角下
|
|
8040
|
+
// 多次 mousemove 之间重复重建几何/canvas。
|
|
7947
8041
|
if (this._isMeasuring) {
|
|
7948
|
-
this._updateMeasurement();
|
|
8042
|
+
this._scheduleMoveWork(() => this._updateMeasurement());
|
|
7949
8043
|
}
|
|
7950
8044
|
}
|
|
7951
8045
|
|
|
@@ -8725,7 +8819,7 @@ class MeasureTool extends BaseTool {
|
|
|
8725
8819
|
verticalOrigin: Cesium$7.VerticalOrigin.BOTTOM,
|
|
8726
8820
|
horizontalOrigin: Cesium$7.HorizontalOrigin.CENTER,
|
|
8727
8821
|
pixelOffset: new Cesium$7.Cartesian2(0, -6),
|
|
8728
|
-
disableDepthTestDistance:
|
|
8822
|
+
disableDepthTestDistance: LabelDepthConfig.distance
|
|
8729
8823
|
}
|
|
8730
8824
|
});
|
|
8731
8825
|
entity._lastText = text;
|
|
@@ -8751,11 +8845,8 @@ class MeasureTool extends BaseTool {
|
|
|
8751
8845
|
const triangleHeight = 8;
|
|
8752
8846
|
const rectHeight = 20;
|
|
8753
8847
|
|
|
8754
|
-
//
|
|
8755
|
-
const
|
|
8756
|
-
const measureCtx = measureCanvas.getContext('2d');
|
|
8757
|
-
measureCtx.font = font;
|
|
8758
|
-
const textWidth = Math.max(1, Math.ceil(measureCtx.measureText(text).width));
|
|
8848
|
+
// 复用模块级 measure canvas 单例,避免每次 mousemove 都 document.createElement('canvas')
|
|
8849
|
+
const textWidth = _measureTextWidth(text, font);
|
|
8759
8850
|
const rectWidth = textWidth + paddingX * 2;
|
|
8760
8851
|
const width = rectWidth + borderWidth * 2;
|
|
8761
8852
|
const height = rectHeight + triangleHeight + borderWidth * 2;
|
|
@@ -8877,7 +8968,7 @@ class MeasureTool extends BaseTool {
|
|
|
8877
8968
|
style: Cesium$7.LabelStyle.FILL_AND_OUTLINE,
|
|
8878
8969
|
verticalOrigin: Cesium$7.VerticalOrigin.BOTTOM,
|
|
8879
8970
|
horizontalOrigin: Cesium$7.HorizontalOrigin.CENTER,
|
|
8880
|
-
disableDepthTestDistance:
|
|
8971
|
+
disableDepthTestDistance: LabelDepthConfig.distance,
|
|
8881
8972
|
pixelOffset: new Cesium$7.Cartesian2(0, -10)
|
|
8882
8973
|
}
|
|
8883
8974
|
});
|
|
@@ -8892,7 +8983,7 @@ class MeasureTool extends BaseTool {
|
|
|
8892
8983
|
pixelSize: 8,
|
|
8893
8984
|
outlineColor: Cesium$7.Color.fromCssColorString(MEASURE_POINT_OUTLINE_COLOR),
|
|
8894
8985
|
outlineWidth: 1,
|
|
8895
|
-
disableDepthTestDistance:
|
|
8986
|
+
disableDepthTestDistance: LabelDepthConfig.distance
|
|
8896
8987
|
}
|
|
8897
8988
|
});
|
|
8898
8989
|
this._pointEntities.push(point);
|
|
@@ -10054,9 +10145,15 @@ class Zoom extends BaseControl {
|
|
|
10054
10145
|
const camera = this._viewer.camera;
|
|
10055
10146
|
// 以双击位置拾取到的地表点为缩放中心;拾取不到退回相机正下方
|
|
10056
10147
|
let cartographic = camera.positionCartographic;
|
|
10148
|
+
// 锚点缩放需要"点击像素的视线方向":保持这条视线不变,
|
|
10149
|
+
// 锚点缩放后才仍投影在光标下方(相机中轴方向只在点击点恰为中心时成立)
|
|
10150
|
+
let rayDirection = camera.direction;
|
|
10057
10151
|
if (movement?.position && this._viewer.scene?.globe) {
|
|
10058
10152
|
const ray = camera.getPickRay(movement.position);
|
|
10059
10153
|
const cartesian = ray ? this._viewer.scene.globe.pick(ray, this._viewer.scene) : null;
|
|
10154
|
+
if (ray) {
|
|
10155
|
+
rayDirection = ray.direction;
|
|
10156
|
+
}
|
|
10060
10157
|
if (cartesian) {
|
|
10061
10158
|
cartographic = Cesium$5.Cartographic.fromCartesian(cartesian);
|
|
10062
10159
|
}
|
|
@@ -10064,7 +10161,89 @@ class Zoom extends BaseControl {
|
|
|
10064
10161
|
|
|
10065
10162
|
const currentLevel = this._pendingLevel ?? this._getZoomLevel();
|
|
10066
10163
|
const targetLevel = Math.max(0, Math.min(24, currentLevel + levelDelta));
|
|
10067
|
-
this.
|
|
10164
|
+
this._flyToLevelKeepScreenPoint(targetLevel, cartographic, rayDirection);
|
|
10165
|
+
}
|
|
10166
|
+
|
|
10167
|
+
/**
|
|
10168
|
+
* 飞到指定层级,且保持 cartographic 对应的地面点在原屏幕位置(锚点缩放)。
|
|
10169
|
+
*
|
|
10170
|
+
* 与 _flyToLevel(以点为中心)不同:这里把相机沿"点击像素的视线方向"反方向
|
|
10171
|
+
* 退到目标高度——同一像素的视线方向只取决于相机姿态、与位置无关,因此相机
|
|
10172
|
+
* 沿该方向移动后,锚点仍投影在双击位置(光标下方),而不是被搬到屏幕中心。
|
|
10173
|
+
* 视线几乎水平(点击靠近地平线/天空)时退化为居中模式。
|
|
10174
|
+
*
|
|
10175
|
+
* @param {number} targetLevel 目标层级
|
|
10176
|
+
* @param {Cesium.Cartographic} cartographic 锚点(双击拾取的地面点)
|
|
10177
|
+
* @param {Cesium.Cartesian3} rayDirection 点击像素的视线方向(ECEF 单位向量)
|
|
10178
|
+
*/
|
|
10179
|
+
_flyToLevelKeepScreenPoint(targetLevel, cartographic, rayDirection) {
|
|
10180
|
+
const camera = this._viewer.camera;
|
|
10181
|
+
const targetHeight = this._getHeightByZoomLevel(targetLevel);
|
|
10182
|
+
const pitch = camera.pitch;
|
|
10183
|
+
|
|
10184
|
+
let destination = null;
|
|
10185
|
+
// 相机俯角至少 ~60° 才做锚点缩放;更平时后退距离发散,观感也差,退化为中心模式
|
|
10186
|
+
const minPitch = Cesium$5.Math.toRadians(-60);
|
|
10187
|
+
if (pitch <= minPitch && rayDirection) {
|
|
10188
|
+
// 锚点处的本地"上"方向(ECEF)
|
|
10189
|
+
const cosLat = Math.cos(cartographic.latitude);
|
|
10190
|
+
const up = new Cesium$5.Cartesian3(
|
|
10191
|
+
cosLat * Math.cos(cartographic.longitude),
|
|
10192
|
+
cosLat * Math.sin(cartographic.longitude),
|
|
10193
|
+
Math.sin(cartographic.latitude)
|
|
10194
|
+
);
|
|
10195
|
+
// 视线向下的分量
|
|
10196
|
+
const rayUp = Cesium$5.Cartesian3.dot(rayDirection, up);
|
|
10197
|
+
// 相机沿视线到锚点的距离:垂直落差 / 视线向下分量
|
|
10198
|
+
const s = (targetHeight - cartographic.height) / (-rayUp);
|
|
10199
|
+
if (rayUp < -0.05 && Number.isFinite(s) && s > 0) {
|
|
10200
|
+
const anchor = Cesium$5.Cartesian3.fromRadians(
|
|
10201
|
+
cartographic.longitude,
|
|
10202
|
+
cartographic.latitude,
|
|
10203
|
+
cartographic.height
|
|
10204
|
+
);
|
|
10205
|
+
destination = Cesium$5.Cartesian3.add(
|
|
10206
|
+
anchor,
|
|
10207
|
+
Cesium$5.Cartesian3.multiplyByScalar(rayDirection, -s, new Cesium$5.Cartesian3()),
|
|
10208
|
+
new Cesium$5.Cartesian3()
|
|
10209
|
+
);
|
|
10210
|
+
}
|
|
10211
|
+
}
|
|
10212
|
+
|
|
10213
|
+
if (!destination) {
|
|
10214
|
+
destination = Cesium$5.Cartesian3.fromRadians(
|
|
10215
|
+
cartographic.longitude,
|
|
10216
|
+
cartographic.latitude,
|
|
10217
|
+
targetHeight
|
|
10218
|
+
);
|
|
10219
|
+
}
|
|
10220
|
+
this._flyToDestination(targetLevel, destination);
|
|
10221
|
+
}
|
|
10222
|
+
|
|
10223
|
+
/**
|
|
10224
|
+
* 飞到指定层级的目的地(目的地构造交给调用方),并记录 _pendingLevel
|
|
10225
|
+
* @param {number} targetLevel 目标层级
|
|
10226
|
+
* @param {Cesium.Cartesian3} destination 相机最终位置
|
|
10227
|
+
*/
|
|
10228
|
+
_flyToDestination(targetLevel, destination) {
|
|
10229
|
+
const camera = this._viewer.camera;
|
|
10230
|
+
|
|
10231
|
+
this._pendingLevel = targetLevel;
|
|
10232
|
+
camera.flyTo({
|
|
10233
|
+
destination,
|
|
10234
|
+
orientation: {
|
|
10235
|
+
heading: camera.heading,
|
|
10236
|
+
pitch: camera.pitch,
|
|
10237
|
+
roll: camera.roll
|
|
10238
|
+
},
|
|
10239
|
+
duration: this._duration,
|
|
10240
|
+
complete: () => {
|
|
10241
|
+
if (this._pendingLevel === targetLevel) this._pendingLevel = null;
|
|
10242
|
+
},
|
|
10243
|
+
cancel: () => {
|
|
10244
|
+
if (this._pendingLevel === targetLevel) this._pendingLevel = null;
|
|
10245
|
+
}
|
|
10246
|
+
});
|
|
10068
10247
|
}
|
|
10069
10248
|
|
|
10070
10249
|
_zoomIn() {
|
|
@@ -10086,34 +10265,19 @@ class Zoom extends BaseControl {
|
|
|
10086
10265
|
}
|
|
10087
10266
|
|
|
10088
10267
|
/**
|
|
10089
|
-
*
|
|
10268
|
+
* 飞到指定层级(以给定经纬度为正下方中心),并记录 _pendingLevel
|
|
10090
10269
|
* @param {number} targetLevel 目标层级
|
|
10091
10270
|
* @param {Cesium.Cartographic} cartographic 目的地中心
|
|
10092
10271
|
*/
|
|
10093
10272
|
_flyToLevel(targetLevel, cartographic) {
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
this._pendingLevel = targetLevel;
|
|
10098
|
-
camera.flyTo({
|
|
10099
|
-
destination: Cesium$5.Cartesian3.fromRadians(
|
|
10273
|
+
this._flyToDestination(
|
|
10274
|
+
targetLevel,
|
|
10275
|
+
Cesium$5.Cartesian3.fromRadians(
|
|
10100
10276
|
cartographic.longitude,
|
|
10101
10277
|
cartographic.latitude,
|
|
10102
|
-
|
|
10103
|
-
)
|
|
10104
|
-
|
|
10105
|
-
heading: camera.heading,
|
|
10106
|
-
pitch: camera.pitch,
|
|
10107
|
-
roll: camera.roll
|
|
10108
|
-
},
|
|
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
|
-
}
|
|
10116
|
-
});
|
|
10278
|
+
this._getHeightByZoomLevel(targetLevel)
|
|
10279
|
+
)
|
|
10280
|
+
);
|
|
10117
10281
|
}
|
|
10118
10282
|
|
|
10119
10283
|
_getZoomLevel() {
|
|
@@ -11888,6 +12052,7 @@ const xs3d = {
|
|
|
11888
12052
|
Zoom,
|
|
11889
12053
|
Compass,
|
|
11890
12054
|
DistanceLegend,
|
|
12055
|
+
LabelDepthConfig,
|
|
11891
12056
|
// 导出工具枚举
|
|
11892
12057
|
DrawType,
|
|
11893
12058
|
EditMode,
|