效果

源码
// 辅助函数:计算两点间距离(米)
function getDistanceBetweenPoints(point1: Cesium.Cartesian3, point2: Cesium.Cartesian3): number {
return Cesium.Cartesian3.distance(point1, point2);
}
// 辅助函数:计算多点总距离(米)
function spaceDistance(points: Cesium.Cartesian3[]): string {
if (points.length < 2) return '0.000';
let totalDistance = 0;
for (let i = 0; i < points.length - 1; i++) {
totalDistance += getDistanceBetweenPoints(points[i], points[i + 1]);
}
return totalDistance.toFixed(3);
}
export default class CesiumMap {
// ... 原有属性省略 ...
// 距离测量相关属性
private isMeasuringDistance = false; // 是否正在距离测量
private measureDistancePositions: Cesium.Cartesian3[] = []; // 测量点坐标
private tempMeasurePositions: Cesium.Cartesian3[] = []; // 临时点(用于鼠标移动预览)
private distanceVertexEntities: Cesium.Entity[] = []; // 测量顶点实体
private distanceLineEntity: Cesium.Entity | null = null; // 测量线实体
private distanceLabelEntity: Cesium.Entity | null = null; // 距离标签实体
private measureTotalDistance = 0; // 总距离测量结果
private moveVertexEntity: Cesium.Entity | null = null; // 移动时的临时点
// ... 原有方法省略 ...
// ---------------------- 距离测量相关方法 ----------------------
/**
* 启动距离测量
*/
public startDistanceMeasure() {
this.clearDistanceMeasureEntities(); // 清除历史数据
this.isMeasuringDistance = true;
this.measureDistancePositions = [];
this.tempMeasurePositions = [];
this.viewer._element.style.cursor = 'crosshair'; // 测量时显示十字光标
console.log('开始距离测量:左键点击添加点,右键结束测量');
}
/**
* 处理距离测量的左键点击
*/
private handleDistanceMeasureLeftClick(e: Cesium.ScreenSpaceEventHandler.PositionedEvent) {
// 获取点击位置坐标
let position = this.viewer.scene.pickPosition(e.position);
if (!position) {
const ellipsoid = this.viewer.scene.globe.ellipsoid;
position = this.viewer.scene.camera.pickEllipsoid(e.position, ellipsoid);
}
if (!position) return;
this.measureDistancePositions.push(position);
// 第一个点:创建线和起点标识
if (this.measureDistancePositions.length === 1) {
this.createDistanceLineEntity();
this.createDistanceStartEntity();
return;
}
// 后续点:创建顶点和分段距离标签
this.createDistanceVertexEntity();
}
/**
* 处理距离测量的鼠标移动(实时预览)
*/
private handleDistanceMeasureMouseMove(e: Cesium.ScreenSpaceEventHandler.MotionEvent) {
if (!this.isMeasuringDistance || this.measureDistancePositions.length === 0) return;
// 获取鼠标移动位置坐标
let position = this.viewer.scene.pickPosition(e.endPosition);
if (!position) {
position = this.viewer.scene.camera.pickEllipsoid(
e.endPosition,
this.viewer.scene.globe.ellipsoid
);
}
if (!position) return;
// 更新临时点数组(用于预览线)
this.tempMeasurePositions = [...this.measureDistancePositions, position];
}
/**
* 结束距离测量(右键触发)
*/
private finishDistanceMeasure() {
if (this.measureDistancePositions.length < 2) {
// 少于2个点时视为取消
this.cancelDistanceMeasure();
return;
}
// 创建终点标识和总距离标签
this.createDistanceEndEntity();
this.isMeasuringDistance = false;
this.viewer._element.style.cursor = 'default';
this.measureTotalDistance = parseFloat(spaceDistance(this.measureDistancePositions));
console.log(`距离测量完成,总距离:${this.measureTotalDistance.toFixed(3)} 米`);
}
/**
* 取消距离测量
*/
private cancelDistanceMeasure() {
this.isMeasuringDistance = false;
this.clearDistanceMeasureEntities();
this.viewer._element.style.cursor = 'default';
console.log('已取消距离测量');
}
/**
* 清除距离测量相关实体
*/
private clearDistanceMeasureEntities() {
// 清除线实体
if (this.distanceLineEntity) {
this.viewer.entities.remove(this.distanceLineEntity);
this.distanceLineEntity = null;
}
// 清除所有顶点实体
this.distanceVertexEntities.forEach(entity => {
this.viewer.entities.remove(entity);
});
this.distanceVertexEntities = [];
// 清除临时移动点
if (this.moveVertexEntity) {
this.viewer.entities.remove(this.moveVertexEntity);
this.moveVertexEntity = null;
}
// 重置测量数据
this.measureDistancePositions = [];
this.tempMeasurePositions = [];
this.measureTotalDistance = 0;
}
/**
* 创建测量线实体(支持实时预览)
*/
private createDistanceLineEntity() {
this.distanceLineEntity = this.viewer.entities.add({
polyline: {
positions: new Cesium.CallbackProperty(() => {
// 优先显示临时点(鼠标移动预览),否则显示已选点
return this.tempMeasurePositions.length > 0
? this.tempMeasurePositions
: this.measureDistancePositions;
}, false),
width: 2,
material: Cesium.Color.YELLOW,
depthFailMaterial: Cesium.Color.YELLOW // 被遮挡时仍显示黄色
}
});
}
/**
* 创建起点实体(第一个点的标识)
*/
private createDistanceStartEntity() {
const startPoint = this.measureDistancePositions[0];
const entity = this.viewer.entities.add({
position: startPoint,
type: "MeasureDistanceStart",
billboard: {
image: "../../static/images/start.png", // 起点图标
scaleByDistance: new Cesium.NearFarScalar(300, 1, 1200, 0.4),
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM
},
point: {
color: Cesium.Color.FUCHSIA,
pixelSize: 6
}
});
this.distanceVertexEntities.push(entity);
}
/**
* 创建测量顶点实体(中间点和距离标签)
*/
private createDistanceVertexEntity() {
const currentIndex = this.measureDistancePositions.length - 1;
const currentPoint = this.measureDistancePositions[currentIndex];
const prevPoint = this.measureDistancePositions[currentIndex - 1];
// 计算当前段距离
const segmentDistance = getDistanceBetweenPoints(prevPoint, currentPoint);
// 创建顶点
const entity = this.viewer.entities.add({
position: currentPoint,
id: `MeasureDistanceVertex_${currentIndex}`,
type: "MeasureDistanceVertex",
point: {
color: Cesium.Color.FUCHSIA,
pixelSize: 8,
disableDepthTestDistance: 500
},
label: {
text: `${segmentDistance.toFixed(3)} 米`, // 显示当前段距离
scale: 0.5,
font: 'normal 24px Microsoft YaHei',
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5000),
scaleByDistance: new Cesium.NearFarScalar(1000, 1, 3000, 0.4),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
pixelOffset: new Cesium.Cartesian2(0, -30),
outlineWidth: 2,
outlineColor: Cesium.Color.WHITE
}
});
this.distanceVertexEntities.push(entity);
}
/**
* 创建终点实体(包含总距离标签)
*/
private createDistanceEndEntity() {
const endPoint = this.measureDistancePositions[this.measureDistancePositions.length - 1];
// 移除最后一个临时顶点的标签(替换为终点标签)
const lastVertexId = `MeasureDistanceVertex_${this.measureDistancePositions.length - 1}`;
const lastVertex = this.viewer.entities.getById(lastVertexId);
if (lastVertex) {
this.viewer.entities.remove(lastVertex);
}
// 清除移动时的临时点
if (this.moveVertexEntity) {
this.viewer.entities.remove(this.moveVertexEntity);
this.moveVertexEntity = null;
}
// 创建终点实体
const entity = this.viewer.entities.add({
position: endPoint,
type: "MeasureDistanceEnd",
billboard: {
image: "../../static/images/end.png", // 终点图标
scaleByDistance: new Cesium.NearFarScalar(300, 1, 1200, 0.4),
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM
},
point: {
color: Cesium.Color.FUCHSIA,
pixelSize: 6
},
label: {
text: `总距离:${spaceDistance(this.measureDistancePositions)} 米`, // 总距离
scale: 0.5,
font: 'normal 26px Microsoft YaHei',
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5000),
scaleByDistance: new Cesium.NearFarScalar(1000, 1, 3000, 0.4),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
pixelOffset: new Cesium.Cartesian2(0, -50),
outlineWidth: 2,
outlineColor: Cesium.Color.WHITE,
eyeOffset: new Cesium.Cartesian3(0, 0, -10)
}
});
this.distanceVertexEntities.push(entity);
}
// ---------------------- 事件绑定整合 ----------------------
/**
* 鼠标左键点击事件(整合距离测量逻辑)
*/
private mapLeftClick(e: Cesium.ScreenSpaceEventHandler.PositionedEvent) {
const r = this.getPickAndPosition(e.position);
// 优先处理距离测量
if (this.isMeasuringDistance) {
this.handleDistanceMeasureLeftClick(e);
return;
}
// 其次处理高度测量(原有逻辑)
if (this.isMeasuringHeight) {
this.handleMeasureLeftClick(e);
return;
}
// ... 其他左键逻辑 ...
}
/**
* 鼠标移动事件(整合距离测量逻辑)
*/
private mouseMoveEvent(e: Cesium.ScreenSpaceEventHandler.MotionEvent) {
const r = this.getPickAndPosition(e.endPosition);
// 优先处理距离测量
if (this.isMeasuringDistance) {
this.handleDistanceMeasureMouseMove(e);
return;
}
// 其次处理高度测量(原有逻辑)
if (this.isMeasuringHeight) {
this.handleMeasureMouseMove(e);
return;
}
// ... 其他鼠标移动逻辑 ...
}
/**
* 鼠标右键点击事件(整合距离测量逻辑)
*/
private mapRightClick(e: Cesium.ScreenSpaceEventHandler.PositionedEvent) {
const r = this.getPickAndPosition(e.position);
// 优先处理距离测量
if (this.isMeasuringDistance) {
this.finishDistanceMeasure();
return;
}
// 其次处理高度测量(原有逻辑)
if (this.isMeasuringHeight) {
this.cancelHeightMeasure();
return;
}
// ... 其他右键逻辑 ...
}
}
居于上一篇笔记高度测量的基础上,写的距离测量,一样使用
整合说明
-
属性隔离:
距离测量使用独立的属性(如isMeasuringDistance、measureDistancePositions),与高度测量属性完全隔离,避免状态冲突。 -
功能完善:
- 支持多点连续测量(左键点击添加点,右键结束)
- 实时预览测量线(鼠标移动时动态更新)
- 显示分段距离和总距离标签
- 起点 / 终点使用图标标识,增强视觉区分
-
事件优先级:
在mapLeftClick、mouseMoveEvent、mapRightClick中,优先判断距离测量状态,再处理高度测量,确保多测量模式不冲突。 -
潜在问题修复:
- 修复原
MeasureDistance类中mouseMoveEvent事件参数类型错误(使用e.endPosition而非e.startPosition) - 完善资源清理逻辑,避免实体残留
- 统一鼠标样式控制(测量时为十字光标,结束后恢复默认)
- 修复原
使用方法
// 启动距离测量(绑定到按钮点击)
document.getElementById('startDistanceMeasureBtn').addEventListener('click', () => {
cesiumMap.startDistanceMeasure();
});

1390

被折叠的 条评论
为什么被折叠?



