效果图:
实现代码:
<template>
<div id="cesiumContainer"></div>
</template>
<script setup>
import * as Cesium from "cesium";
import { onMounted } from "vue";
onMounted(() => {
const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false, // 禁用沙箱,解决控制台报错
selectionIndicator: false, //选择指示器
});
viewer._cesiumWidget._creditContainer.style.display = "none"; //隐藏logo版权
viewer.entities.add({
name: "polygon",
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray([
-115.0, 37.0, -115.0, 32.0, -107.0, 33.0, -102.0, 31.0, -102.0, 35.0,
]),
material: Cesium.Color.RED,
},
});
// 创建监听的handler
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
// 用于保存实体的对象
let gon = undefined;
// 判断是否处于编辑状态
let isEditting = false;
// 设置当前的编辑点
let currentPoint = undefined;
// 清空编辑点ID数组
let pointsId = [];
// 对鼠标按下事件的监听
handler.setInputAction((event) => {
// 获取屏幕坐标
let windowPosition = event.position;
// 通过屏幕坐标获取当前位置的实体信息
let pickedObject = viewer.scene.pick(windowPosition);
// 如果实体信息存在则说明该位置存在实体
if (Cesium.defined(pickedObject)) {
// 获取当前点的实体
let entity = pickedObject.id;
// 如果实体为面同时没有处于编辑状态,那么保存面的实体
if (entity.name === "polygon" && !isEditting) {
gon = entity;
// 生成编辑点
for (let cartesian of gon.polygon.hierarchy._value.positions) {
let point = viewer.entities.add({
name: "gon_point",
position: cartesian,
point: {
color: Cesium.Color.WHITE,
pixelSize: 8,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 1,
},
});
// 保存点的ID以便删除
pointsId.push(point.id);
}
// 设置编辑状态为true
isEditting = true;
// 禁止地球旋转和缩放,地球的旋转会对鼠标移动监听有影响,所以需要禁止
viewer.scene.screenSpaceCameraController.enableRotate = false;
viewer.scene.screenSpaceCameraController.enableZoom = false;
} else if (entity.name === "gon_point") {
// 如果实体为编辑点,那么设置当前编辑点为该点
currentPoint = entity;
}
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
// 对鼠标移动事件的监听
handler.setInputAction((event) => {
// 如果处于编辑状态且编辑点已定义,那么开始拖拽编辑
if (isEditting && currentPoint) {
// 获取屏幕坐标,移动监听与点击有所不同,所以有起始位置和终点位置
let windowPosition = event.startPosition;
// 将屏幕坐标转为笛卡尔坐标
let ellipsoid = viewer.scene.globe.ellipsoid;
let cartesian = viewer.camera.pickEllipsoid(windowPosition, ellipsoid);
// 如果点击到地球外,那么返回
if (!cartesian) {
return;
}
// 更新编辑点的位置
currentPoint.position = cartesian;
// 创建面标每个点位置信息的数组,并循环赋值
let points = [];
for (let id of pointsId) {
points.push(viewer.entities.getById(id).position._value);
}
// 更新面标的位置数组
gon.polygon.hierarchy = points;
// 这种方式报错了,不知道为什么
// gon.polygon.hierarchy = new Cesium.CallbackProperty(() => {
// return points;
// }, false);
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// 对鼠标抬起事件的监听
handler.setInputAction((event) => {
// 移除当前编辑点
currentPoint = undefined;
}, Cesium.ScreenSpaceEventType.LEFT_UP);
});
</script>
<style scoped>
#cesiumContainer {
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
结束编辑:
// 恢复地球的旋转和缩放
viewer.scene.screenSpaceCameraController.enableRotate = true;
viewer.scene.screenSpaceCameraController.enableZoom = true;
// 移除监听器
if (this.handler !== null && !this.handler.isDestroyed()) {
this.handler.destroy();
}
// 移除编辑点,清空编辑点数组
for (let id of this.pointsId) {
viewer.entities.removeById(id);
}
this.pointsId = [];
方式2:待验证
/**
* 多边形自定义编辑类
* author zk
* date 2022-12-13
*/
import * as Cesium from "@cesium/Cesium";
export default class EditPolygon {
constructor(viewer, options) {
this.viewer = viewer;
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
this.options = options || {
polygonColor: "#00ff0088", //编辑面颜色rgba
pointColor: "#ff0000ee", //正式点面颜色rgba
pointSize: 10, //正式点大小
tmpPointColor: "#ffff0088", //临时点面颜色rgba
tmpPointSize: 7, //临时点大小
};
this.currentEntity = null;
this.editCurrentEntity = null;
this.isedit = false;
this.editPolygons = null;
this.editPoint = null;
this.positions = null;
this.editPointIndex = [];
}
/**
* 启动编辑功能
* currentEntity 当前编辑的entity面对象
* ************************/
startEditEntity(currentEntity) {
var that = this;
that.editCurrentEntity = currentEntity;
that.editCurrentEntity.show = false;
that.positions = that.editCurrentEntity.polygon.hierarchy._value;
that.cleanEntityCollection("editTbEntityCollection");
let entityCollection = new Cesium.CustomDataSource(
"editTbEntityCollection"
);
entityCollection.key = that.editCurrentEntity.id;
entityCollection.label = "图斑编辑";
entityCollection.show = true;
that.viewer.dataSources.add(entityCollection);
//添加编辑点
that.addPointByData(that.positions.positions);
//添加临时中点
that.addTmpPoint(that.positions.positions);
var options = {
id: "edit-tb-polygon",
name: "edit-tb-polygon",
polygon: {
hierarchy: [],
material: Cesium.Color.fromCssColorString(that.options.polygonColor),
},
};
options.polygon.hierarchy = new Cesium.CallbackProperty(function () {
return that.positions;
}, false);
entityCollection.entities.add(new Cesium.Entity(options));
//操作事件监听
that.handler.setInputAction((movement) => {
var picks = that.viewer.scene.drillPick(movement.position);
if (picks.length > 0) {
var pick = picks[0];
var entity = pick.id;
//点击原有点
if (entity.id.indexOf("edit-tb-point-") !== -1) {
that.editPointIndex = [];
var strs = entity.id.split("-");
if (strs.length == 5) {
that.editPointIndex.push(Number(strs[4]));
} else if (strs.length == 7) {
that.editPointIndex.push(Number(strs[4]));
that.editPointIndex.push(Number(strs[6]));
}
that.editPolygons = that.getEditTbItemById("edit-tb-polygon");
that.editPoint = entity;
that.isedit = true;
}
// 点击临时点
if (entity.name.indexOf("edit-tb-tmp-point-") !== -1) {
that.editPointIndex = [];
var pindex = Number(entity.description._value);
pindex = pindex + 1;
that.editPointIndex.push(pindex);
that.positions.positions.splice(pindex, 0, entity.position._value);
that.addPointByData(that.positions.positions);
that.addTmpPoint(that.positions.positions);
that.editPolygons = that.getEditTbItemById("edit-tb-polygon");
var tmp = that.viewer.dataSources.getByName(
"editTbPointEntityCollection"
)[0];
that.editPoint = tmp.entities.values[pindex];
that.isedit = true;
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
//移动
that.handler.setInputAction(function (movement) {
if (that.isedit) {
const ray = that.viewer.camera.getPickRay(movement.endPosition);
var cartesian = that.viewer.scene.globe.pick(ray, viewer.scene);
that.editPoint.position = cartesian;
if (that.editPointIndex.length > 1) {
var dt = that.positions.holes[that.editPointIndex[0]].positions;
if (
that.editPointIndex[1] == 0 ||
that.editPointIndex[1] == dt.length - 1
) {
dt[dt.length - 1] = cartesian;
dt[0] = cartesian;
var poStart = that.getEditTbItemById(
"edit-tb-point-holes-" + that.editPointIndex[0] + "-positions-0"
);
if (poStart != null) {
poStart.position = cartesian;
}
var poEnd = that.getEditTbItemById(
"edit-tb-point-holes-" +
that.editPointIndex[0] +
"-positions-" +
dt.length -
1
);
if (poEnd != null) {
poEnd.position = cartesian;
}
} else {
dt[that.editPointIndex[1]] = cartesian;
}
} else if ((that.editPointIndex.length = 1)) {
if (
that.editPointIndex[0] == 0 ||
that.editPointIndex[0] == that.positions.positions.length - 1
) {
that.positions.positions[that.positions.positions.length - 1] =
cartesian;
that.positions.positions[0] = cartesian;
var poStart = that.getEditTbItemById("edit-tb-point-position-0");
if (poStart != null) {
poStart.position = cartesian;
}
var poEnd = that.getEditTbItemById(
"edit-tb-point-position-" + that.positions.positions.length - 1
);
if (poEnd != null) {
poEnd.position = cartesian;
}
} else {
that.positions.positions[that.editPointIndex[0]] = cartesian;
}
that.addTmpPoint(that.positions.positions);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
//双击删除点
that.handler.setInputAction(function (movement) {
that.isedit = false;
var picks = that.viewer.scene.drillPick(movement.position);
if (picks.length > 0) {
var pick = picks[0];
var entity = pick.id;
if (entity.name.indexOf("edit-tb-point-") !== -1) {
if (that.positions.positions.length < 5) {
that.$message.warning("图斑最少有三个点");
} else {
var pindex = Number(entity.description._value);
if (pindex == 0) {
that.positions.positions[that.positions.positions.length - 1] =
that.positions.positions[1];
}
that.positions.positions.splice(pindex, 1);
that.addPointByData(that.positions.positions);
that.addTmpPoint(that.positions.positions);
}
}
}
}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
//右击取消 固定位置
that.handler.setInputAction(function () {
that.isedit = false;
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
//添加编辑点
addPointByData(activeShapePoints1) {
var that = this;
var activeShapePoints = activeShapePoints1.slice(
0,
activeShapePoints1.length - 1
);
this.cleanEntityCollection("editTbPointEntityCollection");
let entityCollection = new Cesium.CustomDataSource(
"editTbPointEntityCollection"
);
that.viewer.dataSources.add(entityCollection);
for (let i = 0; i < activeShapePoints.length; i++) {
var entry = new Cesium.Entity({
id: "edit-tb-point-position-" + i,
name: "edit-tb-point-position-" + i,
position: activeShapePoints[i],
point: {
show: true,
color: Cesium.Color.fromCssColorString(that.options.pointColor),
pixelSize: that.options.pointSize,
},
description: i,
});
entityCollection.entities.add(entry);
}
}
//添加临时编辑点
addTmpPoint(activeShapePoints1) {
var that = this;
var activeShapePoints = activeShapePoints1.slice(
0,
activeShapePoints1.length - 1
);
this.cleanEntityCollection("editTbMidEntityCollection");
let entityCollection = new Cesium.CustomDataSource(
"editTbMidEntityCollection"
);
that.viewer.dataSources.add(entityCollection);
var midposition;
for (let i = 0; i < activeShapePoints.length; i++) {
if (i + 1 === activeShapePoints.length) {
midposition = Cesium.Cartesian3.midpoint(
activeShapePoints[i],
activeShapePoints[0],
new Cesium.Cartesian3()
);
} else {
midposition = Cesium.Cartesian3.midpoint(
activeShapePoints[i],
activeShapePoints[i + 1],
new Cesium.Cartesian3()
);
}
var entry1 = new Cesium.Entity({
name: "edit-tb-tmp-point-position-",
position: midposition,
point: {
pixelSize: that.options.tmpPointSize,
color: Cesium.Color.fromCssColorString(that.options.tmpPointColor),
},
show: true,
description: i,
});
entityCollection.entities.add(entry1);
}
}
//获取编辑点
getEditTbItemById(id) {
var that = this;
var ent = null;
var tmp = that.viewer.dataSources.getByName("editTbEntityCollection");
if (tmp.length > 0) {
tmp.map((res) => {
var entities = res.entities.values;
entities.map((re) => {
if (re.id == id) {
ent = re;
}
});
});
}
return ent;
}
/******************** 退出编辑功能 ************************/
editExit() {
var that = this;
that.cleanEntityCollection("editTbEntityCollection");
that.cleanEntityCollection("editTbMidEntityCollection");
that.cleanEntityCollection("editTbPointEntityCollection");
that.editCurrentEntity.show = true;
var positions = that.positions;
that.editCurrentEntity.polygon.hierarchy = JSON.parse(
JSON.stringify(positions)
);
that.editPolygons = null; //关闭操作事件
if (that.handler != null) {
that.handler.destroy();
}
//数据整理
var tempPoints = [];
var geom = "MULTIPOLYGON(((";
positions.positions.map((rr) => {
var cartographic = Cesium.Cartographic.fromCartesian(rr);
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
var heightString = cartographic.height;
tempPoints.push({
lon: longitudeString,
lat: latitudeString,
hei: heightString,
});
geom += longitudeString + " " + latitudeString + ",";
});
geom = geom.slice(0, geom.length - 1);
geom += ")";
if (positions.holes.length > 0) {
geom += ",(";
positions.holes.map((res) => {
res.positions.map((rr) => {
var cartographic = Cesium.Cartographic.fromCartesian(rr);
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
var heightString = cartographic.height;
geom += longitudeString + " " + latitudeString + ",";
});
geom = geom.slice(0, geom.length - 1);
geom += "),(";
});
geom = geom.slice(0, geom.length - 2);
}
geom += "))";
//保存数据
return geom;
}
/** 清理资源 */
cleanEntityCollection(key) {
var that = this;
var tmp = that.viewer.dataSources.getByName(key);
if (tmp.length > 0) {
tmp.map((res) => {
that.viewer.dataSources.remove(res);
});
}
}
}