前言:基于cesium实现地图拉取矩形框
效果:https://www.bilibili.com/video/BV1NQ4y1A7B6/?spm_id_from=333.999.0.0
思路:
1.创建cesium (省略.....)
2.理清需要那些功能,在这里我们用到了cesium得画点,画面,以及对鼠标得左键,右键,和移动得监听
3.接下来就开始创作了,其中还有一些细节,大家自行体会,
话不多说直接上代码
完整代码如下,当然还有一些缺陷或者bug,请大家指正,我会改进
// 当前点位的数据
let nowPoint = []
// 当前多边形中的点和线实体集合
let polygonEntityArr = []
let pointEntityArr = []
// 是否开始画多边形
let isDrawLine = false
// 是否形成面
let isDrawPolyGon = false
// 事件
const drawRectangleFunC = {
// 删除实体
// 删除鼠标移动生成的线
delDemoEntity: (name) => {
name == 'point_name' && pointEntityArr.forEach(item => {
viewer.entities.remove(item)
})
},
// 画面
draw: () => {
// 经纬度转换
const getLonOrLat = (cartesian2) => {
let cartesian = viewer.scene.globe.pick(viewer.camera.getPickRay(cartesian2), viewer.scene);
// console.log('cartesian',cartesian);
let cartorgraphic = Cesium.Cartographic.fromCartesian(cartesian);
// console.log('ddd', cartorgraphic);
let lon = Cesium.Math.toDegrees(cartorgraphic.longitude); // 经度
let lat = Cesium.Math.toDegrees(cartorgraphic.latitude); // 纬度
// console.log(`经度:${lon},纬度:${lat}`);
return {
longitude: lon,
latitude: lat
}
}
// 画点
const drawPoint = (lonAndLat) => {
const entityPoint = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(lonAndLat[0], lonAndLat[1], lonAndLat[2]),
name: 'point_name',
point: {
color: Cesium.Color.fromCssColorString('#fc3d4a'),
outlineColor: Cesium.Color.fromCssColorString('#fc3d4a'),
pixelSize: 11
},
})
return entityPoint
}
// 画面
const drawPolyGon = (lonAndLat) => {
let lonLats = (data) => {
let arr = []
for (let d in data) {
//判断经纬度范围
if (
data[d][0] >= -180 &&
data[d][0] <= 180 &&
data[d][1] >= -90 &&
data[d][1] <= 90
) {
arr.push(data[d][0], data[d][1])
} else {
console.log('经纬度数值不对:', data[d][0], data[d][1])
}
}
return arr
}
const entityPolygon = viewer.entities.add({
// position: Cesium.Cartesian3.fromDegrees(lonAndLat[0], lonAndLat[1], lonAndLat[2]),
name: "polyGon_name",
polygon: {
clampToGround: true, //开启贴地
hierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(lonLats(lonAndLat))
),
material: Cesium.Color.BLUE.withAlpha(0.5),
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 300000)
}
});
return entityPolygon
}
// 声明监听事件
let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
// 监听鼠标左击事件
handler.setInputAction((event) => {
if (isDrawLine) {
// console.log('ddd', event);
// 判断是否有实体
// 获取坐标信息
let nowPosition = getLonOrLat(event.position)
// 当前点数据
nowPoint = [nowPosition.longitude, nowPosition.latitude, 0]
// 画点
const point = drawPoint([nowPosition.longitude, nowPosition.latitude, 0])
pointEntityArr.push(point)
// 开始形成面
isDrawPolyGon = true
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 鼠标移动事件
handler.setInputAction((event) => {
// 画框逻辑
if (isDrawLine && (nowPoint.length > 0)) {
setTimeout(() => {
// -------
// console.log('ddd event', event);
// 获取坐标信息
let movePosition = getLonOrLat(event.startPosition)
// console.log('ddd nowPosition', movePosition);
const getRectanglePoint = (startPoint, endPoint) => {
//点转turf点
let p1 = turf.point([...startPoint]);
let p2 = turf.point([...endPoint]);
// 两点间距离
let p1p2 = turf.rhumbDistance(p1, p2, { units: 'miles' });
let p1p2bearing = turf.bearing(p1, p2);
// console.log('ddd bearing', bearing);
// p1 ---------- p3
// | \ |
// | \ |
// | \ |
// | \|
// p4 ---------- p2
// 获取生成的两个延长线点
// 获取延长线点
const getExtensionPoint = (point, distance, bearing) => {
// let startPoint = turf.point(point, { "marker-color": "F00" });
const demo = turf.rhumbDestination(point, distance, bearing, { units: 'miles' });
return demo.geometry.coordinates
}
// 获取生成的两个延长线点
let p3RBearing = 0
let p3TBearing = 0
let p4RBearing = 0
let p4TBearing = 0
// turf使用的角度是由北向南
// 北
// |
// |
// |
// |
// p |-----------------
// |
// |
// |
// |
// |
// 南
if (p1p2bearing > 0) {
if (p1p2bearing < 90) {
// 在0 - 90度范围内
p3RBearing = 0
p3TBearing = -90
p4RBearing = 90
p4TBearing = -180
} else {
// 在90 - 180度范围内
p3RBearing = 90
p3TBearing = 0
p4RBearing = -180
p4TBearing = -90
}
} else {
if (p1p2bearing > -90) {
// 在0 - -90度范围内
p3RBearing = -90
p3TBearing = -180
p4RBearing = 0
p4TBearing = 90
} else {
// 在-90 - -180度范围内
p3RBearing = -180
p3TBearing = 90
p4RBearing = -90
p4TBearing = 0
}
}
// 获取p3点
const p3R = getExtensionPoint(p1, p1p2, p3RBearing) //起点
const p3T = getExtensionPoint(p2, p1p2, p3TBearing) //终点(鼠标当前对应的点)
// 获取p4点
const p4R = getExtensionPoint(p1, p1p2, p4RBearing) //起点
const p4T = getExtensionPoint(p2, p1p2, p4TBearing) //终点(鼠标当前对应的点)
//根据两个延长线获取交点 即p3
const getLineIntersect = (pp1, pp2) => {
let line1 = turf.lineString([[...startPoint], [...pp1]]);
let line2 = turf.lineString([[...endPoint], [...pp2]]);
let intersects = turf.lineIntersect(line1, line2);
const ddd = intersects.features.length > 0 ? intersects.features[0].geometry.coordinates : ''
return ddd
}
const p3 = getLineIntersect(p3R, p3T)
const p4 = getLineIntersect(p4R, p4T)
// console.log('ddd p3', p3);
// console.log('ddd p4', p4);
if (p3 == '' || p4 == '') {
console.log('点位有问题!');
} else {
let pointArr = [
startPoint,
p3,
endPoint,
p4
]
if (isDrawPolyGon) {
const entityPolygon = drawPolyGon(pointArr)
polygonEntityArr.push(entityPolygon)
isDrawPolyGon = false
} else {
const points = []
pointArr.forEach(item => {
const demo = Cesium.Cartesian3.fromDegrees(item[0], item[1], 0)
points.push(demo)
})
polygonEntityArr[0].polygon.hierarchy = points
// console.log('polygonEntityArr', polygonEntityArr);
}
}
}
// 根据点生成点位数据
getRectanglePoint([nowPoint[0], nowPoint[1]], [movePosition.longitude, movePosition.latitude])
}, 100)
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
// 鼠标右击事件
handler.setInputAction((event) => {
// console.log('ddd event', event);
if (isDrawLine) {
// 结束画多边形
isDrawLine = false
// 删除鼠标移动画线
// drawRectangleFunC.delDemoEntity('line_demo_name')
// 画多边形结束,形成面开始
// 清空数据
// 删除画点以及画线
// drawRectangleFunC.delDemoEntity('line_name')
drawRectangleFunC.delDemoEntity('point_name')
nowPoint = []
polygonEntityArr = []
pointEntityArr = []
// console.log('handler',handler);
// 画框完毕,取消鼠标监听
handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)//移除事件
handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)//移除事件
handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)//移除事件
// handler.removeAll();
// console.log('ddd', viewer.entities);
// console.log('ddd', viewer);
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
},
// 开始
klk: () => {
// drawRectangleFunC.delDemoEntity('point_name')
drawRectangleFunC.draw()
isDrawLine = true
isDrawPolyGon = false
nowPoint = []
polygonEntityArr = []
pointEntityArr = []
}
}
最后谢谢大家观看,第一次创作,感谢大家!
如有不好的地方,欢迎指正.
也作为在工作当中的积累,展示在这里.