以Cesium.ScreenSpaceEventType.LEFT_CLICK和Cesium.ScreenSpaceEventType.MOUSE_MOVE为例,当setInputAction方法的第二个参数为Cesium.ScreenSpaceEventType.LEFT_CLICK时该方法的回调函数的click参数的类型为Cesium.ScreenSpaceEventHandler.PositionedEvent;
setInputAction方法的第二个参数为Cesium.ScreenSpaceEventType.MOUSE_MOVE时该方法的回调函数的click参数的类型为Cesium.ScreenSpaceEventHandler.MotionEvent,现在我已经将第二个参数改为动态的了,那回调函数的click参数类型怎么改呢?
我尝试将
this.handler.setInputAction((click: Cesium.ScreenSpaceEventHandler.PositionedEvent) {
}, DRAW_SCREEN_SPACE_EVENT_TYPES[drawEntityParams.graphics])
改为联合类型:
type ClickType = Cesium.ScreenSpaceEventHandler.PositionedEvent | Cesium.ScreenSpaceEventHandler.MotionEvent;
this.handler.setInputAction((click: ClickType) {
if (click instanceof Cesium.ScreenSpaceEventHandler.MotionEvent) {
// TODO
return;
}
}, DRAW_SCREEN_SPACE_EVENT_TYPES[drawEntityParams.graphics])
click instanceof Cesium.ScreenSpaceEventHandler.MotionEvent这行ts提示
'类型“typeof ScreenSpaceEventHandler”上不存在属性“MotionEvent”',
当前完整的代码如下:
import * as Cesium from 'cesium';
import type { DrawEntityParams, StyleConfig, EntityCollect, GraphicalType } from '@/components/Map/draw.d'
import { generateRandomString } from '@/utils/utils';
const DEFAULT_DRAW_IMAGE_ICON = new URL('@/components/Map/components/assets/point.svg', import.meta.url).href;
const DRAW_SCREEN_SPACE_EVENT_TYPES: {
[key: string]: Cesium.ScreenSpaceEventType;
} = {
point: Cesium.ScreenSpaceEventType.LEFT_CLICK,
billboard: Cesium.ScreenSpaceEventType.LEFT_CLICK,
polygon: Cesium.ScreenSpaceEventType.MOUSE_MOVE,
polyline: Cesium.ScreenSpaceEventType.MOUSE_MOVE,
box: Cesium.ScreenSpaceEventType.MOUSE_MOVE,
rectangle: Cesium.ScreenSpaceEventType.MOUSE_MOVE,
ellipse: Cesium.ScreenSpaceEventType.MOUSE_MOVE
};
export default class Draw {
viewer: Cesium.Viewer; // 当前的视图容器提供程序
config: StyleConfig; // 用于创建实体的颜色配置
entityCollect: EntityCollect; // 记录已经绘制的实体
handler: Cesium.ScreenSpaceEventHandler; // 用户交互程序对象
constructor(viewer: Cesium.Viewer, config: StyleConfig) {
/**
* cesium实例对象
*/
this.viewer = viewer;
/**
* 绘制要素的相关配置
* 默认配置
*/
this.config = config || {
borderColor: Cesium.Color.BLUE,
borderWidth: 2,
material: Cesium.Color.GREEN.withAlpha(0.5),
}
/**
* 初始化保存绘制实体的集合
*/
this.entityCollect = { point: [], rectangle: [], polyline: [], polygon: [], billboard: [], box: [], ellipse: [] }
// 初始化用户屏幕事件对象
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
};
/**
* 通过屏幕二维坐标获取点击位置得详细信息
*/
private getPositionInfo(position: Cesium.Cartesian2, graphics?: GraphicalType) {
// 点击位置笛卡尔坐标
let cartesian = this.viewer.camera.pickEllipsoid(position, this.viewer.scene.globe.ellipsoid);
if (!cartesian) return;
// 笛卡尔转弧度坐标
let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid, new Cesium.Cartographic())
// 经度
let lng = Cesium.Math.toDegrees(cartographic.longitude);
// 维度
let lat = Cesium.Math.toDegrees(cartographic.latitude);
// 海拔高度
let height = Number(this.viewer.scene.globe.getHeight(cartographic)?.toFixed(2));
// 实体的唯一标注
let id = graphics ? `${graphics}_${generateRandomString()}` : generateRandomString();
return {
cartesian,
cartographic,
lng,
lat,
height,
id
}
};
/**
* 绘制实体
*
*/
drawEntity(drawEntityParams: DrawEntityParams) {
const { graphics, _type, callback } = drawEntityParams;
this.handler.destroy();
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
this.handler.setInputAction((click: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
const positionInfo = this.getPositionInfo(click.position, drawEntityParams.graphics);
if (!positionInfo) return;
const { lng, lat, id, height } = positionInfo;
const entity = this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(lng, lat, height),
id,
billboard: {
// 图像地址,URI或Canvas的属性
image: DEFAULT_DRAW_IMAGE_ICON,
// 设置颜色和透明度
color: Cesium.Color.WHITE.withAlpha(0.8),
// 高度(以像素为单位)
height: 50,
// 宽度(以像素为单位)
width: 50,
// 大小是否以米为单位
sizeInMeters: false,
// 相对于坐标的垂直位置
verticalOrigin: Cesium.VerticalOrigin.CENTER,
// 相对于坐标的水平位置
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
// 该属性指定标签在屏幕空间中距此标签原点的像素偏移量
pixelOffset: new Cesium.Cartesian2(0, -12.5),
// 应用于图像的统一比例。比例大于会1.0放大标签,而比例小于会1.0缩小标签。
scale: 1.0,
// 显示在距相机的距离处的属性,多少区间内是可以显示的
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500),
// 是否显示
show: true,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
disableDepthTestDistance: Number.POSITIVE_INFINITY
}
});
const entityInfo = { id, position: [lng, lat], entity, graphics, _type };
this.entityCollect.point.push(entityInfo);
if (callback) callback(entityInfo)
}, DRAW_SCREEN_SPACE_EVENT_TYPES[drawEntityParams.graphics])
this.handler.setInputAction(() => {
this.handler.destroy();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
};
/**
* 获取绘制的实体集合
*/
get getEntityCollect() {
return this.entityCollect
}
}
补充:
我按照采纳的回答修改了代码,
然后在setInputAction的回调方法内通过 click instanceof Cesium.ScreenSpaceEventHandler.MotionEvent,来处理两个不同情况,但是ts提示了类型“typeof ScreenSpaceEventHandler”上不存在属性“MotionEvent”
代码如下:
this.handler.setInputAction((click: ClickType<typeof eventType>) => {
if (click instanceof Cesium.ScreenSpaceEventHandler.MotionEvent) {
// TODO
} else {
// TODO
}
}, DRAW_SCREEN_SPACE_EVENT_TYPES[drawEntityParams.graphics])
然后在GPT的帮助下,写了如下方法,一切就都正常了:
function isPositionedEvent(click: ClickType<Cesium.ScreenSpaceEventType>): click is Cesium.ScreenSpaceEventHandler.PositionedEvent {
return 'position' in click;
}
this.handler.setInputAction((click: ClickType<typeof eventType>) => {
if (!isPositionedEvent(click)) {
console.log(click.endPosition)
} else {
console.log(click.position)
}
}, DRAW_SCREEN_SPACE_EVENT_TYPES[drawEntityParams.graphics])
我想知道为什么不能使用click instanceof Cesium.ScreenSpaceEventHandler.MotionEvent
?
GPT给我的解决方案是否合理?
我这样写复杂的方式是否合理?
因为完全可以通过以下方式分不同情况编码, 只是多写了几次this.handler.setInputAction
,比如:
const graphicsFuns = {
billboard: () => {
this.handler.setInputAction((click: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
const positionInfo = this.getPositionInfo(click.position, drawEntityParams.graphics);
if (!positionInfo) return;
const { lng, lat, id, height } = positionInfo;
const entity = this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(lng, lat, height),
id,
billboard: {
// ...
}
});
const entityInfo = { id, position: [lng, lat], entity, graphics, _type };
this.entityCollect.point.push(entityInfo);
if (callback) callback(entityInfo)
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
},
polyline: () => {
this.handler.setInputAction((click: Cesium.ScreenSpaceEventHandler.MotionEvent) => {
const positionInfo = this.getPositionInfo(click.endPosition, drawEntityParams.graphics);
if (!positionInfo) return;
const { lng, lat, id, height } = positionInfo;
const entity = this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(lng, lat, height),
id,
polyline: {
// ...
}
});
const entityInfo = { id, position: [lng, lat], entity, graphics, _type };
this.entityCollect.point.push(entityInfo);
if (callback) callback(entityInfo)
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
};
写一个映射:
再写一个类型:
最后: