cesium-xs-sdk 1.0.8 → 1.0.9
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 +830 -673
- package/dist/cesium-xs-sdk.cjs.js.map +1 -1
- package/dist/cesium-xs-sdk.esm.js +830 -673
- 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 +135 -135
- package/src/index.d.ts +6 -0
- package/src/modules/GraphicModule.js +157 -0
- package/src/modules/tools/MeasureTool.js +514 -514
- package/src/vue.d.ts +18 -18
- package/src/vue.js +70 -70
|
@@ -3047,6 +3047,9 @@ class GraphicModule {
|
|
|
3047
3047
|
return false;
|
|
3048
3048
|
}
|
|
3049
3049
|
|
|
3050
|
+
// 清理可能存在的 outline 等关联 entity
|
|
3051
|
+
this.removeOutline(graphicId);
|
|
3052
|
+
|
|
3050
3053
|
const entity = this.graphicMap.get(graphicId);
|
|
3051
3054
|
this.viewer.entities.remove(entity);
|
|
3052
3055
|
this.graphicMap.delete(graphicId);
|
|
@@ -3062,6 +3065,160 @@ class GraphicModule {
|
|
|
3062
3065
|
getGraphic(graphicId) {
|
|
3063
3066
|
return this.graphicMap.get(graphicId);
|
|
3064
3067
|
}
|
|
3068
|
+
|
|
3069
|
+
/**
|
|
3070
|
+
* 从 entity 中提取顶点坐标
|
|
3071
|
+
* 支持 point / polyline / polygon
|
|
3072
|
+
* @private
|
|
3073
|
+
* @param {Cesium.Entity} entity 图元实体
|
|
3074
|
+
* @returns {Cesium.Cartesian3[]} 顶点坐标数组
|
|
3075
|
+
*/
|
|
3076
|
+
_getEntityPositions(entity) {
|
|
3077
|
+
const getValue = (prop) => {
|
|
3078
|
+
if (prop == null) return undefined;
|
|
3079
|
+
return typeof prop.getValue === 'function' ? prop.getValue(Cesium$e.JulianDate.now()) : prop;
|
|
3080
|
+
};
|
|
3081
|
+
|
|
3082
|
+
// 优先按 geometry 类型取顶点,避免 polygon/polyline 也带 position 时只拿到中心点
|
|
3083
|
+
if (entity.polygon?.hierarchy) {
|
|
3084
|
+
const hierarchy = getValue(entity.polygon.hierarchy);
|
|
3085
|
+
if (Array.isArray(hierarchy)) return hierarchy;
|
|
3086
|
+
if (Array.isArray(hierarchy?.positions)) return hierarchy.positions;
|
|
3087
|
+
return [];
|
|
3088
|
+
}
|
|
3089
|
+
if (entity.polyline?.positions) {
|
|
3090
|
+
return getValue(entity.polyline.positions) ?? [];
|
|
3091
|
+
}
|
|
3092
|
+
if (entity.position) {
|
|
3093
|
+
const p = getValue(entity.position);
|
|
3094
|
+
return p ? [p] : [];
|
|
3095
|
+
}
|
|
3096
|
+
return [];
|
|
3097
|
+
}
|
|
3098
|
+
|
|
3099
|
+
/**
|
|
3100
|
+
* 获取图元顶点坐标
|
|
3101
|
+
* @param {string|Cesium.Entity} graphicIdOrEntity 图元ID或实体
|
|
3102
|
+
* @returns {Cesium.Cartesian3[]} 顶点坐标数组
|
|
3103
|
+
*/
|
|
3104
|
+
getPositions(graphicIdOrEntity) {
|
|
3105
|
+
const entity = typeof graphicIdOrEntity === 'string'
|
|
3106
|
+
? this.getGraphic(graphicIdOrEntity)
|
|
3107
|
+
: graphicIdOrEntity;
|
|
3108
|
+
return entity ? this._getEntityPositions(entity) : [];
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
/**
|
|
3112
|
+
* 获取图元包围球
|
|
3113
|
+
* @param {string|Cesium.Entity} graphicIdOrEntity 图元ID或实体
|
|
3114
|
+
* @returns {Cesium.BoundingSphere|null} 包围球
|
|
3115
|
+
*/
|
|
3116
|
+
getBoundingSphere(graphicIdOrEntity) {
|
|
3117
|
+
const positions = this.getPositions(graphicIdOrEntity);
|
|
3118
|
+
if (!positions.length) return null;
|
|
3119
|
+
|
|
3120
|
+
const sphere = Cesium$e.BoundingSphere.fromPoints(positions);
|
|
3121
|
+
// 点图元只有单个坐标,radius 为 0,给一个最小可视半径避免相机钻进点里
|
|
3122
|
+
if (positions.length === 1 && sphere.radius === 0) {
|
|
3123
|
+
sphere.radius = 5000;
|
|
3124
|
+
}
|
|
3125
|
+
return sphere;
|
|
3126
|
+
}
|
|
3127
|
+
|
|
3128
|
+
/**
|
|
3129
|
+
* 飞行定位到图元
|
|
3130
|
+
* @param {string|Cesium.Entity} graphicIdOrEntity 图元ID或实体
|
|
3131
|
+
* @param {object} options 配置项 { pitch?, padding?, duration? }
|
|
3132
|
+
* @returns {Promise<boolean>}
|
|
3133
|
+
*/
|
|
3134
|
+
flyTo(graphicIdOrEntity, options = {}) {
|
|
3135
|
+
const entity = typeof graphicIdOrEntity === 'string'
|
|
3136
|
+
? this.getGraphic(graphicIdOrEntity)
|
|
3137
|
+
: graphicIdOrEntity;
|
|
3138
|
+
if (!entity || !this.viewer) return Promise.resolve(false);
|
|
3139
|
+
|
|
3140
|
+
const sphere = this.getBoundingSphere(entity);
|
|
3141
|
+
if (!sphere) return Promise.resolve(false);
|
|
3142
|
+
|
|
3143
|
+
const pitch = options.pitch ?? -Cesium$e.Math.PI_OVER_TWO;
|
|
3144
|
+
const padding = options.padding ?? 2;
|
|
3145
|
+
const fovy = this.viewer.camera.frustum.fovy;
|
|
3146
|
+
const range = (sphere.radius / Math.tan(fovy / 2)) * padding;
|
|
3147
|
+
|
|
3148
|
+
return this.viewer.camera.flyToBoundingSphere(sphere, {
|
|
3149
|
+
duration: options.duration ?? 1.5,
|
|
3150
|
+
offset: new Cesium$e.HeadingPitchRange(0, pitch, range),
|
|
3151
|
+
}).then(() => true).catch((err) => {
|
|
3152
|
+
console.error('图元定位失败', err);
|
|
3153
|
+
return false;
|
|
3154
|
+
});
|
|
3155
|
+
}
|
|
3156
|
+
|
|
3157
|
+
/**
|
|
3158
|
+
* 瞬间定位到图元(无动画)
|
|
3159
|
+
* @param {string|Cesium.Entity} graphicIdOrEntity 图元ID或实体
|
|
3160
|
+
* @param {object} options 配置项 { pitch?, padding? }
|
|
3161
|
+
*/
|
|
3162
|
+
zoomTo(graphicIdOrEntity, options = {}) {
|
|
3163
|
+
const entity = typeof graphicIdOrEntity === 'string'
|
|
3164
|
+
? this.getGraphic(graphicIdOrEntity)
|
|
3165
|
+
: graphicIdOrEntity;
|
|
3166
|
+
if (!entity || !this.viewer) return;
|
|
3167
|
+
|
|
3168
|
+
const sphere = this.getBoundingSphere(entity);
|
|
3169
|
+
if (!sphere) return;
|
|
3170
|
+
|
|
3171
|
+
const pitch = options.pitch ?? -Cesium$e.Math.PI_OVER_TWO;
|
|
3172
|
+
const padding = options.padding ?? 2;
|
|
3173
|
+
const fovy = this.viewer.camera.frustum.fovy;
|
|
3174
|
+
const range = (sphere.radius / Math.tan(fovy / 2)) * padding;
|
|
3175
|
+
|
|
3176
|
+
this.viewer.camera.viewBoundingSphere(sphere, new Cesium$e.HeadingPitchRange(0, pitch, range));
|
|
3177
|
+
}
|
|
3178
|
+
|
|
3179
|
+
/**
|
|
3180
|
+
* 为面图元设置/移除外边框(用 polyline 模拟,解决 Cesium 贴地 polygon 不支持 outline 的问题)
|
|
3181
|
+
* @param {string} graphicId 图元ID
|
|
3182
|
+
* @param {object} options 配置项 { enabled, color, width }
|
|
3183
|
+
* @returns {boolean} 是否设置成功
|
|
3184
|
+
*/
|
|
3185
|
+
setOutline(graphicId, options = {}) {
|
|
3186
|
+
const entity = this.getGraphic(graphicId);
|
|
3187
|
+
if (!entity || !entity.polygon || !this.viewer) return false;
|
|
3188
|
+
|
|
3189
|
+
// 先移除旧的
|
|
3190
|
+
this.removeOutline(graphicId);
|
|
3191
|
+
|
|
3192
|
+
if (!options.enabled) return true;
|
|
3193
|
+
|
|
3194
|
+
const positions = this._getEntityPositions(entity);
|
|
3195
|
+
if (positions.length < 3) return false;
|
|
3196
|
+
|
|
3197
|
+
const closedPositions = [...positions, positions[0]];
|
|
3198
|
+
const outlineId = `${graphicId}_outline`;
|
|
3199
|
+
const color = options.color ?? Cesium$e.Color.WHITE;
|
|
3200
|
+
const width = options.width ?? 2;
|
|
3201
|
+
|
|
3202
|
+
this.viewer.entities.add({
|
|
3203
|
+
id: outlineId,
|
|
3204
|
+
polyline: {
|
|
3205
|
+
positions: closedPositions,
|
|
3206
|
+
width,
|
|
3207
|
+
material: color,
|
|
3208
|
+
clampToGround: true,
|
|
3209
|
+
},
|
|
3210
|
+
});
|
|
3211
|
+
return true;
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
/**
|
|
3215
|
+
* 移除面图元的外边框
|
|
3216
|
+
* @param {string} graphicId 图元ID
|
|
3217
|
+
*/
|
|
3218
|
+
removeOutline(graphicId) {
|
|
3219
|
+
if (!this.viewer) return;
|
|
3220
|
+
this.viewer.entities.removeById(`${graphicId}_outline`);
|
|
3221
|
+
}
|
|
3065
3222
|
}
|
|
3066
3223
|
|
|
3067
3224
|
const Cesium$d = getCesium();
|
|
@@ -6886,563 +7043,563 @@ class GeoCalcUtil {
|
|
|
6886
7043
|
}
|
|
6887
7044
|
}
|
|
6888
7045
|
|
|
6889
|
-
const Cesium$6 = getCesium();
|
|
6890
|
-
|
|
6891
|
-
/**
|
|
6892
|
-
* 测量类型枚举
|
|
6893
|
-
*/
|
|
6894
|
-
const MeasureType = {
|
|
6895
|
-
DISTANCE: 'distance',
|
|
6896
|
-
AREA: 'area'
|
|
6897
|
-
};
|
|
6898
|
-
|
|
6899
|
-
/**
|
|
6900
|
-
* 测量工具
|
|
6901
|
-
* 支持交互式测距(折线)和测面积(多边形)。
|
|
6902
|
-
* 左键加点,右键 / Enter 完成,Esc 取消,Backspace 撤销上一点。
|
|
6903
|
-
*/
|
|
6904
|
-
class MeasureTool extends BaseTool {
|
|
6905
|
-
constructor(editorModule, options = {}) {
|
|
6906
|
-
super(editorModule, options);
|
|
6907
|
-
|
|
6908
|
-
this._measureType = options.measureType || MeasureType.DISTANCE;
|
|
6909
|
-
this._positions = []; // 已点击的经纬度点
|
|
6910
|
-
this._mousePos = null; // 当前鼠标位置(经纬度)
|
|
6911
|
-
this._isMeasuring = false; // 是否正在一次测量中
|
|
6912
|
-
this._lastResult = null; // 最后一次测量结果
|
|
6913
|
-
|
|
6914
|
-
// 临时图元引用
|
|
6915
|
-
this._pointEntities = []; // 点击点标记
|
|
6916
|
-
this._previewLine = null; // 测距预览线
|
|
6917
|
-
this._previewPolygon = null; // 测面积预览面
|
|
6918
|
-
this._previewOutline = null; // 测面积预览轮廓线
|
|
6919
|
-
this._previewCartesians = []; // 当前预览几何的笛卡尔坐标数组(CallbackProperty 共享引用)
|
|
6920
|
-
this._segmentLabelEntities = []; // 测距每段标注
|
|
6921
|
-
this._totalLabelEntity = null; // 总距离 / 面积标注
|
|
6922
|
-
|
|
6923
|
-
// 已完成的测量结果图元分组,支持一次激活中保留多个测量结果
|
|
6924
|
-
this._finishedResults = [];
|
|
6925
|
-
}
|
|
6926
|
-
|
|
6927
|
-
/**
|
|
6928
|
-
* 设置测量类型
|
|
6929
|
-
* @param {string} type MeasureType
|
|
6930
|
-
*/
|
|
6931
|
-
setMeasureType(type) {
|
|
6932
|
-
this._measureType = type;
|
|
6933
|
-
return this;
|
|
6934
|
-
}
|
|
6935
|
-
|
|
6936
|
-
/**
|
|
6937
|
-
* 获取当前测量类型
|
|
6938
|
-
*/
|
|
6939
|
-
getMeasureType() {
|
|
6940
|
-
return this._measureType;
|
|
6941
|
-
}
|
|
6942
|
-
|
|
6943
|
-
/**
|
|
6944
|
-
* 获取最后一次测量结果
|
|
6945
|
-
*/
|
|
6946
|
-
getLastResult() {
|
|
6947
|
-
return this._lastResult;
|
|
6948
|
-
}
|
|
6949
|
-
|
|
6950
|
-
onActivate() {
|
|
6951
|
-
this.registerObserver('mouse:click', this._onClick.bind(this));
|
|
6952
|
-
this.registerObserver('mouse:move', this._onMove.bind(this));
|
|
6953
|
-
this.registerObserver('mouse:rightclick', this._onRightClick.bind(this));
|
|
6954
|
-
this.registerObserver('keyboard:keydown', this._onKeyDown.bind(this));
|
|
6955
|
-
}
|
|
6956
|
-
|
|
6957
|
-
onDeactivate() {
|
|
6958
|
-
this.clearMeasurements();
|
|
6959
|
-
}
|
|
6960
|
-
|
|
6961
|
-
_onClick(lngLat) {
|
|
6962
|
-
if (!lngLat) return;
|
|
6963
|
-
|
|
6964
|
-
this._isMeasuring = true;
|
|
6965
|
-
this._positions.push(lngLat);
|
|
6966
|
-
this._addPointMarker(lngLat);
|
|
6967
|
-
this._updateMeasurement();
|
|
6968
|
-
}
|
|
6969
|
-
|
|
6970
|
-
_onMove(data) {
|
|
6971
|
-
const screenPos = data.position || data.endPosition;
|
|
6972
|
-
if (!screenPos) return;
|
|
6973
|
-
|
|
6974
|
-
const lonLat = this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
|
|
6975
|
-
if (!lonLat) return;
|
|
6976
|
-
|
|
6977
|
-
this._mousePos = lonLat;
|
|
6978
|
-
if (this._isMeasuring) {
|
|
6979
|
-
this._updateMeasurement();
|
|
6980
|
-
}
|
|
6981
|
-
}
|
|
6982
|
-
|
|
6983
|
-
_onRightClick() {
|
|
6984
|
-
this._finishMeasurement();
|
|
6985
|
-
}
|
|
6986
|
-
|
|
6987
|
-
_onKeyDown(data) {
|
|
6988
|
-
if (data.key === 'Escape') {
|
|
6989
|
-
this.cancelMeasurement();
|
|
6990
|
-
return;
|
|
6991
|
-
}
|
|
6992
|
-
|
|
6993
|
-
if (data.key === 'Enter') {
|
|
6994
|
-
this._finishMeasurement();
|
|
6995
|
-
return;
|
|
6996
|
-
}
|
|
6997
|
-
|
|
6998
|
-
if (data.key === 'Backspace' && this._isMeasuring && this._positions.length > 0) {
|
|
6999
|
-
this._positions.pop();
|
|
7000
|
-
const lastPoint = this._pointEntities.pop();
|
|
7001
|
-
if (lastPoint) {
|
|
7002
|
-
this.removeTempEntity(lastPoint);
|
|
7003
|
-
}
|
|
7004
|
-
this._updateMeasurement();
|
|
7005
|
-
}
|
|
7006
|
-
}
|
|
7007
|
-
|
|
7008
|
-
/**
|
|
7009
|
-
* 完成当前测量
|
|
7010
|
-
*/
|
|
7011
|
-
_finishMeasurement() {
|
|
7012
|
-
const minPoints = this._measureType === MeasureType.AREA ? 3 : 2;
|
|
7013
|
-
if (this._positions.length < minPoints) return;
|
|
7014
|
-
|
|
7015
|
-
this._isMeasuring = false;
|
|
7016
|
-
this._mousePos = null;
|
|
7017
|
-
this._updateMeasurement();
|
|
7018
|
-
|
|
7019
|
-
const result = this._computeResult(this._positions);
|
|
7020
|
-
this._lastResult = result;
|
|
7021
|
-
|
|
7022
|
-
// 将当前测量结果保留在场景中,并清空工作态以便继续下一次测量
|
|
7023
|
-
this._commitCurrentResult();
|
|
7024
|
-
|
|
7025
|
-
this._emitMeasureComplete(result);
|
|
7026
|
-
}
|
|
7027
|
-
|
|
7028
|
-
/**
|
|
7029
|
-
* 把当前测量图元归档为已完成结果,重置工作态
|
|
7030
|
-
*/
|
|
7031
|
-
_commitCurrentResult() {
|
|
7032
|
-
const finalCartesians = this._previewCartesians.slice();
|
|
7033
|
-
|
|
7034
|
-
// 将动态 CallbackProperty 替换为常量几何,避免归档后随 _previewCartesians 变化而消失
|
|
7035
|
-
if (this._previewLine) {
|
|
7036
|
-
this._previewLine.polyline.positions = finalCartesians.length > 0 ? finalCartesians : [];
|
|
7037
|
-
}
|
|
7038
|
-
if (this._previewPolygon) {
|
|
7039
|
-
this._previewPolygon.polygon.hierarchy = finalCartesians.length >= 3
|
|
7040
|
-
? new Cesium$6.PolygonHierarchy(finalCartesians)
|
|
7041
|
-
: new Cesium$6.PolygonHierarchy([]);
|
|
7042
|
-
}
|
|
7043
|
-
if (this._previewOutline) {
|
|
7044
|
-
this._previewOutline.polyline.positions = finalCartesians.length >= 3
|
|
7045
|
-
? [...finalCartesians, finalCartesians[0]]
|
|
7046
|
-
: [];
|
|
7047
|
-
}
|
|
7048
|
-
|
|
7049
|
-
this._finishedResults.push({
|
|
7050
|
-
pointEntities: this._pointEntities,
|
|
7051
|
-
segmentLabels: this._segmentLabelEntities,
|
|
7052
|
-
totalLabel: this._totalLabelEntity,
|
|
7053
|
-
previewLine: this._previewLine,
|
|
7054
|
-
previewPolygon: this._previewPolygon,
|
|
7055
|
-
previewOutline: this._previewOutline
|
|
7056
|
-
});
|
|
7057
|
-
|
|
7058
|
-
this._positions = [];
|
|
7059
|
-
this._mousePos = null;
|
|
7060
|
-
this._isMeasuring = false;
|
|
7061
|
-
this._previewCartesians = [];
|
|
7062
|
-
|
|
7063
|
-
this._pointEntities = [];
|
|
7064
|
-
this._segmentLabelEntities = [];
|
|
7065
|
-
this._totalLabelEntity = null;
|
|
7066
|
-
this._previewLine = null;
|
|
7067
|
-
this._previewPolygon = null;
|
|
7068
|
-
this._previewOutline = null;
|
|
7069
|
-
}
|
|
7070
|
-
|
|
7071
|
-
/**
|
|
7072
|
-
* 取消当前测量
|
|
7073
|
-
*/
|
|
7074
|
-
cancelMeasurement() {
|
|
7075
|
-
this.clearMeasurements();
|
|
7076
|
-
this._emitMeasureCancel();
|
|
7077
|
-
}
|
|
7078
|
-
|
|
7079
|
-
/**
|
|
7080
|
-
* 清空所有测量结果与临时图元
|
|
7081
|
-
*/
|
|
7082
|
-
clearMeasurements() {
|
|
7083
|
-
this._positions = [];
|
|
7084
|
-
this._mousePos = null;
|
|
7085
|
-
this._isMeasuring = false;
|
|
7086
|
-
this._lastResult = null;
|
|
7087
|
-
this._previewCartesians = [];
|
|
7088
|
-
|
|
7089
|
-
this._pointEntities.forEach(e => this.removeTempEntity(e));
|
|
7090
|
-
this._pointEntities = [];
|
|
7091
|
-
|
|
7092
|
-
this._segmentLabelEntities.forEach(e => this.removeTempEntity(e));
|
|
7093
|
-
this._segmentLabelEntities = [];
|
|
7094
|
-
|
|
7095
|
-
if (this._totalLabelEntity) {
|
|
7096
|
-
this.removeTempEntity(this._totalLabelEntity);
|
|
7097
|
-
this._totalLabelEntity = null;
|
|
7098
|
-
}
|
|
7099
|
-
|
|
7100
|
-
if (this._previewLine) {
|
|
7101
|
-
this.removeTempEntity(this._previewLine);
|
|
7102
|
-
this._previewLine = null;
|
|
7103
|
-
}
|
|
7104
|
-
|
|
7105
|
-
if (this._previewPolygon) {
|
|
7106
|
-
this.removeTempEntity(this._previewPolygon);
|
|
7107
|
-
this._previewPolygon = null;
|
|
7108
|
-
}
|
|
7109
|
-
|
|
7110
|
-
if (this._previewOutline) {
|
|
7111
|
-
this.removeTempEntity(this._previewOutline);
|
|
7112
|
-
this._previewOutline = null;
|
|
7113
|
-
}
|
|
7114
|
-
|
|
7115
|
-
this._finishedResults.forEach(group => {
|
|
7116
|
-
group.pointEntities.forEach(e => this.removeTempEntity(e));
|
|
7117
|
-
group.segmentLabels.forEach(e => this.removeTempEntity(e));
|
|
7118
|
-
if (group.totalLabel) this.removeTempEntity(group.totalLabel);
|
|
7119
|
-
if (group.previewLine) this.removeTempEntity(group.previewLine);
|
|
7120
|
-
if (group.previewPolygon) this.removeTempEntity(group.previewPolygon);
|
|
7121
|
-
if (group.previewOutline) this.removeTempEntity(group.previewOutline);
|
|
7122
|
-
});
|
|
7123
|
-
this._finishedResults = [];
|
|
7124
|
-
}
|
|
7125
|
-
|
|
7126
|
-
/**
|
|
7127
|
-
* 更新预览几何与标注
|
|
7128
|
-
*/
|
|
7129
|
-
_updateMeasurement() {
|
|
7130
|
-
if (this._positions.length === 0) return;
|
|
7131
|
-
|
|
7132
|
-
const positions = [...this._positions];
|
|
7133
|
-
if (this._isMeasuring && this._mousePos) {
|
|
7134
|
-
positions.push(this._mousePos);
|
|
7135
|
-
}
|
|
7136
|
-
|
|
7137
|
-
if (this._measureType === MeasureType.DISTANCE) {
|
|
7138
|
-
this._updateDistancePreview(positions);
|
|
7139
|
-
} else {
|
|
7140
|
-
this._updateAreaPreview(positions);
|
|
7141
|
-
}
|
|
7142
|
-
|
|
7143
|
-
if (this._isMeasuring) {
|
|
7144
|
-
this._emitMeasureProgress(this._computeResult(positions));
|
|
7145
|
-
}
|
|
7146
|
-
}
|
|
7147
|
-
|
|
7148
|
-
_updateDistancePreview(positions) {
|
|
7149
|
-
const cartesians = positions.length >= 2
|
|
7150
|
-
? positions.map(p => Cesium$6.Cartesian3.fromDegrees(...p))
|
|
7151
|
-
: [];
|
|
7152
|
-
this._previewCartesians = cartesians;
|
|
7153
|
-
|
|
7154
|
-
// 预览线
|
|
7155
|
-
if (!this._previewLine) {
|
|
7156
|
-
this._previewLine = this.createTempEntity(this.generateId('measure_line'), {
|
|
7157
|
-
polyline: {
|
|
7158
|
-
positions: new Cesium$6.CallbackProperty(() => this._previewCartesians, false),
|
|
7159
|
-
material: Cesium$6.Color.YELLOW,
|
|
7160
|
-
width: 2,
|
|
7161
|
-
clampToGround: true
|
|
7162
|
-
}
|
|
7163
|
-
});
|
|
7164
|
-
}
|
|
7165
|
-
this._previewLine.show = cartesians.length >= 2;
|
|
7166
|
-
|
|
7167
|
-
// 每段标注
|
|
7168
|
-
const segmentCount = Math.max(0, positions.length - 1);
|
|
7169
|
-
this._ensureSegmentLabels(segmentCount);
|
|
7170
|
-
|
|
7171
|
-
let total = 0;
|
|
7172
|
-
for (let i = 0; i < segmentCount; i++) {
|
|
7173
|
-
const p1 = positions[i];
|
|
7174
|
-
const p2 = positions[i + 1];
|
|
7175
|
-
const dist = GeoCalcUtil.calcDistance(p1, p2);
|
|
7176
|
-
total += dist;
|
|
7177
|
-
|
|
7178
|
-
const mid = Cesium$6.Cartesian3.midpoint(
|
|
7179
|
-
Cesium$6.Cartesian3.fromDegrees(...p1),
|
|
7180
|
-
Cesium$6.Cartesian3.fromDegrees(...p2),
|
|
7181
|
-
new Cesium$6.Cartesian3()
|
|
7182
|
-
);
|
|
7183
|
-
|
|
7184
|
-
const label = this._segmentLabelEntities[i];
|
|
7185
|
-
label.position = mid;
|
|
7186
|
-
label.label.text = this._formatDistance(dist).text;
|
|
7187
|
-
label.show = true;
|
|
7188
|
-
}
|
|
7189
|
-
|
|
7190
|
-
// 总距离标注
|
|
7191
|
-
const lastCartesian = cartesians[cartesians.length - 1];
|
|
7192
|
-
if (positions.length >= 2) {
|
|
7193
|
-
if (!this._totalLabelEntity) {
|
|
7194
|
-
this._totalLabelEntity = this._createLabelEntity(
|
|
7195
|
-
this.generateId('measure_total'),
|
|
7196
|
-
lastCartesian,
|
|
7197
|
-
`总长:${this._formatDistance(total).text}`
|
|
7198
|
-
);
|
|
7199
|
-
} else {
|
|
7200
|
-
this._totalLabelEntity.position = lastCartesian;
|
|
7201
|
-
this._totalLabelEntity.label.text = `总长:${this._formatDistance(total).text}`;
|
|
7202
|
-
this._totalLabelEntity.show = true;
|
|
7203
|
-
}
|
|
7204
|
-
} else if (this._totalLabelEntity) {
|
|
7205
|
-
this._totalLabelEntity.show = false;
|
|
7206
|
-
}
|
|
7207
|
-
}
|
|
7208
|
-
|
|
7209
|
-
_updateAreaPreview(positions) {
|
|
7210
|
-
const cartesians = positions.map(p => Cesium$6.Cartesian3.fromDegrees(...p));
|
|
7211
|
-
this._previewCartesians = cartesians;
|
|
7212
|
-
|
|
7213
|
-
if (positions.length >= 3) {
|
|
7214
|
-
// 显示面 + 闭合轮廓
|
|
7215
|
-
if (!this._previewPolygon) {
|
|
7216
|
-
this._previewPolygon = this.createTempEntity(this.generateId('measure_polygon'), {
|
|
7217
|
-
polygon: {
|
|
7218
|
-
hierarchy: new Cesium$6.CallbackProperty(() => new Cesium$6.PolygonHierarchy(this._previewCartesians), false),
|
|
7219
|
-
material: Cesium$6.Color.YELLOW.withAlpha(0.2),
|
|
7220
|
-
outline: false
|
|
7221
|
-
}
|
|
7222
|
-
});
|
|
7223
|
-
this._previewOutline = this.createTempEntity(this.generateId('measure_outline'), {
|
|
7224
|
-
polyline: {
|
|
7225
|
-
positions: new Cesium$6.CallbackProperty(() => this._previewCartesians.length > 0
|
|
7226
|
-
? [...this._previewCartesians, this._previewCartesians[0]]
|
|
7227
|
-
: [], false),
|
|
7228
|
-
material: Cesium$6.Color.YELLOW,
|
|
7229
|
-
width: 2,
|
|
7230
|
-
clampToGround: true
|
|
7231
|
-
}
|
|
7232
|
-
});
|
|
7233
|
-
}
|
|
7234
|
-
this._previewPolygon.show = true;
|
|
7235
|
-
this._previewOutline.show = true;
|
|
7236
|
-
if (this._previewLine) {
|
|
7237
|
-
this._previewLine.show = false;
|
|
7238
|
-
}
|
|
7239
|
-
|
|
7240
|
-
const area = GeoCalcUtil.calcArea(positions);
|
|
7241
|
-
const centroid = this._computeCentroid(cartesians);
|
|
7242
|
-
|
|
7243
|
-
if (!this._totalLabelEntity) {
|
|
7244
|
-
this._totalLabelEntity = this._createLabelEntity(
|
|
7245
|
-
this.generateId('measure_area'),
|
|
7246
|
-
centroid,
|
|
7247
|
-
`面积:${this._formatArea(area).text}`
|
|
7248
|
-
);
|
|
7249
|
-
} else {
|
|
7250
|
-
this._totalLabelEntity.position = centroid;
|
|
7251
|
-
this._totalLabelEntity.label.text = `面积:${this._formatArea(area).text}`;
|
|
7252
|
-
this._totalLabelEntity.show = true;
|
|
7253
|
-
}
|
|
7254
|
-
} else {
|
|
7255
|
-
// 不足 3 点时只显示连线,并隐藏已有的面、轮廓、面积标注
|
|
7256
|
-
if (this._previewPolygon) {
|
|
7257
|
-
this._previewPolygon.show = false;
|
|
7258
|
-
}
|
|
7259
|
-
if (this._previewOutline) {
|
|
7260
|
-
this._previewOutline.show = false;
|
|
7261
|
-
}
|
|
7262
|
-
if (this._totalLabelEntity) {
|
|
7263
|
-
this._totalLabelEntity.show = false;
|
|
7264
|
-
}
|
|
7265
|
-
|
|
7266
|
-
if (!this._previewLine) {
|
|
7267
|
-
this._previewLine = this.createTempEntity(this.generateId('measure_line'), {
|
|
7268
|
-
polyline: {
|
|
7269
|
-
positions: new Cesium$6.CallbackProperty(() => this._previewCartesians, false),
|
|
7270
|
-
material: Cesium$6.Color.YELLOW,
|
|
7271
|
-
width: 2,
|
|
7272
|
-
clampToGround: true
|
|
7273
|
-
}
|
|
7274
|
-
});
|
|
7275
|
-
}
|
|
7276
|
-
this._previewLine.show = positions.length >= 2;
|
|
7277
|
-
}
|
|
7278
|
-
}
|
|
7279
|
-
|
|
7280
|
-
_ensureSegmentLabels(count) {
|
|
7281
|
-
// 移除多余的标注
|
|
7282
|
-
while (this._segmentLabelEntities.length > count) {
|
|
7283
|
-
const label = this._segmentLabelEntities.pop();
|
|
7284
|
-
this.removeTempEntity(label);
|
|
7285
|
-
}
|
|
7286
|
-
|
|
7287
|
-
// 创建缺少的标注
|
|
7288
|
-
while (this._segmentLabelEntities.length < count) {
|
|
7289
|
-
const label = this._createLabelEntity(
|
|
7290
|
-
this.generateId('measure_segment'),
|
|
7291
|
-
Cesium$6.Cartesian3.ZERO,
|
|
7292
|
-
''
|
|
7293
|
-
);
|
|
7294
|
-
this._segmentLabelEntities.push(label);
|
|
7295
|
-
}
|
|
7296
|
-
}
|
|
7297
|
-
|
|
7298
|
-
_createLabelEntity(id, position, text) {
|
|
7299
|
-
return this.createTempEntity(id, {
|
|
7300
|
-
position,
|
|
7301
|
-
label: {
|
|
7302
|
-
text,
|
|
7303
|
-
font: '14px Microsoft YaHei',
|
|
7304
|
-
fillColor: Cesium$6.Color.WHITE,
|
|
7305
|
-
outlineColor: Cesium$6.Color.BLACK,
|
|
7306
|
-
outlineWidth: 2,
|
|
7307
|
-
style: Cesium$6.LabelStyle.FILL_AND_OUTLINE,
|
|
7308
|
-
verticalOrigin: Cesium$6.VerticalOrigin.BOTTOM,
|
|
7309
|
-
horizontalOrigin: Cesium$6.HorizontalOrigin.CENTER,
|
|
7310
|
-
heightReference: Cesium$6.HeightReference.CLAMP_TO_GROUND,
|
|
7311
|
-
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
7312
|
-
pixelOffset: new Cesium$6.Cartesian2(0, -10)
|
|
7313
|
-
}
|
|
7314
|
-
});
|
|
7315
|
-
}
|
|
7316
|
-
|
|
7317
|
-
_addPointMarker(lonLat) {
|
|
7318
|
-
const point = this.createTempEntity(this.generateId('measure_point'), {
|
|
7319
|
-
position: Cesium$6.Cartesian3.fromDegrees(...lonLat),
|
|
7320
|
-
point: {
|
|
7321
|
-
color: Cesium$6.Color.YELLOW,
|
|
7322
|
-
pixelSize: 8,
|
|
7323
|
-
outlineColor: Cesium$6.Color.BLACK,
|
|
7324
|
-
outlineWidth: 1,
|
|
7325
|
-
heightReference: Cesium$6.HeightReference.CLAMP_TO_GROUND,
|
|
7326
|
-
disableDepthTestDistance: Number.POSITIVE_INFINITY
|
|
7327
|
-
}
|
|
7328
|
-
});
|
|
7329
|
-
this._pointEntities.push(point);
|
|
7330
|
-
}
|
|
7331
|
-
|
|
7332
|
-
_computeResult(positions) {
|
|
7333
|
-
if (this._measureType === MeasureType.DISTANCE) {
|
|
7334
|
-
let total = 0;
|
|
7335
|
-
for (let i = 0; i < positions.length - 1; i++) {
|
|
7336
|
-
total += GeoCalcUtil.calcDistance(positions[i], positions[i + 1]);
|
|
7337
|
-
}
|
|
7338
|
-
const fmt = this._formatDistance(total);
|
|
7339
|
-
return {
|
|
7340
|
-
type: MeasureType.DISTANCE,
|
|
7341
|
-
value: total,
|
|
7342
|
-
unit: fmt.unit,
|
|
7343
|
-
formatted: fmt.text,
|
|
7344
|
-
positions: positions.slice()
|
|
7345
|
-
};
|
|
7346
|
-
}
|
|
7347
|
-
|
|
7348
|
-
const area = GeoCalcUtil.calcArea(positions);
|
|
7349
|
-
const fmt = this._formatArea(area);
|
|
7350
|
-
return {
|
|
7351
|
-
type: MeasureType.AREA,
|
|
7352
|
-
value: area,
|
|
7353
|
-
unit: fmt.unit,
|
|
7354
|
-
formatted: fmt.text,
|
|
7355
|
-
positions: positions.slice()
|
|
7356
|
-
};
|
|
7357
|
-
}
|
|
7358
|
-
|
|
7359
|
-
_computeCentroid(cartesians) {
|
|
7360
|
-
const center = new Cesium$6.Cartesian3(0, 0, 0);
|
|
7361
|
-
for (const c of cartesians) {
|
|
7362
|
-
Cesium$6.Cartesian3.add(center, c, center);
|
|
7363
|
-
}
|
|
7364
|
-
return Cesium$6.Cartesian3.multiplyByScalar(center, 1 / cartesians.length, center);
|
|
7365
|
-
}
|
|
7366
|
-
|
|
7367
|
-
_formatDistance(meters) {
|
|
7368
|
-
if (meters >= 1000) {
|
|
7369
|
-
return { text: `${(meters / 1000).toFixed(2)} km`, unit: 'km' };
|
|
7370
|
-
}
|
|
7371
|
-
return { text: `${meters.toFixed(2)} m`, unit: 'm' };
|
|
7372
|
-
}
|
|
7373
|
-
|
|
7374
|
-
_formatArea(squareMeters) {
|
|
7375
|
-
if (squareMeters >= 1000000) {
|
|
7376
|
-
return { text: `${(squareMeters / 1000000).toFixed(3)} km²`, unit: 'km²' };
|
|
7377
|
-
}
|
|
7378
|
-
return { text: `${squareMeters.toFixed(2)} m²`, unit: 'm²' };
|
|
7379
|
-
}
|
|
7380
|
-
|
|
7381
|
-
_emitMeasureProgress(result) {
|
|
7382
|
-
if (this._options.onMeasureProgress) {
|
|
7383
|
-
this._options.onMeasureProgress(result);
|
|
7384
|
-
}
|
|
7385
|
-
}
|
|
7386
|
-
|
|
7387
|
-
_emitMeasureComplete(result) {
|
|
7388
|
-
if (this._options.onMeasureComplete) {
|
|
7389
|
-
this._options.onMeasureComplete(result);
|
|
7390
|
-
}
|
|
7391
|
-
}
|
|
7392
|
-
|
|
7393
|
-
_emitMeasureCancel() {
|
|
7394
|
-
if (this._options.onMeasureCancel) {
|
|
7395
|
-
this._options.onMeasureCancel();
|
|
7396
|
-
}
|
|
7397
|
-
}
|
|
7398
|
-
}
|
|
7399
|
-
|
|
7046
|
+
const Cesium$6 = getCesium();
|
|
7047
|
+
|
|
7400
7048
|
/**
|
|
7401
|
-
*
|
|
7049
|
+
* 测量类型枚举
|
|
7402
7050
|
*/
|
|
7403
|
-
const
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
SELECT: 'select',
|
|
7407
|
-
DELETE: 'delete',
|
|
7408
|
-
MEASURE: 'measure'
|
|
7051
|
+
const MeasureType = {
|
|
7052
|
+
DISTANCE: 'distance',
|
|
7053
|
+
AREA: 'area'
|
|
7409
7054
|
};
|
|
7410
7055
|
|
|
7411
7056
|
/**
|
|
7412
|
-
*
|
|
7413
|
-
*
|
|
7057
|
+
* 测量工具
|
|
7058
|
+
* 支持交互式测距(折线)和测面积(多边形)。
|
|
7059
|
+
* 左键加点,右键 / Enter 完成,Esc 取消,Backspace 撤销上一点。
|
|
7414
7060
|
*/
|
|
7415
|
-
class
|
|
7416
|
-
constructor(
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
this.
|
|
7420
|
-
this.
|
|
7421
|
-
this.
|
|
7422
|
-
this.
|
|
7423
|
-
this.
|
|
7424
|
-
|
|
7061
|
+
class MeasureTool extends BaseTool {
|
|
7062
|
+
constructor(editorModule, options = {}) {
|
|
7063
|
+
super(editorModule, options);
|
|
7064
|
+
|
|
7065
|
+
this._measureType = options.measureType || MeasureType.DISTANCE;
|
|
7066
|
+
this._positions = []; // 已点击的经纬度点
|
|
7067
|
+
this._mousePos = null; // 当前鼠标位置(经纬度)
|
|
7068
|
+
this._isMeasuring = false; // 是否正在一次测量中
|
|
7069
|
+
this._lastResult = null; // 最后一次测量结果
|
|
7070
|
+
|
|
7071
|
+
// 临时图元引用
|
|
7072
|
+
this._pointEntities = []; // 点击点标记
|
|
7073
|
+
this._previewLine = null; // 测距预览线
|
|
7074
|
+
this._previewPolygon = null; // 测面积预览面
|
|
7075
|
+
this._previewOutline = null; // 测面积预览轮廓线
|
|
7076
|
+
this._previewCartesians = []; // 当前预览几何的笛卡尔坐标数组(CallbackProperty 共享引用)
|
|
7077
|
+
this._segmentLabelEntities = []; // 测距每段标注
|
|
7078
|
+
this._totalLabelEntity = null; // 总距离 / 面积标注
|
|
7079
|
+
|
|
7080
|
+
// 已完成的测量结果图元分组,支持一次激活中保留多个测量结果
|
|
7081
|
+
this._finishedResults = [];
|
|
7425
7082
|
}
|
|
7426
7083
|
|
|
7427
7084
|
/**
|
|
7428
|
-
*
|
|
7429
|
-
* @param {
|
|
7085
|
+
* 设置测量类型
|
|
7086
|
+
* @param {string} type MeasureType
|
|
7430
7087
|
*/
|
|
7431
|
-
|
|
7432
|
-
this.
|
|
7433
|
-
this.eventModule = deps.eventModule;
|
|
7088
|
+
setMeasureType(type) {
|
|
7089
|
+
this._measureType = type;
|
|
7434
7090
|
return this;
|
|
7435
7091
|
}
|
|
7436
7092
|
|
|
7437
7093
|
/**
|
|
7438
|
-
*
|
|
7094
|
+
* 获取当前测量类型
|
|
7439
7095
|
*/
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7096
|
+
getMeasureType() {
|
|
7097
|
+
return this._measureType;
|
|
7098
|
+
}
|
|
7099
|
+
|
|
7100
|
+
/**
|
|
7101
|
+
* 获取最后一次测量结果
|
|
7102
|
+
*/
|
|
7103
|
+
getLastResult() {
|
|
7104
|
+
return this._lastResult;
|
|
7105
|
+
}
|
|
7106
|
+
|
|
7107
|
+
onActivate() {
|
|
7108
|
+
this.registerObserver('mouse:click', this._onClick.bind(this));
|
|
7109
|
+
this.registerObserver('mouse:move', this._onMove.bind(this));
|
|
7110
|
+
this.registerObserver('mouse:rightclick', this._onRightClick.bind(this));
|
|
7111
|
+
this.registerObserver('keyboard:keydown', this._onKeyDown.bind(this));
|
|
7112
|
+
}
|
|
7113
|
+
|
|
7114
|
+
onDeactivate() {
|
|
7115
|
+
this.clearMeasurements();
|
|
7116
|
+
}
|
|
7117
|
+
|
|
7118
|
+
_onClick(lngLat) {
|
|
7119
|
+
if (!lngLat) return;
|
|
7120
|
+
|
|
7121
|
+
this._isMeasuring = true;
|
|
7122
|
+
this._positions.push(lngLat);
|
|
7123
|
+
this._addPointMarker(lngLat);
|
|
7124
|
+
this._updateMeasurement();
|
|
7125
|
+
}
|
|
7126
|
+
|
|
7127
|
+
_onMove(data) {
|
|
7128
|
+
const screenPos = data.position || data.endPosition;
|
|
7129
|
+
if (!screenPos) return;
|
|
7130
|
+
|
|
7131
|
+
const lonLat = this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
|
|
7132
|
+
if (!lonLat) return;
|
|
7133
|
+
|
|
7134
|
+
this._mousePos = lonLat;
|
|
7135
|
+
if (this._isMeasuring) {
|
|
7136
|
+
this._updateMeasurement();
|
|
7137
|
+
}
|
|
7138
|
+
}
|
|
7139
|
+
|
|
7140
|
+
_onRightClick() {
|
|
7141
|
+
this._finishMeasurement();
|
|
7142
|
+
}
|
|
7143
|
+
|
|
7144
|
+
_onKeyDown(data) {
|
|
7145
|
+
if (data.key === 'Escape') {
|
|
7146
|
+
this.cancelMeasurement();
|
|
7147
|
+
return;
|
|
7148
|
+
}
|
|
7149
|
+
|
|
7150
|
+
if (data.key === 'Enter') {
|
|
7151
|
+
this._finishMeasurement();
|
|
7152
|
+
return;
|
|
7153
|
+
}
|
|
7154
|
+
|
|
7155
|
+
if (data.key === 'Backspace' && this._isMeasuring && this._positions.length > 0) {
|
|
7156
|
+
this._positions.pop();
|
|
7157
|
+
const lastPoint = this._pointEntities.pop();
|
|
7158
|
+
if (lastPoint) {
|
|
7159
|
+
this.removeTempEntity(lastPoint);
|
|
7160
|
+
}
|
|
7161
|
+
this._updateMeasurement();
|
|
7162
|
+
}
|
|
7163
|
+
}
|
|
7164
|
+
|
|
7165
|
+
/**
|
|
7166
|
+
* 完成当前测量
|
|
7167
|
+
*/
|
|
7168
|
+
_finishMeasurement() {
|
|
7169
|
+
const minPoints = this._measureType === MeasureType.AREA ? 3 : 2;
|
|
7170
|
+
if (this._positions.length < minPoints) return;
|
|
7171
|
+
|
|
7172
|
+
this._isMeasuring = false;
|
|
7173
|
+
this._mousePos = null;
|
|
7174
|
+
this._updateMeasurement();
|
|
7175
|
+
|
|
7176
|
+
const result = this._computeResult(this._positions);
|
|
7177
|
+
this._lastResult = result;
|
|
7178
|
+
|
|
7179
|
+
// 将当前测量结果保留在场景中,并清空工作态以便继续下一次测量
|
|
7180
|
+
this._commitCurrentResult();
|
|
7181
|
+
|
|
7182
|
+
this._emitMeasureComplete(result);
|
|
7183
|
+
}
|
|
7184
|
+
|
|
7185
|
+
/**
|
|
7186
|
+
* 把当前测量图元归档为已完成结果,重置工作态
|
|
7187
|
+
*/
|
|
7188
|
+
_commitCurrentResult() {
|
|
7189
|
+
const finalCartesians = this._previewCartesians.slice();
|
|
7190
|
+
|
|
7191
|
+
// 将动态 CallbackProperty 替换为常量几何,避免归档后随 _previewCartesians 变化而消失
|
|
7192
|
+
if (this._previewLine) {
|
|
7193
|
+
this._previewLine.polyline.positions = finalCartesians.length > 0 ? finalCartesians : [];
|
|
7194
|
+
}
|
|
7195
|
+
if (this._previewPolygon) {
|
|
7196
|
+
this._previewPolygon.polygon.hierarchy = finalCartesians.length >= 3
|
|
7197
|
+
? new Cesium$6.PolygonHierarchy(finalCartesians)
|
|
7198
|
+
: new Cesium$6.PolygonHierarchy([]);
|
|
7199
|
+
}
|
|
7200
|
+
if (this._previewOutline) {
|
|
7201
|
+
this._previewOutline.polyline.positions = finalCartesians.length >= 3
|
|
7202
|
+
? [...finalCartesians, finalCartesians[0]]
|
|
7203
|
+
: [];
|
|
7204
|
+
}
|
|
7205
|
+
|
|
7206
|
+
this._finishedResults.push({
|
|
7207
|
+
pointEntities: this._pointEntities,
|
|
7208
|
+
segmentLabels: this._segmentLabelEntities,
|
|
7209
|
+
totalLabel: this._totalLabelEntity,
|
|
7210
|
+
previewLine: this._previewLine,
|
|
7211
|
+
previewPolygon: this._previewPolygon,
|
|
7212
|
+
previewOutline: this._previewOutline
|
|
7213
|
+
});
|
|
7214
|
+
|
|
7215
|
+
this._positions = [];
|
|
7216
|
+
this._mousePos = null;
|
|
7217
|
+
this._isMeasuring = false;
|
|
7218
|
+
this._previewCartesians = [];
|
|
7219
|
+
|
|
7220
|
+
this._pointEntities = [];
|
|
7221
|
+
this._segmentLabelEntities = [];
|
|
7222
|
+
this._totalLabelEntity = null;
|
|
7223
|
+
this._previewLine = null;
|
|
7224
|
+
this._previewPolygon = null;
|
|
7225
|
+
this._previewOutline = null;
|
|
7226
|
+
}
|
|
7227
|
+
|
|
7228
|
+
/**
|
|
7229
|
+
* 取消当前测量
|
|
7230
|
+
*/
|
|
7231
|
+
cancelMeasurement() {
|
|
7232
|
+
this.clearMeasurements();
|
|
7233
|
+
this._emitMeasureCancel();
|
|
7234
|
+
}
|
|
7235
|
+
|
|
7236
|
+
/**
|
|
7237
|
+
* 清空所有测量结果与临时图元
|
|
7238
|
+
*/
|
|
7239
|
+
clearMeasurements() {
|
|
7240
|
+
this._positions = [];
|
|
7241
|
+
this._mousePos = null;
|
|
7242
|
+
this._isMeasuring = false;
|
|
7243
|
+
this._lastResult = null;
|
|
7244
|
+
this._previewCartesians = [];
|
|
7245
|
+
|
|
7246
|
+
this._pointEntities.forEach(e => this.removeTempEntity(e));
|
|
7247
|
+
this._pointEntities = [];
|
|
7248
|
+
|
|
7249
|
+
this._segmentLabelEntities.forEach(e => this.removeTempEntity(e));
|
|
7250
|
+
this._segmentLabelEntities = [];
|
|
7251
|
+
|
|
7252
|
+
if (this._totalLabelEntity) {
|
|
7253
|
+
this.removeTempEntity(this._totalLabelEntity);
|
|
7254
|
+
this._totalLabelEntity = null;
|
|
7255
|
+
}
|
|
7256
|
+
|
|
7257
|
+
if (this._previewLine) {
|
|
7258
|
+
this.removeTempEntity(this._previewLine);
|
|
7259
|
+
this._previewLine = null;
|
|
7260
|
+
}
|
|
7261
|
+
|
|
7262
|
+
if (this._previewPolygon) {
|
|
7263
|
+
this.removeTempEntity(this._previewPolygon);
|
|
7264
|
+
this._previewPolygon = null;
|
|
7265
|
+
}
|
|
7266
|
+
|
|
7267
|
+
if (this._previewOutline) {
|
|
7268
|
+
this.removeTempEntity(this._previewOutline);
|
|
7269
|
+
this._previewOutline = null;
|
|
7270
|
+
}
|
|
7271
|
+
|
|
7272
|
+
this._finishedResults.forEach(group => {
|
|
7273
|
+
group.pointEntities.forEach(e => this.removeTempEntity(e));
|
|
7274
|
+
group.segmentLabels.forEach(e => this.removeTempEntity(e));
|
|
7275
|
+
if (group.totalLabel) this.removeTempEntity(group.totalLabel);
|
|
7276
|
+
if (group.previewLine) this.removeTempEntity(group.previewLine);
|
|
7277
|
+
if (group.previewPolygon) this.removeTempEntity(group.previewPolygon);
|
|
7278
|
+
if (group.previewOutline) this.removeTempEntity(group.previewOutline);
|
|
7279
|
+
});
|
|
7280
|
+
this._finishedResults = [];
|
|
7281
|
+
}
|
|
7282
|
+
|
|
7283
|
+
/**
|
|
7284
|
+
* 更新预览几何与标注
|
|
7285
|
+
*/
|
|
7286
|
+
_updateMeasurement() {
|
|
7287
|
+
if (this._positions.length === 0) return;
|
|
7288
|
+
|
|
7289
|
+
const positions = [...this._positions];
|
|
7290
|
+
if (this._isMeasuring && this._mousePos) {
|
|
7291
|
+
positions.push(this._mousePos);
|
|
7292
|
+
}
|
|
7293
|
+
|
|
7294
|
+
if (this._measureType === MeasureType.DISTANCE) {
|
|
7295
|
+
this._updateDistancePreview(positions);
|
|
7296
|
+
} else {
|
|
7297
|
+
this._updateAreaPreview(positions);
|
|
7298
|
+
}
|
|
7299
|
+
|
|
7300
|
+
if (this._isMeasuring) {
|
|
7301
|
+
this._emitMeasureProgress(this._computeResult(positions));
|
|
7302
|
+
}
|
|
7303
|
+
}
|
|
7304
|
+
|
|
7305
|
+
_updateDistancePreview(positions) {
|
|
7306
|
+
const cartesians = positions.length >= 2
|
|
7307
|
+
? positions.map(p => Cesium$6.Cartesian3.fromDegrees(...p))
|
|
7308
|
+
: [];
|
|
7309
|
+
this._previewCartesians = cartesians;
|
|
7310
|
+
|
|
7311
|
+
// 预览线
|
|
7312
|
+
if (!this._previewLine) {
|
|
7313
|
+
this._previewLine = this.createTempEntity(this.generateId('measure_line'), {
|
|
7314
|
+
polyline: {
|
|
7315
|
+
positions: new Cesium$6.CallbackProperty(() => this._previewCartesians, false),
|
|
7316
|
+
material: Cesium$6.Color.YELLOW,
|
|
7317
|
+
width: 2,
|
|
7318
|
+
clampToGround: true
|
|
7319
|
+
}
|
|
7320
|
+
});
|
|
7321
|
+
}
|
|
7322
|
+
this._previewLine.show = cartesians.length >= 2;
|
|
7323
|
+
|
|
7324
|
+
// 每段标注
|
|
7325
|
+
const segmentCount = Math.max(0, positions.length - 1);
|
|
7326
|
+
this._ensureSegmentLabels(segmentCount);
|
|
7327
|
+
|
|
7328
|
+
let total = 0;
|
|
7329
|
+
for (let i = 0; i < segmentCount; i++) {
|
|
7330
|
+
const p1 = positions[i];
|
|
7331
|
+
const p2 = positions[i + 1];
|
|
7332
|
+
const dist = GeoCalcUtil.calcDistance(p1, p2);
|
|
7333
|
+
total += dist;
|
|
7334
|
+
|
|
7335
|
+
const mid = Cesium$6.Cartesian3.midpoint(
|
|
7336
|
+
Cesium$6.Cartesian3.fromDegrees(...p1),
|
|
7337
|
+
Cesium$6.Cartesian3.fromDegrees(...p2),
|
|
7338
|
+
new Cesium$6.Cartesian3()
|
|
7339
|
+
);
|
|
7340
|
+
|
|
7341
|
+
const label = this._segmentLabelEntities[i];
|
|
7342
|
+
label.position = mid;
|
|
7343
|
+
label.label.text = this._formatDistance(dist).text;
|
|
7344
|
+
label.show = true;
|
|
7345
|
+
}
|
|
7346
|
+
|
|
7347
|
+
// 总距离标注
|
|
7348
|
+
const lastCartesian = cartesians[cartesians.length - 1];
|
|
7349
|
+
if (positions.length >= 2) {
|
|
7350
|
+
if (!this._totalLabelEntity) {
|
|
7351
|
+
this._totalLabelEntity = this._createLabelEntity(
|
|
7352
|
+
this.generateId('measure_total'),
|
|
7353
|
+
lastCartesian,
|
|
7354
|
+
`总长:${this._formatDistance(total).text}`
|
|
7355
|
+
);
|
|
7356
|
+
} else {
|
|
7357
|
+
this._totalLabelEntity.position = lastCartesian;
|
|
7358
|
+
this._totalLabelEntity.label.text = `总长:${this._formatDistance(total).text}`;
|
|
7359
|
+
this._totalLabelEntity.show = true;
|
|
7360
|
+
}
|
|
7361
|
+
} else if (this._totalLabelEntity) {
|
|
7362
|
+
this._totalLabelEntity.show = false;
|
|
7363
|
+
}
|
|
7364
|
+
}
|
|
7365
|
+
|
|
7366
|
+
_updateAreaPreview(positions) {
|
|
7367
|
+
const cartesians = positions.map(p => Cesium$6.Cartesian3.fromDegrees(...p));
|
|
7368
|
+
this._previewCartesians = cartesians;
|
|
7369
|
+
|
|
7370
|
+
if (positions.length >= 3) {
|
|
7371
|
+
// 显示面 + 闭合轮廓
|
|
7372
|
+
if (!this._previewPolygon) {
|
|
7373
|
+
this._previewPolygon = this.createTempEntity(this.generateId('measure_polygon'), {
|
|
7374
|
+
polygon: {
|
|
7375
|
+
hierarchy: new Cesium$6.CallbackProperty(() => new Cesium$6.PolygonHierarchy(this._previewCartesians), false),
|
|
7376
|
+
material: Cesium$6.Color.YELLOW.withAlpha(0.2),
|
|
7377
|
+
outline: false
|
|
7378
|
+
}
|
|
7379
|
+
});
|
|
7380
|
+
this._previewOutline = this.createTempEntity(this.generateId('measure_outline'), {
|
|
7381
|
+
polyline: {
|
|
7382
|
+
positions: new Cesium$6.CallbackProperty(() => this._previewCartesians.length > 0
|
|
7383
|
+
? [...this._previewCartesians, this._previewCartesians[0]]
|
|
7384
|
+
: [], false),
|
|
7385
|
+
material: Cesium$6.Color.YELLOW,
|
|
7386
|
+
width: 2,
|
|
7387
|
+
clampToGround: true
|
|
7388
|
+
}
|
|
7389
|
+
});
|
|
7390
|
+
}
|
|
7391
|
+
this._previewPolygon.show = true;
|
|
7392
|
+
this._previewOutline.show = true;
|
|
7393
|
+
if (this._previewLine) {
|
|
7394
|
+
this._previewLine.show = false;
|
|
7395
|
+
}
|
|
7396
|
+
|
|
7397
|
+
const area = GeoCalcUtil.calcArea(positions);
|
|
7398
|
+
const centroid = this._computeCentroid(cartesians);
|
|
7399
|
+
|
|
7400
|
+
if (!this._totalLabelEntity) {
|
|
7401
|
+
this._totalLabelEntity = this._createLabelEntity(
|
|
7402
|
+
this.generateId('measure_area'),
|
|
7403
|
+
centroid,
|
|
7404
|
+
`面积:${this._formatArea(area).text}`
|
|
7405
|
+
);
|
|
7406
|
+
} else {
|
|
7407
|
+
this._totalLabelEntity.position = centroid;
|
|
7408
|
+
this._totalLabelEntity.label.text = `面积:${this._formatArea(area).text}`;
|
|
7409
|
+
this._totalLabelEntity.show = true;
|
|
7410
|
+
}
|
|
7411
|
+
} else {
|
|
7412
|
+
// 不足 3 点时只显示连线,并隐藏已有的面、轮廓、面积标注
|
|
7413
|
+
if (this._previewPolygon) {
|
|
7414
|
+
this._previewPolygon.show = false;
|
|
7415
|
+
}
|
|
7416
|
+
if (this._previewOutline) {
|
|
7417
|
+
this._previewOutline.show = false;
|
|
7418
|
+
}
|
|
7419
|
+
if (this._totalLabelEntity) {
|
|
7420
|
+
this._totalLabelEntity.show = false;
|
|
7421
|
+
}
|
|
7422
|
+
|
|
7423
|
+
if (!this._previewLine) {
|
|
7424
|
+
this._previewLine = this.createTempEntity(this.generateId('measure_line'), {
|
|
7425
|
+
polyline: {
|
|
7426
|
+
positions: new Cesium$6.CallbackProperty(() => this._previewCartesians, false),
|
|
7427
|
+
material: Cesium$6.Color.YELLOW,
|
|
7428
|
+
width: 2,
|
|
7429
|
+
clampToGround: true
|
|
7430
|
+
}
|
|
7431
|
+
});
|
|
7432
|
+
}
|
|
7433
|
+
this._previewLine.show = positions.length >= 2;
|
|
7434
|
+
}
|
|
7435
|
+
}
|
|
7436
|
+
|
|
7437
|
+
_ensureSegmentLabels(count) {
|
|
7438
|
+
// 移除多余的标注
|
|
7439
|
+
while (this._segmentLabelEntities.length > count) {
|
|
7440
|
+
const label = this._segmentLabelEntities.pop();
|
|
7441
|
+
this.removeTempEntity(label);
|
|
7442
|
+
}
|
|
7443
|
+
|
|
7444
|
+
// 创建缺少的标注
|
|
7445
|
+
while (this._segmentLabelEntities.length < count) {
|
|
7446
|
+
const label = this._createLabelEntity(
|
|
7447
|
+
this.generateId('measure_segment'),
|
|
7448
|
+
Cesium$6.Cartesian3.ZERO,
|
|
7449
|
+
''
|
|
7450
|
+
);
|
|
7451
|
+
this._segmentLabelEntities.push(label);
|
|
7452
|
+
}
|
|
7453
|
+
}
|
|
7454
|
+
|
|
7455
|
+
_createLabelEntity(id, position, text) {
|
|
7456
|
+
return this.createTempEntity(id, {
|
|
7457
|
+
position,
|
|
7458
|
+
label: {
|
|
7459
|
+
text,
|
|
7460
|
+
font: '14px Microsoft YaHei',
|
|
7461
|
+
fillColor: Cesium$6.Color.WHITE,
|
|
7462
|
+
outlineColor: Cesium$6.Color.BLACK,
|
|
7463
|
+
outlineWidth: 2,
|
|
7464
|
+
style: Cesium$6.LabelStyle.FILL_AND_OUTLINE,
|
|
7465
|
+
verticalOrigin: Cesium$6.VerticalOrigin.BOTTOM,
|
|
7466
|
+
horizontalOrigin: Cesium$6.HorizontalOrigin.CENTER,
|
|
7467
|
+
heightReference: Cesium$6.HeightReference.CLAMP_TO_GROUND,
|
|
7468
|
+
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
7469
|
+
pixelOffset: new Cesium$6.Cartesian2(0, -10)
|
|
7470
|
+
}
|
|
7471
|
+
});
|
|
7472
|
+
}
|
|
7473
|
+
|
|
7474
|
+
_addPointMarker(lonLat) {
|
|
7475
|
+
const point = this.createTempEntity(this.generateId('measure_point'), {
|
|
7476
|
+
position: Cesium$6.Cartesian3.fromDegrees(...lonLat),
|
|
7477
|
+
point: {
|
|
7478
|
+
color: Cesium$6.Color.YELLOW,
|
|
7479
|
+
pixelSize: 8,
|
|
7480
|
+
outlineColor: Cesium$6.Color.BLACK,
|
|
7481
|
+
outlineWidth: 1,
|
|
7482
|
+
heightReference: Cesium$6.HeightReference.CLAMP_TO_GROUND,
|
|
7483
|
+
disableDepthTestDistance: Number.POSITIVE_INFINITY
|
|
7484
|
+
}
|
|
7485
|
+
});
|
|
7486
|
+
this._pointEntities.push(point);
|
|
7487
|
+
}
|
|
7488
|
+
|
|
7489
|
+
_computeResult(positions) {
|
|
7490
|
+
if (this._measureType === MeasureType.DISTANCE) {
|
|
7491
|
+
let total = 0;
|
|
7492
|
+
for (let i = 0; i < positions.length - 1; i++) {
|
|
7493
|
+
total += GeoCalcUtil.calcDistance(positions[i], positions[i + 1]);
|
|
7494
|
+
}
|
|
7495
|
+
const fmt = this._formatDistance(total);
|
|
7496
|
+
return {
|
|
7497
|
+
type: MeasureType.DISTANCE,
|
|
7498
|
+
value: total,
|
|
7499
|
+
unit: fmt.unit,
|
|
7500
|
+
formatted: fmt.text,
|
|
7501
|
+
positions: positions.slice()
|
|
7502
|
+
};
|
|
7503
|
+
}
|
|
7504
|
+
|
|
7505
|
+
const area = GeoCalcUtil.calcArea(positions);
|
|
7506
|
+
const fmt = this._formatArea(area);
|
|
7507
|
+
return {
|
|
7508
|
+
type: MeasureType.AREA,
|
|
7509
|
+
value: area,
|
|
7510
|
+
unit: fmt.unit,
|
|
7511
|
+
formatted: fmt.text,
|
|
7512
|
+
positions: positions.slice()
|
|
7513
|
+
};
|
|
7514
|
+
}
|
|
7515
|
+
|
|
7516
|
+
_computeCentroid(cartesians) {
|
|
7517
|
+
const center = new Cesium$6.Cartesian3(0, 0, 0);
|
|
7518
|
+
for (const c of cartesians) {
|
|
7519
|
+
Cesium$6.Cartesian3.add(center, c, center);
|
|
7520
|
+
}
|
|
7521
|
+
return Cesium$6.Cartesian3.multiplyByScalar(center, 1 / cartesians.length, center);
|
|
7522
|
+
}
|
|
7523
|
+
|
|
7524
|
+
_formatDistance(meters) {
|
|
7525
|
+
if (meters >= 1000) {
|
|
7526
|
+
return { text: `${(meters / 1000).toFixed(2)} km`, unit: 'km' };
|
|
7527
|
+
}
|
|
7528
|
+
return { text: `${meters.toFixed(2)} m`, unit: 'm' };
|
|
7529
|
+
}
|
|
7530
|
+
|
|
7531
|
+
_formatArea(squareMeters) {
|
|
7532
|
+
if (squareMeters >= 1000000) {
|
|
7533
|
+
return { text: `${(squareMeters / 1000000).toFixed(3)} km²`, unit: 'km²' };
|
|
7534
|
+
}
|
|
7535
|
+
return { text: `${squareMeters.toFixed(2)} m²`, unit: 'm²' };
|
|
7536
|
+
}
|
|
7537
|
+
|
|
7538
|
+
_emitMeasureProgress(result) {
|
|
7539
|
+
if (this._options.onMeasureProgress) {
|
|
7540
|
+
this._options.onMeasureProgress(result);
|
|
7541
|
+
}
|
|
7542
|
+
}
|
|
7543
|
+
|
|
7544
|
+
_emitMeasureComplete(result) {
|
|
7545
|
+
if (this._options.onMeasureComplete) {
|
|
7546
|
+
this._options.onMeasureComplete(result);
|
|
7547
|
+
}
|
|
7548
|
+
}
|
|
7549
|
+
|
|
7550
|
+
_emitMeasureCancel() {
|
|
7551
|
+
if (this._options.onMeasureCancel) {
|
|
7552
|
+
this._options.onMeasureCancel();
|
|
7553
|
+
}
|
|
7554
|
+
}
|
|
7555
|
+
}
|
|
7556
|
+
|
|
7557
|
+
/**
|
|
7558
|
+
* 工具名称枚举
|
|
7559
|
+
*/
|
|
7560
|
+
const ToolName = {
|
|
7561
|
+
DRAW: 'draw',
|
|
7562
|
+
EDIT: 'edit',
|
|
7563
|
+
SELECT: 'select',
|
|
7564
|
+
DELETE: 'delete',
|
|
7565
|
+
MEASURE: 'measure'
|
|
7566
|
+
};
|
|
7567
|
+
|
|
7568
|
+
/**
|
|
7569
|
+
* 编辑器模块
|
|
7570
|
+
* 负责工具的注册、切换、激活管理
|
|
7571
|
+
*/
|
|
7572
|
+
class EditorModule {
|
|
7573
|
+
constructor(viewer, options = {}) {
|
|
7574
|
+
this.viewer = viewer;
|
|
7575
|
+
this.config = Config.getInstance().getConfig();
|
|
7576
|
+
this.graphicModule = null; // 依赖注入
|
|
7577
|
+
this.eventModule = null; // 依赖注入
|
|
7578
|
+
this.toolMap = new Map(); // 工具缓存
|
|
7579
|
+
this.currentTool = null; // 当前激活的工具
|
|
7580
|
+
this.currentToolName = null;
|
|
7581
|
+
this._isActive = false;
|
|
7582
|
+
}
|
|
7583
|
+
|
|
7584
|
+
/**
|
|
7585
|
+
* 设置依赖模块
|
|
7586
|
+
* @param {object} deps 依赖模块 { graphicModule, eventModule }
|
|
7587
|
+
*/
|
|
7588
|
+
setDependencies(deps) {
|
|
7589
|
+
this.graphicModule = deps.graphicModule;
|
|
7590
|
+
this.eventModule = deps.eventModule;
|
|
7591
|
+
return this;
|
|
7592
|
+
}
|
|
7593
|
+
|
|
7594
|
+
/**
|
|
7595
|
+
* 初始化编辑器,注册所有内置工具
|
|
7596
|
+
*/
|
|
7597
|
+
init() {
|
|
7598
|
+
// 注册内置工具
|
|
7599
|
+
this.registerTool(ToolName.DRAW, new DrawTool(this));
|
|
7600
|
+
this.registerTool(ToolName.EDIT, new EditTool(this));
|
|
7601
|
+
this.registerTool(ToolName.SELECT, new SelectTool(this));
|
|
7602
|
+
this.registerTool(ToolName.DELETE, new DeleteTool(this));
|
|
7446
7603
|
this.registerTool(ToolName.MEASURE, new MeasureTool(this));
|
|
7447
7604
|
|
|
7448
7605
|
return this;
|
|
@@ -8266,137 +8423,137 @@ class LocationBar extends BaseControl {
|
|
|
8266
8423
|
}
|
|
8267
8424
|
}
|
|
8268
8425
|
|
|
8269
|
-
const Cesium$4 = getCesium();
|
|
8270
|
-
|
|
8271
|
-
/**
|
|
8272
|
-
* 缩放控件
|
|
8273
|
-
* 提供放大/缩小两个按钮,默认挂到 SDK 统一工具栏(xs3d-viewer-toolbar)。
|
|
8274
|
-
*/
|
|
8275
|
-
class Zoom extends BaseControl {
|
|
8276
|
-
/**
|
|
8277
|
-
* @param {object} options
|
|
8278
|
-
* @param {number} [options.duration=0.5] 缩放动画时长(秒)
|
|
8279
|
-
*/
|
|
8280
|
-
constructor(options = {}) {
|
|
8281
|
-
super({
|
|
8282
|
-
type: 'zoom',
|
|
8283
|
-
...options
|
|
8284
|
-
});
|
|
8285
|
-
|
|
8286
|
-
this._duration = options.duration ?? 0.5;
|
|
8287
|
-
}
|
|
8288
|
-
|
|
8289
|
-
_createContainer() {
|
|
8290
|
-
const div = super._createContainer();
|
|
8291
|
-
div.className += ' xs3d-zoom';
|
|
8292
|
-
// 只有在统一工具栏内才使用 display: contents,让按钮直接参与工具栏 flex 布局;
|
|
8293
|
-
// 自定义容器挂载时保留正常 absolute 定位,支持 top/left/right/bottom。
|
|
8294
|
-
if (this._parentContainer?.classList?.contains('xs3d-viewer-toolbar')) {
|
|
8295
|
-
div.style.display = 'contents';
|
|
8296
|
-
}
|
|
8297
|
-
return div;
|
|
8298
|
-
}
|
|
8299
|
-
|
|
8300
|
-
_getParentContainer() {
|
|
8301
|
-
if (this._options.container) {
|
|
8302
|
-
return super._getParentContainer();
|
|
8303
|
-
}
|
|
8304
|
-
return this._getOrCreateToolbar();
|
|
8305
|
-
}
|
|
8306
|
-
|
|
8307
|
-
_mount() {
|
|
8308
|
-
this._clearAbsolutePositionIfInToolbar();
|
|
8309
|
-
|
|
8310
|
-
this._zoomInBtn = this._createButton('+', '放大');
|
|
8311
|
-
this._zoomOutBtn = this._createButton('-', '缩小');
|
|
8312
|
-
|
|
8313
|
-
this._container.appendChild(this._zoomInBtn);
|
|
8314
|
-
this._container.appendChild(this._zoomOutBtn);
|
|
8315
|
-
}
|
|
8316
|
-
|
|
8317
|
-
_createButton(label, title) {
|
|
8318
|
-
const btn = document.createElement('button');
|
|
8319
|
-
btn.type = 'button';
|
|
8320
|
-
btn.title = title;
|
|
8321
|
-
btn.className = 'cesium-button cesium-toolbar-button xs3d-zoom-button';
|
|
8322
|
-
btn.textContent = label;
|
|
8323
|
-
btn.style.width = '32px';
|
|
8324
|
-
btn.style.height = '32px';
|
|
8325
|
-
btn.style.lineHeight = '1';
|
|
8326
|
-
btn.style.fontSize = '18px';
|
|
8327
|
-
btn.style.fontWeight = 'bold';
|
|
8328
|
-
btn.style.display = 'flex';
|
|
8329
|
-
btn.style.alignItems = 'center';
|
|
8330
|
-
btn.style.justifyContent = 'center';
|
|
8331
|
-
btn.style.cursor = 'pointer';
|
|
8332
|
-
// 在统一工具栏内按 order 排列:指南针 -1,放大 1,缩小 2
|
|
8333
|
-
btn.style.order = label === '+' ? '1' : '2';
|
|
8334
|
-
return btn;
|
|
8335
|
-
}
|
|
8336
|
-
|
|
8337
|
-
_bindEvents() {
|
|
8338
|
-
this._addDomEvent(this._zoomInBtn, 'click', (e) => {
|
|
8339
|
-
e.stopPropagation();
|
|
8340
|
-
this._zoomIn();
|
|
8341
|
-
});
|
|
8342
|
-
|
|
8343
|
-
this._addDomEvent(this._zoomOutBtn, 'click', (e) => {
|
|
8344
|
-
e.stopPropagation();
|
|
8345
|
-
this._zoomOut();
|
|
8346
|
-
});
|
|
8347
|
-
}
|
|
8348
|
-
|
|
8349
|
-
_zoomIn() {
|
|
8350
|
-
this._zoomBy(1);
|
|
8351
|
-
}
|
|
8352
|
-
|
|
8353
|
-
_zoomOut() {
|
|
8354
|
-
this._zoomBy(-1);
|
|
8355
|
-
}
|
|
8356
|
-
|
|
8357
|
-
/**
|
|
8358
|
-
* 按地图层级步进缩放
|
|
8359
|
-
* @param {number} levelDelta 层级变化量,+1 放大一级,-1 缩小一级
|
|
8360
|
-
*/
|
|
8361
|
-
_zoomBy(levelDelta) {
|
|
8362
|
-
const camera = this._viewer.camera;
|
|
8363
|
-
const cartographic = camera.positionCartographic;
|
|
8364
|
-
const currentLevel = this._getZoomLevel();
|
|
8365
|
-
const targetLevel = Math.max(0, Math.min(24, currentLevel + levelDelta));
|
|
8366
|
-
const targetHeight = this._getHeightByZoomLevel(targetLevel);
|
|
8367
|
-
|
|
8368
|
-
camera.flyTo({
|
|
8369
|
-
destination: Cesium$4.Cartesian3.fromRadians(
|
|
8370
|
-
cartographic.longitude,
|
|
8371
|
-
cartographic.latitude,
|
|
8372
|
-
targetHeight
|
|
8373
|
-
),
|
|
8374
|
-
orientation: {
|
|
8375
|
-
heading: camera.heading,
|
|
8376
|
-
pitch: camera.pitch,
|
|
8377
|
-
roll: camera.roll
|
|
8378
|
-
},
|
|
8379
|
-
duration: this._duration
|
|
8380
|
-
});
|
|
8381
|
-
}
|
|
8382
|
-
|
|
8383
|
-
_getZoomLevel() {
|
|
8384
|
-
const positionCartographic = this._viewer.camera.positionCartographic;
|
|
8385
|
-
const surfaceCartesian = Cesium$4.Cartesian3.fromRadians(
|
|
8386
|
-
positionCartographic.longitude,
|
|
8387
|
-
positionCartographic.latitude,
|
|
8388
|
-
0
|
|
8389
|
-
);
|
|
8390
|
-
const distance = Cesium$4.Cartesian3.distance(this._viewer.camera.position, surfaceCartesian);
|
|
8391
|
-
if (!distance || distance <= 0 || !Number.isFinite(distance)) return 0;
|
|
8392
|
-
const equatorCircumference = 6378137 * 2 * Math.PI;
|
|
8393
|
-
return Math.max(0, Math.floor(Math.log2(equatorCircumference / distance)) + 1);
|
|
8394
|
-
}
|
|
8395
|
-
|
|
8396
|
-
_getHeightByZoomLevel(level) {
|
|
8397
|
-
const equatorCircumference = 6378137 * 2 * Math.PI;
|
|
8398
|
-
return equatorCircumference / Math.pow(2, Math.max(0, level - 1));
|
|
8399
|
-
}
|
|
8426
|
+
const Cesium$4 = getCesium();
|
|
8427
|
+
|
|
8428
|
+
/**
|
|
8429
|
+
* 缩放控件
|
|
8430
|
+
* 提供放大/缩小两个按钮,默认挂到 SDK 统一工具栏(xs3d-viewer-toolbar)。
|
|
8431
|
+
*/
|
|
8432
|
+
class Zoom extends BaseControl {
|
|
8433
|
+
/**
|
|
8434
|
+
* @param {object} options
|
|
8435
|
+
* @param {number} [options.duration=0.5] 缩放动画时长(秒)
|
|
8436
|
+
*/
|
|
8437
|
+
constructor(options = {}) {
|
|
8438
|
+
super({
|
|
8439
|
+
type: 'zoom',
|
|
8440
|
+
...options
|
|
8441
|
+
});
|
|
8442
|
+
|
|
8443
|
+
this._duration = options.duration ?? 0.5;
|
|
8444
|
+
}
|
|
8445
|
+
|
|
8446
|
+
_createContainer() {
|
|
8447
|
+
const div = super._createContainer();
|
|
8448
|
+
div.className += ' xs3d-zoom';
|
|
8449
|
+
// 只有在统一工具栏内才使用 display: contents,让按钮直接参与工具栏 flex 布局;
|
|
8450
|
+
// 自定义容器挂载时保留正常 absolute 定位,支持 top/left/right/bottom。
|
|
8451
|
+
if (this._parentContainer?.classList?.contains('xs3d-viewer-toolbar')) {
|
|
8452
|
+
div.style.display = 'contents';
|
|
8453
|
+
}
|
|
8454
|
+
return div;
|
|
8455
|
+
}
|
|
8456
|
+
|
|
8457
|
+
_getParentContainer() {
|
|
8458
|
+
if (this._options.container) {
|
|
8459
|
+
return super._getParentContainer();
|
|
8460
|
+
}
|
|
8461
|
+
return this._getOrCreateToolbar();
|
|
8462
|
+
}
|
|
8463
|
+
|
|
8464
|
+
_mount() {
|
|
8465
|
+
this._clearAbsolutePositionIfInToolbar();
|
|
8466
|
+
|
|
8467
|
+
this._zoomInBtn = this._createButton('+', '放大');
|
|
8468
|
+
this._zoomOutBtn = this._createButton('-', '缩小');
|
|
8469
|
+
|
|
8470
|
+
this._container.appendChild(this._zoomInBtn);
|
|
8471
|
+
this._container.appendChild(this._zoomOutBtn);
|
|
8472
|
+
}
|
|
8473
|
+
|
|
8474
|
+
_createButton(label, title) {
|
|
8475
|
+
const btn = document.createElement('button');
|
|
8476
|
+
btn.type = 'button';
|
|
8477
|
+
btn.title = title;
|
|
8478
|
+
btn.className = 'cesium-button cesium-toolbar-button xs3d-zoom-button';
|
|
8479
|
+
btn.textContent = label;
|
|
8480
|
+
btn.style.width = '32px';
|
|
8481
|
+
btn.style.height = '32px';
|
|
8482
|
+
btn.style.lineHeight = '1';
|
|
8483
|
+
btn.style.fontSize = '18px';
|
|
8484
|
+
btn.style.fontWeight = 'bold';
|
|
8485
|
+
btn.style.display = 'flex';
|
|
8486
|
+
btn.style.alignItems = 'center';
|
|
8487
|
+
btn.style.justifyContent = 'center';
|
|
8488
|
+
btn.style.cursor = 'pointer';
|
|
8489
|
+
// 在统一工具栏内按 order 排列:指南针 -1,放大 1,缩小 2
|
|
8490
|
+
btn.style.order = label === '+' ? '1' : '2';
|
|
8491
|
+
return btn;
|
|
8492
|
+
}
|
|
8493
|
+
|
|
8494
|
+
_bindEvents() {
|
|
8495
|
+
this._addDomEvent(this._zoomInBtn, 'click', (e) => {
|
|
8496
|
+
e.stopPropagation();
|
|
8497
|
+
this._zoomIn();
|
|
8498
|
+
});
|
|
8499
|
+
|
|
8500
|
+
this._addDomEvent(this._zoomOutBtn, 'click', (e) => {
|
|
8501
|
+
e.stopPropagation();
|
|
8502
|
+
this._zoomOut();
|
|
8503
|
+
});
|
|
8504
|
+
}
|
|
8505
|
+
|
|
8506
|
+
_zoomIn() {
|
|
8507
|
+
this._zoomBy(1);
|
|
8508
|
+
}
|
|
8509
|
+
|
|
8510
|
+
_zoomOut() {
|
|
8511
|
+
this._zoomBy(-1);
|
|
8512
|
+
}
|
|
8513
|
+
|
|
8514
|
+
/**
|
|
8515
|
+
* 按地图层级步进缩放
|
|
8516
|
+
* @param {number} levelDelta 层级变化量,+1 放大一级,-1 缩小一级
|
|
8517
|
+
*/
|
|
8518
|
+
_zoomBy(levelDelta) {
|
|
8519
|
+
const camera = this._viewer.camera;
|
|
8520
|
+
const cartographic = camera.positionCartographic;
|
|
8521
|
+
const currentLevel = this._getZoomLevel();
|
|
8522
|
+
const targetLevel = Math.max(0, Math.min(24, currentLevel + levelDelta));
|
|
8523
|
+
const targetHeight = this._getHeightByZoomLevel(targetLevel);
|
|
8524
|
+
|
|
8525
|
+
camera.flyTo({
|
|
8526
|
+
destination: Cesium$4.Cartesian3.fromRadians(
|
|
8527
|
+
cartographic.longitude,
|
|
8528
|
+
cartographic.latitude,
|
|
8529
|
+
targetHeight
|
|
8530
|
+
),
|
|
8531
|
+
orientation: {
|
|
8532
|
+
heading: camera.heading,
|
|
8533
|
+
pitch: camera.pitch,
|
|
8534
|
+
roll: camera.roll
|
|
8535
|
+
},
|
|
8536
|
+
duration: this._duration
|
|
8537
|
+
});
|
|
8538
|
+
}
|
|
8539
|
+
|
|
8540
|
+
_getZoomLevel() {
|
|
8541
|
+
const positionCartographic = this._viewer.camera.positionCartographic;
|
|
8542
|
+
const surfaceCartesian = Cesium$4.Cartesian3.fromRadians(
|
|
8543
|
+
positionCartographic.longitude,
|
|
8544
|
+
positionCartographic.latitude,
|
|
8545
|
+
0
|
|
8546
|
+
);
|
|
8547
|
+
const distance = Cesium$4.Cartesian3.distance(this._viewer.camera.position, surfaceCartesian);
|
|
8548
|
+
if (!distance || distance <= 0 || !Number.isFinite(distance)) return 0;
|
|
8549
|
+
const equatorCircumference = 6378137 * 2 * Math.PI;
|
|
8550
|
+
return Math.max(0, Math.floor(Math.log2(equatorCircumference / distance)) + 1);
|
|
8551
|
+
}
|
|
8552
|
+
|
|
8553
|
+
_getHeightByZoomLevel(level) {
|
|
8554
|
+
const equatorCircumference = 6378137 * 2 * Math.PI;
|
|
8555
|
+
return equatorCircumference / Math.pow(2, Math.max(0, level - 1));
|
|
8556
|
+
}
|
|
8400
8557
|
}
|
|
8401
8558
|
|
|
8402
8559
|
const Cesium$3 = getCesium();
|