【CesiumJS入门】(7)绘制多段线(动态实时画线)
前言
如果你是在寻求解决方案,可以直接用cesium-draw这个插件。
鼠标左键添加点、右键完成绘制,单击右侧弹窗关闭按钮清空绘制。参考沙盒示例:Drawing on Terrain

直接上代码了
/** @Date: 2023-07-12 18:47:18* @LastEditors: ReBeX 420659880@qq.com* @LastEditTime: 2023-07-16 16:26:19* @FilePath: \cesium-tyro-blog\src\utils\Entity\Draw\polyline.js* @Description: 绘制多段线*/
import { viewer } from '@/utils/createCesium.js' // 引入地图对象import * as Cesium from 'cesium'export class PolylineDrawer {activeLine // 动态线activePoint // 动态点constructor(callback) {if (!PolylineDrawer.instance) { // 首次使用构造器实例this.callback = callback// 新建DataSource用来管理entitiesthis.nodeCollection = new Cesium.CustomDataSource("nodeEntityCollection");this.lineCollection = new Cesium.CustomDataSource("lineEntityCollection");viewer.dataSources.add(this.nodeCollection);viewer.dataSources.add(this.lineCollection);this.addHandler = this.createScreenSpaceEventHandler(); // 新增点位的交互句柄this.finHandler = this.createScreenSpaceEventHandler(); // 完成点选的交互句柄this.moveHandler = this.createScreenSpaceEventHandler(); // 完成点选的交互句柄viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); // 关闭左键双击事件PolylineDrawer.instance = this // 将this挂载到PolylineDrawer这个类的instance属性上}return PolylineDrawer.instance // 返回单例}// 返回交互句柄createScreenSpaceEventHandler() {return new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);}// 开始绘制start() {this.activePoint = this.createCursorPoint({ x: 0, y: 0, z: 0 }); // 默认显示动态点this.activePoint.position.setValue(undefined); // 隐藏指针点let pointList = []; // 初始化当前的线坐标数组// 绘制打点时的事件this.addHandler.setInputAction(event => {// 获取地形表面经纬度和高度const ray = viewer.camera.getPickRay(event.position || event.endPosition);const cartesian = viewer.scene.globe.pick(ray, viewer.scene);// // 获取椭球体表面的经纬度// const cartesian = viewer.camera.pickEllipsoid(event.position || event.endPosition, viewer.scene.globe.ellipsoid);if (Cesium.defined(cartesian)) {this.nodeCollection.entities.add(this.createNodePoint(cartesian)); // 添加节点// 绘制动态线:首次点击后触发if (pointList.length === 0) {pointList.push(cartesian) // 加入一个动态点const dynamicPositions = new Cesium.CallbackProperty(() => pointList.slice(-2), false);this.activeLine = this.createActiveLine(dynamicPositions); // 添加动态线}// 绘制线:点击2次后触发if (pointList.length === 1) {const dynamicPositions = new Cesium.CallbackProperty(() => pointList.slice(0, -1), false);this.lineCollection.entities.add(this.createNormalLine(dynamicPositions)) // 绘制线}pointList.push(cartesian);}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);// 鼠标移动时的事件this.moveHandler.setInputAction(event => {if (Cesium.defined(this.activePoint)) {// 获取地形表面经纬度和高度const ray = viewer.camera.getPickRay(event.endPosition || event.position);const cartesian = viewer.scene.globe.pick(ray, viewer.scene);// // 获取椭球体表面的经纬度// const cartesian = viewer.camera.pickEllipsoid(event.position || event.endPosition, viewer.scene.globe.ellipsoid);if (Cesium.defined(cartesian)) {this.activePoint.position.setValue(cartesian);if (pointList.length > 0) {pointList.pop();pointList.push(cartesian);}} else {this.activePoint.position.setValue(undefined); // 指针超出地球外了就隐藏指针点}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 完成绘制时的事件this.finHandler.setInputAction(event => {if (pointList.length < 2) { // 一个节点都没添加alert('请至少选2个点')} else if (pointList.length < 3) { // 如果点击了一次,就会马上创建点和线,那么就需要清除掉最末的entity,否则会污染数据集alert('请至少选2个点')this.nodeCollection.entities.remove(this.nodeCollection.entities.values[this.nodeCollection.entities.values.length - 1]);this.lineCollection.entities.remove(this.lineCollection.entities.values[this.lineCollection.entities.values.length - 1]);}this.stop()this.start()}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}// 结束绘制stop() {this.addHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)this.moveHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)this.finHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)viewer.entities.remove(this.activeLine); // 移除动态线viewer.entities.remove(this.activePoint); // 移除动态点this.callback && this.callback(this.lineCollection) // 如果需要,就把线集合给回调函数}// 绘制:动态点createCursorPoint(cartesian, show) {const point = viewer.entities.add({position: cartesian,point: {pixelSize: 5, // 像素大小,默认: 1 heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 表示相对于地形的位置color: Cesium.Color.SKYBLUE, // 默认: 白disableDepthTestDistance: Number.POSITIVE_INFINITY,},});return point;}// 绘制:节点createNodePoint(cartesian) {return new Cesium.Entity({position: cartesian,point: {pixelSize: 3, // 像素大小,默认: 1 heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 表示相对于地形的位置color: Cesium.Color.BLUE, // 默认: 白disableDepthTestDistance: Number.POSITIVE_INFINITY,}})}// 绘制:动态线createActiveLine(list) {const shape = viewer.entities.add({polyline: {positions: list,clampToGround: true,width: 2,material: new Cesium.PolylineDashMaterialProperty({color: Cesium.Color.RED,dashLength: 10,dashPattern: 255,}),},});return shape;}// 绘制:线createNormalLine(list) {return new Cesium.Entity({polyline: {positions: list,clampToGround: true,width: 2,},})}// 销毁:清空绘制与监听destroy() {this.stop()this.nodeCollection.entities.removeAll()this.lineCollection.entities.removeAll()}
}
调用:
// 引入
import { PolylineDrawer } from '@/utils/Entity/Draw/polyline.js'// 声明实例:无回调函数
const polylineDrawer = new PolylineDrawer();// 声明实例:有回调函数
const polylineDrawer = new PolylineDrawer((lineList)=> {console.log(lineList)
);// 开始绘制
polylineDrawer.start()// 结束绘制并清除所有点和线
polylineDrawer.destroy()
补充:修改点或线的样式
如果你需要修改节点或动态点的样式,你可以参考如下Entity Point相关参数:
const PointOptions = {show: true,pixelSize: 10, // 像素大小,默认: 1 heightReference: Cesium.HeightReference.NONE, // 表示相对于地形的位置color: Cesium.Color.SKYBLUE, // 默认: 白outlineColor: Cesium.Color.BLACK, // 边框颜色,默认: 黑outlineWidth: 3, // 边框宽度,默认: 0scaleByDistance: new Cesium.NearFarScalar(1.0e3, 10.0, 2.0e3, 1.0), // 随着相机的距离改变大小translucencyByDistance: new Cesium.NearFarScalar(1.0e3,1.0,2.0e3,0.1), // 随着相机的距离改变透明度distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0,2.0e3), // 在指定距离区间内可见// 获取或设置与相机的距离,在深度处禁用深度测试// 设置为零时,将始终应用深度测试。设置为Number.POSITIVE_INFINITY时,永远不会应用深度测试。disableDepthTestDistance: Number.POSITIVE_INFINITY,}
如果你需要修改线或动态线的样式,你可以参考如下Entity Polyline相关参数:
const LineOptions = {show: true,// 定义线条的 Cartesian3 位置的数组positions: Cesium.Cartesian3.fromDegreesArray([-75, 35, -125, 35]),width: 5,// 如果arcType不是ArcType.NONE,则指定每个纬度和经度之间的角距离granularity: Cesium.Math.RADIANS_PER_DEGREE,material: Cesium.Color.RED,// 线低于地形时用于绘制折线的材质depthFailMaterial: Cesium.Color.WHITE,// 折线段必须遵循的线型arcType: Cesium.ArcType.GEODESIC,clampToGround: true, // 是否贴地shadows: Cesium.ShadowMode.DISABLED, // 折线是投射还是接收光源的阴影distanceDisplayCondition: new Cesium.DistanceDisplayCondition(1.0e3,2.0e3),// 在地面上时将对地形,3D tiles还是对两者进行分类 type:ClassificationType default:ClassificationType.BOTH// TERRAIN 将仅对地形进行分类;CESIUM_3D_TILE 将仅对3D Tiles进行分类;BOTH 将同时对Terrain和3D Tiles进行分类。classificationType: Cesium.ClassificationType.BOTH,// 指定用于订购地面几何形状的z索引。仅在多边形为常数且未指定高度或拉伸高度的情况下才有效 type:ConstantPropertyzIndex: 0,}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
