export default class DrawLineTool { /** * 构造函数 * param {Object} cesium - Cesium 对象 * param {Object} viewer - Cesium Viewer 实例 */ constructor(cesium, viewer) { this.Cesium cesium; this.viewer viewer; this.handler null; this.isDrawing false; } /** * 开始绘制 * returns {PromiseArray{lon: number, lat: number}} 返回经纬度数组 */ startDraw() { const { Cesium, viewer } this; return new Promise((resolve, reject) { if (this.isDrawing) { console.warn(正在绘制中...); return; } this.isDrawing true; let tempEntities []; let firstPointPos null; // 动态更新虚线的位置回调 let currentMousePos null; let dynamicPositions new Cesium.CallbackProperty(() { if (firstPointPos currentMousePos) { return [firstPointPos, currentMousePos]; } return null; }, false); // 1. 鼠标变十字 viewer.canvas.style.cursor crosshair; if (!this.handler || this.handler.isDestroyed()) { this.handler new Cesium.ScreenSpaceEventHandler(viewer.canvas); } // 辅助方法笛卡尔坐标转经纬度 const getLonLat (cartesian) { const cartographic Cesium.Cartographic.fromCartesian(cartesian); return { lon: Cesium.Math.toDegrees(cartographic.longitude), lat: Cesium.Math.toDegrees(cartographic.latitude) }; }; // 2. 监听鼠标移动 this.handler.setInputAction((movement) { if (!this.isDrawing || !firstPointPos) return; // 这里的 pickEllipsoid 获取椭球面坐标对于贴地已经足够 const cartesian viewer.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid); if (cartesian) { currentMousePos cartesian; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); // 3. 监听点击事件 this.handler.setInputAction((click) { const cartesian viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid); if (!cartesian) return; // 第一次点击 if (!firstPointPos) { firstPointPos cartesian; // [修复重点]绘制不会被遮挡的、完整显示的起点 const pointEntity viewer.entities.add({ position: cartesian, point: { pixelSize: 12, color: Cesium.Color.YELLOW, outlineColor: Cesium.Color.BLACK, outlineWidth: 3, // 关键属性1贴地解决高度偏差问题 heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键属性2禁用深度测试防止点被地形/模型遮挡显示不全 // 设置为 Number.POSITIVE_INFINITY 表示无论距离多远都禁用深度测试 disableDepthTestDistance: Number.POSITIVE_INFINITY } }); tempEntities.push(pointEntity); // 绘制跟随鼠标的黄色虚线 const dashLineEntity viewer.entities.add({ polyline: { positions: dynamicPositions, width: 3, material: new Cesium.PolylineDashMaterialProperty({ color: Cesium.Color.YELLOW, dashLength: 10.0 }), // 线也需要贴地否则会穿入地下 clampToGround: true } }); tempEntities.push(dashLineEntity); } // 第二次点击 else { const secondPointPos cartesian; // 清理临时图形点和虚线 tempEntities.forEach(entity { viewer.entities.remove(entity); }); // 绘制最终的实线 viewer.entities.add({ polyline: { positions: [firstPointPos, secondPointPos], width: 3, material: Cesium.Color.YELLOW, clampToGround: true } }); // 结束绘制状态 this.destroy(); // 返回结果 resolve([ getLonLat(firstPointPos), getLonLat(secondPointPos) ]); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }); } /** * 销毁资源并恢复状态 */ destroy() { this.isDrawing false; this.viewer.canvas.style.cursor default; if (this.handler) { this.handler.destroy(); this.handler null; } } }使用// 1. 初始化工具类 const drawTool new DrawLineTool(Cesium, viewer); // 2. 调用绘制方法 async function handleDraw() { console.log(开始绘制请点击两点...); try { // 等待用户点击两点 const coordinates await drawTool.startDraw(); console.log(绘制完成坐标数据, coordinates); // 可以在这里进行后续业务逻辑处理 } catch (error) { console.error(绘制出错:, error); } }
Cesium@1.138中点击绘制直线
export default class DrawLineTool { /** * 构造函数 * param {Object} cesium - Cesium 对象 * param {Object} viewer - Cesium Viewer 实例 */ constructor(cesium, viewer) { this.Cesium cesium; this.viewer viewer; this.handler null; this.isDrawing false; } /** * 开始绘制 * returns {PromiseArray{lon: number, lat: number}} 返回经纬度数组 */ startDraw() { const { Cesium, viewer } this; return new Promise((resolve, reject) { if (this.isDrawing) { console.warn(正在绘制中...); return; } this.isDrawing true; let tempEntities []; let firstPointPos null; // 动态更新虚线的位置回调 let currentMousePos null; let dynamicPositions new Cesium.CallbackProperty(() { if (firstPointPos currentMousePos) { return [firstPointPos, currentMousePos]; } return null; }, false); // 1. 鼠标变十字 viewer.canvas.style.cursor crosshair; if (!this.handler || this.handler.isDestroyed()) { this.handler new Cesium.ScreenSpaceEventHandler(viewer.canvas); } // 辅助方法笛卡尔坐标转经纬度 const getLonLat (cartesian) { const cartographic Cesium.Cartographic.fromCartesian(cartesian); return { lon: Cesium.Math.toDegrees(cartographic.longitude), lat: Cesium.Math.toDegrees(cartographic.latitude) }; }; // 2. 监听鼠标移动 this.handler.setInputAction((movement) { if (!this.isDrawing || !firstPointPos) return; // 这里的 pickEllipsoid 获取椭球面坐标对于贴地已经足够 const cartesian viewer.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid); if (cartesian) { currentMousePos cartesian; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); // 3. 监听点击事件 this.handler.setInputAction((click) { const cartesian viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid); if (!cartesian) return; // 第一次点击 if (!firstPointPos) { firstPointPos cartesian; // [修复重点]绘制不会被遮挡的、完整显示的起点 const pointEntity viewer.entities.add({ position: cartesian, point: { pixelSize: 12, color: Cesium.Color.YELLOW, outlineColor: Cesium.Color.BLACK, outlineWidth: 3, // 关键属性1贴地解决高度偏差问题 heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键属性2禁用深度测试防止点被地形/模型遮挡显示不全 // 设置为 Number.POSITIVE_INFINITY 表示无论距离多远都禁用深度测试 disableDepthTestDistance: Number.POSITIVE_INFINITY } }); tempEntities.push(pointEntity); // 绘制跟随鼠标的黄色虚线 const dashLineEntity viewer.entities.add({ polyline: { positions: dynamicPositions, width: 3, material: new Cesium.PolylineDashMaterialProperty({ color: Cesium.Color.YELLOW, dashLength: 10.0 }), // 线也需要贴地否则会穿入地下 clampToGround: true } }); tempEntities.push(dashLineEntity); } // 第二次点击 else { const secondPointPos cartesian; // 清理临时图形点和虚线 tempEntities.forEach(entity { viewer.entities.remove(entity); }); // 绘制最终的实线 viewer.entities.add({ polyline: { positions: [firstPointPos, secondPointPos], width: 3, material: Cesium.Color.YELLOW, clampToGround: true } }); // 结束绘制状态 this.destroy(); // 返回结果 resolve([ getLonLat(firstPointPos), getLonLat(secondPointPos) ]); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }); } /** * 销毁资源并恢复状态 */ destroy() { this.isDrawing false; this.viewer.canvas.style.cursor default; if (this.handler) { this.handler.destroy(); this.handler null; } } }使用// 1. 初始化工具类 const drawTool new DrawLineTool(Cesium, viewer); // 2. 调用绘制方法 async function handleDraw() { console.log(开始绘制请点击两点...); try { // 等待用户点击两点 const coordinates await drawTool.startDraw(); console.log(绘制完成坐标数据, coordinates); // 可以在这里进行后续业务逻辑处理 } catch (error) { console.error(绘制出错:, error); } }