Cesium实现空间查询,主要通过在地图上勾画区域,从而查询区域内的点。功能实现依靠viewer.screenSpaceEventHandler.setInputAction方法为屏幕空间事件绑定处理函数,主要触发的事件为Cesium.ScreenSpaceEventType.LEFT_CLICK、Cesium.ScreenSpaceEventType.MOUSE_MOVE、Cesium.ScreenSpaceEventType.RIGHT_CLICK对应鼠标左键、鼠标移动、鼠标右键。
1.Cesium.ScreenSpaceEventType.LEFT_CLICK事件
鼠标左键点击事件用来勾画地图区域。
通过点击事件来获取地球表面的具体坐标
const ray = viewer.camera.getPickRay(event.position)
const earthPosition = viewer.scene.globe.pick(ray,viewer.scene)
判断earthPosition是否点击在地球上的区域,如果不是则会返回undefined
if(Cesium.defined(earthPosition))
判断是否为第一个点如果是:
(1)创建浮动点floatingPoint,后续勾画鼠标过程中,通过更改floatingPoint的position来保证该点跟随鼠标移动
(2)将勾画的点添加到activeShapePoints数组中,用来作为动态创建多边形的顶点数组
(3)Cesium.CallbackProperty动态创建属性,动态创建多边形,用于后续鼠标移动过程中不断在activeShapePoints中添加数据,跟随鼠标移动生成多边形
if(activeShapePoints.length === 0) {
floatingPoint = createPoint(earthPosition)
activeShapePoints.push(earthPosition)
//创建活动面
const dynamicPositions = new Cesium.CallbackProperty(function () {
return new Cesium.PolygonHierarchy(activeShapePoints)
})
activeShape = drawShape(dynamicPositions)
}
后续则是将earthPosition的坐标转换为经纬度,添加到geojsonPoints数组中,通过使用turf创建polygon,判断点是否在多边形内;createPoint用来显示勾画的点
//将Cartesian坐标转换为经纬度数据
let cartographic = Cesium.Cartographic.fromCartesian(earthPosition)
geojsonPoints.push([Cesium.Math.toDegrees(cartographic.longitude),Cesium.Math.toDegrees(cartographic.latitude)])
activeShapePoints.push(earthPosition)
createPoint(earthPosition)
Cesium.ScreenSpaceEventType.LEFT_CLICK事件整体代码:
viewer.screenSpaceEventHandler.setInputAction(function (event) {
//通过点击事件,获取地球的坐标
const ray = viewer.camera.getPickRay(event.position)
const earthPosition = viewer.scene.globe.pick(ray,viewer.scene)
//检查是否点击的地球上的位置,如果不是earthPosition则为undefined
if(Cesium.defined(earthPosition)) {
//点击地图区域创建点
if(activeShapePoints.length === 0) {
floatingPoint = createPoint(earthPosition)
activeShapePoints.push(earthPosition)
//动态创建多边形
const dynamicPositions = new Cesium.CallbackProperty(function () {
return new Cesium.PolygonHierarchy(activeShapePoints)
})
activeShape = drawShape(dynamicPositions)
}
//将Cartesian坐标转换为经纬度数据
let cartographic = Cesium.Cartographic.fromCartesian(earthPosition)
//方便后续使用turf生成polygon
geojsonPoints.push([Cesium.Math.toDegrees(cartographic.longitude),Cesium.Math.toDegrees(cartographic.latitude)])
activeShapePoints.push(earthPosition)
createPoint(earthPosition)
}
},Cesium.ScreenSpaceEventType.LEFT_CLICK)
2.Cesium.ScreenSpaceEventType.MOUSE_MOVE事件
判断是否创建了浮动点,鼠标勾画过程中需要有浮动点跟随
if(Cesium.defined(floatingPoint))
(1)与开始勾画类似 ,通过鼠标移动事件来获取地球表面的具体坐标,判断是否点击地球上的位置
(2)如果在地图上的区域,鼠标移动过程中动态更新浮动点位置;并不断替换activeShapePoints中最后一个数据,跟随鼠标移动,动态生成多边形。
if(Cesium.defined(floatingPoint)) {
const ray = viewer.camera.getPickRay(event.endPosition)
const newPosition = viewer.scene.globe.pick(ray,viewer.scene)
// console.log(newPosition)
if(Cesium.defined(newPosition)) {
//更新浮动点的位置,鼠标移动过程中,这个点跟随移动,当第二次点击是,留下一个点,因为floatingPoint又接受了一个新值
floatingPoint.position.setValue(newPosition)
activeShapePoints.pop()
activeShapePoints.push(newPosition)
// console.log(activeShapePoints)
}
}
Cesium.ScreenSpaceEventType.MOUSE_MOVE事件整体代码:
viewer.screenSpaceEventHandler.setInputAction(function (event) {
if(Cesium.defined(floatingPoint)) {
const ray = viewer.camera.getPickRay(event.endPosition)
const newPosition = viewer.scene.globe.pick(ray,viewer.scene)
// console.log(newPosition)
if(Cesium.defined(newPosition)) {
//更新浮动点的位置,鼠标移动过程中,这个点跟随移动,当第二次点击是,留下一个点,因为floatingPoint又接受了一个新值
floatingPoint.position.setValue(newPosition)
activeShapePoints.pop()
activeShapePoints.push(newPosition)
// console.log(activeShapePoints)
}
}
},Cesium.ScreenSpaceEventType.MOUSE_MOVE)
3.Cesium.ScreenSpaceEventType.RIGHT_CLICK事件
鼠标右键事件则是完成勾画,对多边形区域内的点进行查询
根据geojsonPoints中的点数据,利用turf第三方库生成多边形;turf生成多边形,需要第一个点和最后一个点相同,需要在最后一个位置再次添加第一个点
let one = geojsonPoints[0]
geojsonPoints.push(one)
let geojsonPolygon = turf.polygon([geojsonPoints])
设置要查询的点数据
let points = {
'北京': [115.7,39.4,500],
'成都': [104.066458,30.659461,500],
'上海': [121.473701,31.230416,500]
}
对数据进行遍历,通过turf.point创建点;利用turf.booleanPointInPolygon判断点是否在多边形内,如果在则添加到地图上显示
for(let key in points) {
let point = turf.point(points[key])
console.log(points[key])
if(turf.booleanPointInPolygon(point, geojsonPolygon)) {
viewer.entities.add({
name: 'pointQuery',
position: Cesium.Cartesian3.fromDegrees(...points[key]),
point: {
color: Cesium.Color.fromCssColorString('#000000'),
outlineColor: Cesium.Color.fromCssColorString('#ffffff'),
outlineWidth: 2,
pixelSize: 6,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,//始终贴合地形表面
disableDepthTestDistance: Number.POSITIVE_INFINITY, //确保一个点实体总是可见,即使它位于其他对象后面
}
})
}
}
最后清除相关数据,解除相关事件
terminateShape()
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
Cesium.ScreenSpaceEventType.RIGHT_CLICK事件整体代码:
viewer.screenSpaceEventHandler.setInputAction(function () {
let one = geojsonPoints[0]
geojsonPoints.push(one)
let geojsonPolygon = turf.polygon([geojsonPoints])
let points = {
'北京': [115.7,39.4,500],
'成都': [104.066458,30.659461,500],
'上海': [121.473701,31.230416,500]
}
for(let key in points) {
let point = turf.point(points[key])
console.log(points[key])
if(turf.booleanPointInPolygon(point, geojsonPolygon)) {
viewer.entities.add({
name: 'pointQuery',
position: Cesium.Cartesian3.fromDegrees(...points[key]),
point: {
color: Cesium.Color.fromCssColorString('#000000'),
outlineColor: Cesium.Color.fromCssColorString('#ffffff'),
outlineWidth: 2,
pixelSize: 6,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,//始终贴合地形表面
disableDepthTestDistance: Number.POSITIVE_INFINITY, //确保一个点实体总是可见,即使它位于其他对象后面
}
})
}
}
terminateShape()
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
// getEntity()
},Cesium.ScreenSpaceEventType.RIGHT_CLICK)
实现效果:
全部代码:
viewer.screenSpaceEventHandler.setInputAction(function (event) {
const ray = viewer.camera.getPickRay(event.position)
const earthPosition = viewer.scene.globe.pick(ray,viewer.scene)
console.log(earthPosition)
//检查是否点击的地球上的位置,如果不是earthPosition则为undefined
if(Cesium.defined(earthPosition)) {
//点击地图区域创建点
if(activeShapePoints.length === 0) {
floatingPoint = createPoint(earthPosition)
activeShapePoints.push(earthPosition)
//创建活动面
const dynamicPositions = new Cesium.CallbackProperty(function () {
return new Cesium.PolygonHierarchy(activeShapePoints)
})
activeShape = drawShape(dynamicPositions)
}
//将Cartesian坐标转换为经纬度数据
let cartographic = Cesium.Cartographic.fromCartesian(earthPosition)
geojsonPoints.push([Cesium.Math.toDegrees(cartographic.longitude),Cesium.Math.toDegrees(cartographic.latitude)])
activeShapePoints.push(earthPosition)
// let hh = earthPosition
console.log(activeShapePoints)
createPoint(earthPosition)
}
},Cesium.ScreenSpaceEventType.LEFT_CLICK)
viewer.screenSpaceEventHandler.setInputAction(function (event) {
if(Cesium.defined(floatingPoint)) {
const ray = viewer.camera.getPickRay(event.endPosition)
const newPosition = viewer.scene.globe.pick(ray,viewer.scene)
// console.log(newPosition)
if(Cesium.defined(newPosition)) {
//更新浮动点的位置,鼠标移动过程中,这个点跟随移动,当第二次点击是,留下一个点,因为floatingPoint又接受了一个新值
floatingPoint.position.setValue(newPosition)
activeShapePoints.pop()
activeShapePoints.push(newPosition)
// console.log(activeShapePoints)
}
}
},Cesium.ScreenSpaceEventType.MOUSE_MOVE)
viewer.screenSpaceEventHandler.setInputAction(function () {
let one = geojsonPoints[0]
geojsonPoints.push(one)
let geojsonPolygon = turf.polygon([geojsonPoints])
let points = {
'北京': [115.7,39.4,500],
'成都': [104.066458,30.659461,500],
'上海': [121.473701,31.230416,500]
}
for(let key in points) {
let point = turf.point(points[key])
console.log(points[key])
if(turf.booleanPointInPolygon(point, geojsonPolygon)) {
viewer.entities.add({
name: 'pointQuery',
position: Cesium.Cartesian3.fromDegrees(...points[key]),
point: {
color: Cesium.Color.fromCssColorString('#000000'),
outlineColor: Cesium.Color.fromCssColorString('#ffffff'),
outlineWidth: 2,
pixelSize: 6,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,//始终贴合地形表面
disableDepthTestDistance: Number.POSITIVE_INFINITY, //确保一个点实体总是可见,即使它位于其他对象后面
}
})
}
}
terminateShape()
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
// getEntity()
},Cesium.ScreenSpaceEventType.RIGHT_CLICK)
})
const createPoint = (worldPosition) => {
let point = viewer.entities.add({
name: 'point',
position: worldPosition,
point: {
color: Cesium.Color.fromCssColorString('#000000'),
outlineColor: Cesium.Color.fromCssColorString('#03edfe'),
outlineWidth: 2,
pixelSize: 6,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,//始终贴合地形表面
disableDepthTestDistance: Number.POSITIVE_INFINITY, //确保一个点实体总是可见,即使它位于其他对象后面
}
})
return point
}
const drawShape = (dynamicPositions) => {
return viewer.entities.add({
name: 'sketchPolygon',
polygon: {
hierarchy:dynamicPositions,
material: new Cesium.ColorMaterialProperty(Cesium.Color.WHITE.withAlpha(0.2))
}
})
}
const terminateShape = () => {
// drawShape(activeShapePoints)
viewer.entities.remove(floatingPoint)
viewer.entities.remove(activeShape)
activeShapePoints = []
floatingPoint = undefined
activeShape = undefined
clearPoint()
}
const clearPoint = () => {
//清除点entity
let entities = viewer.entities.values
let entitiesToRemove = entities.filter((entity) => {
return entity.name == 'point'
})
console.log(entitiesToRemove)
entitiesToRemove.forEach((entity) => {
viewer.entities.remove(entity)
})
}
参考链接: