第14章 - 交互与事件处理
第14章:交互与事件处理
14.1 事件处理器
14.1.1 ScreenSpaceEventHandler
// 创建事件处理器
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
// 鼠标事件类型
const eventTypes = {
LEFT_DOWN: Cesium.ScreenSpaceEventType.LEFT_DOWN,
LEFT_UP: Cesium.ScreenSpaceEventType.LEFT_UP,
LEFT_CLICK: Cesium.ScreenSpaceEventType.LEFT_CLICK,
LEFT_DOUBLE_CLICK: Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
RIGHT_DOWN: Cesium.ScreenSpaceEventType.RIGHT_DOWN,
RIGHT_UP: Cesium.ScreenSpaceEventType.RIGHT_UP,
RIGHT_CLICK: Cesium.ScreenSpaceEventType.RIGHT_CLICK,
MIDDLE_DOWN: Cesium.ScreenSpaceEventType.MIDDLE_DOWN,
MIDDLE_UP: Cesium.ScreenSpaceEventType.MIDDLE_UP,
MIDDLE_CLICK: Cesium.ScreenSpaceEventType.MIDDLE_CLICK,
MOUSE_MOVE: Cesium.ScreenSpaceEventType.MOUSE_MOVE,
WHEEL: Cesium.ScreenSpaceEventType.WHEEL,
PINCH_START: Cesium.ScreenSpaceEventType.PINCH_START,
PINCH_MOVE: Cesium.ScreenSpaceEventType.PINCH_MOVE,
PINCH_END: Cesium.ScreenSpaceEventType.PINCH_END
};
// 键盘修饰符
const modifiers = {
SHIFT: Cesium.KeyboardEventModifier.SHIFT,
CTRL: Cesium.KeyboardEventModifier.CTRL,
ALT: Cesium.KeyboardEventModifier.ALT
};
14.1.2 注册事件
// 左键点击
handler.setInputAction(function(click) {
console.log('点击位置:', click.position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 鼠标移动
handler.setInputAction(function(movement) {
console.log('起点:', movement.startPosition);
console.log('终点:', movement.endPosition);
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// 滚轮
handler.setInputAction(function(delta) {
console.log('滚轮:', delta);
}, Cesium.ScreenSpaceEventType.WHEEL);
// 组合键(Ctrl + 点击)
handler.setInputAction(function(click) {
console.log('Ctrl + 点击');
}, Cesium.ScreenSpaceEventType.LEFT_CLICK, Cesium.KeyboardEventModifier.CTRL);
// 移除事件
handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 销毁处理器
handler.destroy();
14.2 对象拾取
14.2.1 基本拾取
handler.setInputAction(function(click) {
// 拾取第一个对象
const pickedObject = viewer.scene.pick(click.position);
if (Cesium.defined(pickedObject)) {
// Entity
if (pickedObject.id instanceof Cesium.Entity) {
const entity = pickedObject.id;
console.log('选中 Entity:', entity.name);
}
// 3D Tiles
if (pickedObject.primitive instanceof Cesium.Cesium3DTileset) {
console.log('选中 3D Tiles');
if (pickedObject.getProperty) {
console.log('属性:', pickedObject.getPropertyIds());
}
}
// Primitive
if (pickedObject.primitive instanceof Cesium.Primitive) {
console.log('选中 Primitive:', pickedObject.id);
}
}
// 拾取位置(世界坐标)
const worldPosition = viewer.scene.pickPosition(click.position);
if (Cesium.defined(worldPosition)) {
const cartographic = Cesium.Cartographic.fromCartesian(worldPosition);
console.log('位置:', {
lon: Cesium.Math.toDegrees(cartographic.longitude),
lat: Cesium.Math.toDegrees(cartographic.latitude),
height: cartographic.height
});
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 穿透拾取(获取所有对象)
const pickedObjects = viewer.scene.drillPick(click.position);
console.log('拾取对象数:', pickedObjects.length);
14.2.2 高亮与选中
// 高亮管理器
class HighlightManager {
constructor(viewer) {
this.viewer = viewer;
this.highlighted = null;
this.selected = null;
this.highlightColor = Cesium.Color.YELLOW.withAlpha(0.5);
this.selectColor = Cesium.Color.CYAN;
this.originalColors = new Map();
}
highlight(object) {
// 清除之前的高亮
if (this.highlighted && this.highlighted !== this.selected) {
this.restoreColor(this.highlighted);
}
if (object && object !== this.selected) {
this.saveColor(object);
this.setColor(object, this.highlightColor);
this.highlighted = object;
} else {
this.highlighted = null;
}
}
select(object) {
// 清除之前的选中
if (this.selected) {
this.restoreColor(this.selected);
}
if (object) {
this.saveColor(object);
this.setColor(object, this.selectColor);
this.selected = object;
} else {
this.selected = null;
}
}
saveColor(object) {
if (object.id instanceof Cesium.Entity) {
const entity = object.id;
if (entity.polygon) {
this.originalColors.set(object, entity.polygon.material.getValue().color.clone());
}
}
}
restoreColor(object) {
const color = this.originalColors.get(object);
if (color) {
this.setColor(object, color);
this.originalColors.delete(object);
}
}
setColor(object, color) {
if (object.id instanceof Cesium.Entity) {
const entity = object.id;
if (entity.polygon) {
entity.polygon.material = color;
}
}
}
}
// 使用
const highlightManager = new HighlightManager(viewer);
handler.setInputAction(function(movement) {
const object = viewer.scene.pick(movement.endPosition);
highlightManager.highlight(object);
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
handler.setInputAction(function(click) {
const object = viewer.scene.pick(click.position);
highlightManager.select(object);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
14.3 绘图工具
14.3.1 点绘制
class PointDrawTool {
constructor(viewer) {
this.viewer = viewer;
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
this.points = [];
}
start(callback) {
this.handler.setInputAction((click) => {
const position = this.viewer.scene.pickPosition(click.position);
if (Cesium.defined(position)) {
const entity = this.viewer.entities.add({
position: position,
point: {
pixelSize: 10,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2
}
});
this.points.push(entity);
if (callback) {
const cartographic = Cesium.Cartographic.fromCartesian(position);
callback({
entity: entity,
position: {
lon: Cesium.Math.toDegrees(cartographic.longitude),
lat: Cesium.Math.toDegrees(cartographic.latitude),
height: cartographic.height
}
});
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
stop() {
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
clear() {
this.points.forEach(p => this.viewer.entities.remove(p));
this.points = [];
}
}
14.3.2 多边形绘制
class PolygonDrawTool {
constructor(viewer) {
this.viewer = viewer;
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
this.positions = [];
this.tempEntities = [];
this.polygon = null;
}
start(callback) {
// 左键添加点
this.handler.setInputAction((click) => {
const position = this.viewer.scene.pickPosition(click.position);
if (Cesium.defined(position)) {
this.positions.push(position);
this.addVertex(position);
this.updatePolygon();
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 鼠标移动
this.handler.setInputAction((movement) => {
if (this.positions.length >= 2) {
const position = this.viewer.scene.pickPosition(movement.endPosition);
if (Cesium.defined(position)) {
this.updateTempPolygon(position);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// 右键完成
this.handler.setInputAction(() => {
if (this.positions.length >= 3) {
this.finish(callback);
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
// 双击完成
this.handler.setInputAction(() => {
if (this.positions.length >= 3) {
this.finish(callback);
}
}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
}
addVertex(position) {
const point = this.viewer.entities.add({
position: position,
point: { pixelSize: 8, color: Cesium.Color.RED }
});
this.tempEntities.push(point);
}
updatePolygon() {
if (this.positions.length < 3) return;
if (this.polygon) {
this.polygon.polygon.hierarchy = new Cesium.PolygonHierarchy(this.positions);
} else {
this.polygon = this.viewer.entities.add({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(this.positions),
material: Cesium.Color.YELLOW.withAlpha(0.3),
outline: true,
outlineColor: Cesium.Color.YELLOW
}
});
}
}
updateTempPolygon(mousePosition) {
if (!this.polygon) return;
const tempPositions = [...this.positions, mousePosition];
this.polygon.polygon.hierarchy = new Cesium.PolygonHierarchy(tempPositions);
}
finish(callback) {
this.stop();
// 清理临时点
this.tempEntities.forEach(e => this.viewer.entities.remove(e));
this.tempEntities = [];
if (callback) {
const coordinates = this.positions.map(p => {
const c = Cesium.Cartographic.fromCartesian(p);
return [Cesium.Math.toDegrees(c.longitude), Cesium.Math.toDegrees(c.latitude)];
});
callback({ polygon: this.polygon, coordinates: coordinates });
}
}
stop() {
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
}
clear() {
this.tempEntities.forEach(e => this.viewer.entities.remove(e));
if (this.polygon) this.viewer.entities.remove(this.polygon);
this.positions = [];
this.tempEntities = [];
this.polygon = null;
}
}
// 使用
const drawTool = new PolygonDrawTool(viewer);
drawTool.start((result) => {
console.log('绘制完成:', result.coordinates);
});
14.4 相机交互控制
// 禁用默认交互
const controller = viewer.scene.screenSpaceCameraController;
controller.enableRotate = false;
controller.enableTranslate = false;
controller.enableZoom = false;
controller.enableTilt = false;
controller.enableLook = false;
// 自定义交互
let isDragging = false;
let lastPosition = null;
handler.setInputAction((click) => {
isDragging = true;
lastPosition = click.position.clone();
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
handler.setInputAction((movement) => {
if (isDragging && lastPosition) {
const dx = movement.endPosition.x - lastPosition.x;
const dy = movement.endPosition.y - lastPosition.y;
// 自定义平移逻辑
viewer.camera.moveRight(dx * 100);
viewer.camera.moveDown(dy * 100);
lastPosition = movement.endPosition.clone();
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
handler.setInputAction(() => {
isDragging = false;
lastPosition = null;
}, Cesium.ScreenSpaceEventType.LEFT_UP);
14.5 本章小结
本章介绍了交互与事件处理:
- 事件处理器:ScreenSpaceEventHandler、事件类型
- 对象拾取:pick、drillPick、pickPosition
- 高亮选中:高亮管理器
- 绘图工具:点、线、面绘制
- 相机交互:自定义交互控制
在下一章中,我们将详细介绍样式与可视化效果。
14.6 思考与练习
- 实现完整的绘图工具栏。
- 开发实体拖拽移动功能。
- 实现框选多个对象功能。
- 开发右键菜单功能。
- 实现快捷键控制功能。

浙公网安备 33010602011771号