一、创作来源
1、cesium的entity绘制线
2、不使用entity的情况下,使用自定义的primitive来动态绘制线
3、结合上一篇文章的动态绘制线,执行动态线的更新
二、ScreenSpaceEventHandler
1、概念
cesium中的用户输入事件:ScreenSpaceEventHandler,处理用户输入事件。可以添加自定义功能以在用户输入时执行。
API地址:CesiumApi传送门
2、事件类型
红色部分为常用类型
3、方法
destroy()
移除此对象持有的侦听器。
isDestroyed()
如果此对象被销毁,则返回 true;否则为false。
getInputAction(type, modifier)
返回要在输入事件上执行的函数。
removeInputAction(type, modifier)
删除要在输入事件上执行的函数。
setInputAction(action, type, modifier)
设置要在输入事件上执行的功能。
4、示例
a、左键单击
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((event) => {
console.log('shift + 左键单击', event.position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
b、鼠标移动事件
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((event) => {
console.log('shift + 鼠标移动', event.position);
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
c、右键事件
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((event) => {
console.log('shift + 右键单击', event.position);
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
三、编写步骤
1、创建绘制线的类
包括构造函数、绘图函数以及销毁函数
import { Viewer, ScreenSpaceEventHandler } from "cesium";
export default class DrawPolylineTool {
/**
* 构造函数
* @param {Viewer} viewer
*/
constructor(viewer) {
/**
* 地球视图
* @type {Viewer}
* @private
*/
this._viewer = viewer;
/**
* 线对象
* @type {CustomPolylinePrimitive}
* @private
*/
this._primitive = undefined;
/**
* 事件
* @type {ScreenSpaceEventHandler}
* @private
*/
this._handler = undefined;
}
draw() {}
destroy() {}
}
2、事件确认
鼠标点击事件、移动事件、右键结束编辑
import { Viewer, ScreenSpaceEventHandler, ScreenSpaceEventType } from "cesium";
export default class DrawPolylineTool {
/**
* 构造函数
* @param {Viewer} viewer
*/
constructor(viewer) {
/**
* 地球视图
* @type {Viewer}
* @private
*/
this._viewer = viewer;
/**
* 线对象
* @type {CustomPolylinePrimitive}
* @private
*/
this._primitive = undefined;
/**
* 事件
* @type {ScreenSpaceEventHandler}
* @private
*/
this._handler = undefined;
}
/**
* 绘图
*/
draw() {
this._handler = new ScreenSpaceEventHandler(this._viewer.canvas);
this._handler.setInputAction((event) => {
console.log("左键单机事件");
}, ScreenSpaceEventType.LEFT_CLICK);
this._handler.setInputAction((event) => {
console.log("鼠标移动事件");
}, ScreenSpaceEventType.MOUSE_MOVE);
this._handler.setInputAction((event) => {
console.log("鼠标右键单机事件");
}, ScreenSpaceEventType.RIGHT_CLICK);
}
/**
* 销毁
*/
destroy() {
if (this._handler) {
this._handler.isDestroyed() && this._handler.destroy();
this._handler = null;
}
}
}
3、点位变动逻辑
=>初始为空的数组
=>点击后当为空时直接push,当有两个点时,先pop后push
=>移动:当只有一个点时直接push,当点位数大于1的时候,先移除后push
=>右键直接结束
4、代码实现
1、屏幕坐标转地球坐标
/**
* 获取地图点位
* @param {Cartesian2} screenPosition 屏幕坐标
* @param {Viewer} viewer 地图
* @returns {Cartesian3} 地图三维坐标
*/
export const pickPosition = (screenPosition, viewer) => {
let ray = viewer.camera.getPickRay(screenPosition);
return viewer.scene.globe.pick(ray, viewer.scene);
};
2、鼠标事件代码
/**
* 绘图
*/
draw() {
this._handler = new ScreenSpaceEventHandler(this._viewer.canvas);
let positions = [];
let flag = this;
this._handler.setInputAction((event) => {
console.log("左键单机事件");
let position = pickPosition(event.position, flag._viewer);
if (position) {
if (positions.length === 0) {
positions.push(position);
} else {
positions.pop();
positions.push(position);
}
}
}, ScreenSpaceEventType.LEFT_CLICK);
this._handler.setInputAction((event) => {
console.log("鼠标移动事件");
let position = pickPosition(event.endPosition, flag._viewer);
if (position) {
if (positions.length === 1) {
positions.push(position);
} else if (positions.length > 1) {
positions.pop();
positions.push(position);
}
}
}, ScreenSpaceEventType.MOUSE_MOVE);
this._handler.setInputAction((event) => {
console.log("鼠标右键单机事件");
this._primitive = undefined;
positions = [];
}, ScreenSpaceEventType.RIGHT_CLICK);
}
3、渲染线代码
/**
* 绘图
*/
draw() {
this._handler = new ScreenSpaceEventHandler(this._viewer.canvas);
let positions = [];
let flag = this;
this._handler.setInputAction((event) => {
console.log("左键单机事件");
let position = pickPosition(event.position, flag._viewer);
if (position) {
if (positions.length === 0) {
positions.push(position);
flag._primitive = new CustomPolylinePrimitive();
this._viewer.scene.primitives.add(this._primitive);
} else {
let moveP = positions.pop();
positions.push(position, moveP);
}
if (flag._primitive) {
flag._primitive.updateProperty({
positions: [...positions],
complete: false,
});
}
}
}, ScreenSpaceEventType.LEFT_CLICK);
this._handler.setInputAction((event) => {
console.log("鼠标移动事件");
let position = pickPosition(event.endPosition, flag._viewer);
if (position) {
if (positions.length === 1) {
positions.push(position);
} else if (positions.length > 1) {
positions.pop();
positions.push(position);
}
if (flag._primitive) {
flag._primitive.updateProperty({
positions: [...positions],
complete: false,
});
}
}
}, ScreenSpaceEventType.MOUSE_MOVE);
this._handler.setInputAction((event) => {
console.log("鼠标右键单机事件");
if (flag._primitive) {
flag._primitive.updateProperty({
positions: [...positions],
complete: false,
});
}
this._primitive = undefined;
positions = [];
}, ScreenSpaceEventType.RIGHT_CLICK);
}
4、测试
let tool = new DrawPolylineTool(viewer);
tool.draw();
四、演示结果
五、全部代码
import { Viewer, ScreenSpaceEventHandler, ScreenSpaceEventType } from "cesium";
import { pickPosition } from "@/components/MilitaryPlot/utils/PlotUtils";
import CustomPolylinePrimitive from "@/components/entity/CustomPolylinePrimitive";
export default class DrawPolylineTool {
/**
* 构造函数
* @param {Viewer} viewer
*/
constructor(viewer) {
/**
* 地球视图
* @type {Viewer}
* @private
*/
this._viewer = viewer;
/**
* 线对象
* @type {CustomPolylinePrimitive}
* @private
*/
this._primitive = undefined;
/**
* 事件
* @type {ScreenSpaceEventHandler}
* @private
*/
this._handler = undefined;
}
/**
* 绘图
*/
draw() {
this._handler = new ScreenSpaceEventHandler(this._viewer.canvas);
let positions = [];
let flag = this;
this._handler.setInputAction((event) => {
console.log("左键单机事件");
let position = pickPosition(event.position, flag._viewer);
if (position) {
if (positions.length === 0) {
positions.push(position);
flag._primitive = new CustomPolylinePrimitive();
this._viewer.scene.primitives.add(this._primitive);
} else {
let moveP = positions.pop();
positions.push(position, moveP);
}
if (flag._primitive) {
flag._primitive.updateProperty({
positions: [...positions],
complete: false,
});
}
}
}, ScreenSpaceEventType.LEFT_CLICK);
this._handler.setInputAction((event) => {
console.log("鼠标移动事件");
let position = pickPosition(event.endPosition, flag._viewer);
if (position) {
if (positions.length === 1) {
positions.push(position);
} else if (positions.length > 1) {
positions.pop();
positions.push(position);
}
if (flag._primitive) {
flag._primitive.updateProperty({
positions: [...positions],
complete: false,
});
}
}
}, ScreenSpaceEventType.MOUSE_MOVE);
this._handler.setInputAction((event) => {
console.log("鼠标右键单机事件");
if (flag._primitive) {
flag._primitive.updateProperty({
positions: [...positions],
complete: false,
});
}
this._primitive = undefined;
positions = [];
}, ScreenSpaceEventType.RIGHT_CLICK);
}
/**
* 销毁
*/
destroy() {
if (this._handler) {
this._handler.isDestroyed() && this._handler.destroy();
this._handler = null;
}
}
}