<script lang="ts">
import { defineComponent } from "vue";
import { getDictItemsByCode } from "/@/utils/dict";
const riskLevel = getDictItemsByCode("risk_level");
// console.log("riskLevel", riskLevel);
// 模型地址
const publicPath = import.meta.env.VITE_PUBLIC_PATH || "/";
const glbModelUrl = publicPath + "tiles/NiangQiang_v11_nomap.glb";
export default defineComponent({
props: {
config: {
type: Object,
default: () => {},
},
// 是否开始绘制
isDrawing: {
type: Boolean,
default: false,
},
recordRowData: {
type: Object,
default: () => {},
},
areaPositionData: {
type: Array,
default: () => [],
},
},
emits: {
// "update:modelValue": null,
},
data() {
return {
viewer: "",
floatingPoint: undefined,
activeShape: undefined,
activeShapePointsLatlng: [],
activeShapePoints: [],
drawColor: "",
primitiveArray: [], //primitive的集合
recordData: {}, //表格行数据
};
},
// 监听isDrawing
watch: {
isDrawing(newVal, oldValue) {
if (newVal && newVal !== oldValue) {
this.startDraw();
}
},
// 监听recordRowData
recordRowData: {
async handler(newValue) {
this.recordData = newValue;
// 重绘之前删除之前的
if (newValue?.isDraw) {
this.deleteArea(newValue);
}
// 在数据改变时执行逻辑
if (newValue.csys) {
this.drawColor = await this.hexToRGBA(newValue.csys, 0.3);
} else {
this.drawColor = await this.hexToRGBA("#ffffff", 0.3);
}
},
immediate: true,
deep: true,
},
// 监听areaPositionData绘制原有区域
areaPositionData: {
handler(newValue, oldvalue) {
console.log("newValue", newValue);
// 在数据改变时执行逻辑
if ( newValue !== oldvalue && newValue !== '' && newValue!==null ) {
this.drawArea(newValue);
}
},
immediate: true, // 立即执行一次
deep: true, // 深度监听
},
},
mounted() {
this.initMap();
this.registerMouseEvents()
},
beforeDestroy() {
if (this.viewer) {
this.viewer.destroy();
}
},
methods: {
initMap(): Promise<Promise<void>> {
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1OTNiNTAyYi0yYjMyLTQ1NzMtYmQ5Ni0xMjM1NzgyZDFlNjQiLCJpZCI6MjI1ODY0LCJpYXQiOjE3MTk5MDY2MDZ9.elYgczKeh0tP-JmSb09PDHxcM38TIHbMRNovaYzckpE';
this.viewer = new Cesium.Viewer("cesiumContainer", {
animation: false, //左下角的动画仪表盘
baseLayerPicker: false, //右上角的图层选择按钮
geocoder: false, //搜索框
homeButton: false, //home按钮
sceneModePicker: false, //模式切换按钮
timeline: false, //底部的时间轴
navigationHelpButton: false, //右上角的帮助按钮,
fullscreenButton: false, //右下角的全屏按钮
selectionIndicator: false, // 去掉聚焦
infoBox: false,
});
this.viewer.scene.skyBox.destroy();
this.viewer.scene.skyBox = undefined;
this.viewer.scene.globe.show = false;
this.viewer.scene.backgroundColor = new Cesium.Color(0.5, 0.5, 0.5, 1);
this.viewer.scene.globe.baseColor = new Cesium.Color(0.5, 0.5, 0.5, 1);
this.viewer.scene.debugShowFramesPerSecond = false; //显示帧率
this.viewer._cesiumWidget._creditContainer.style.display = "none";
this.viewer.scene.debugShowFramesPerSecond = false; //显示帧率
this.viewer._cesiumWidget._creditContainer.style.display = "none";
this.viewer.scene.light = new Cesium.DirectionalLight({
direction: new Cesium.Cartesian3(0.354925, -0.890918, -0.283358)
})
this.createModel(0);
},
// 创建模型
createModel(height) {
this.viewer.entities.removeAll();
// 3D笛卡尔点,参数 x、y、z
const position = Cesium.Cartesian3.fromDegrees(
106.303956, 32.847126,
height
);
// 将实体添加到集合中
const entity = this.viewer.entities.add({
name: "model-factory",
position: position,
id: 'model-factory',
// orientation: orientation, // 设置方向
model: {
uri: glbModelUrl, // 获取或设置字符串Property,该字符串指定glTF资产的URI。
minimumPixelSize: 128, // 获取或设置数字属性,指定近似最小值模型的像素大小,与缩放无关。这可以用来确保即使观看者缩小视图,模型仍然可见。当 0.0 时,没有强制执行最小大小。
maximumScale: 20000, // 获取或设置数字属性,该属性指定最大比例模型的大小
zIndex: 1,
scale: 2.0,
},
});
const origin = entity.position.getValue()
const heading = Cesium.Math.toRadians(52)
const pitch = Cesium.Math.toRadians(0)
const roll = Cesium.Math.toRadians(0)
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
const orientation = Cesium.Transforms.headingPitchRollQuaternion(origin, hpr)
entity.orientation = orientation
// this.viewer.trackedEntity = entity; // 聚焦模型
this.viewer.camera.flyTo({ //106.301116, 32.850026
destination: Cesium.Cartesian3.fromDegrees(106.306016, 32.850226, 220), // 经纬度以及相机离地高度
orientation: {
heading: Cesium.Math.toRadians(200), // 航向角
pitch: Cesium.Math.toRadians(-25), // 俯仰角
roll: 0.02 // 距中心的距离,以米为单位
},
duration: 0.5 // 飞行时间
})
},
resetModel(){
const modelEntity = this.viewer.entities.getById('model-factory');
if (modelEntity) {
this.viewer.entities.remove(modelEntity);
this.createModel(0);
}
},
// 颜色hex转rgba
hexToRGBA(hex, alpha) {
const r = parseInt(hex.substring(1, 3), 16);
const g = parseInt(hex.substring(3, 5), 16);
const b = parseInt(hex.substring(5, 7), 16);
return "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
},
createPoint(position) {
const point = this.viewer.entities.add({
position: position,
point: {
color: Cesium.Color.WHITE,
outlineColor: Cesium.Color.RED,
outlineWidth: 0.5,
pixelSize: 8,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
zIndex: 2,
},
});
return point;
},
drawGraphic(positionData) {
// 绘制图形
let shape = null;
shape = this.viewer.entities.add({
polygon: {
hierarchy: positionData,
material: new Cesium.ColorMaterialProperty(Cesium.Color.WHITE.withAlpha(0.7)),
},
});
return shape;
},
startDraw() {
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas);
const that = this;
// this.viewer.scene.globe.depthTestAgainstTerrain = true //深度检测
//鼠标左键
this.handler.setInputAction(async function (event) {
//点击获取经纬度坐标
const earthPosition = that.viewer.scene.pickPosition(event.position);
if (Cesium.defined(earthPosition)) {
if (that.activeShapePointsLatlng.length === 0) {
that.floatingPoint = that.createPoint(earthPosition);
that.activeShapePointsLatlng.push(earthPosition);
const dynamicPositions = new Cesium.CallbackProperty(function () {
return new Cesium.PolygonHierarchy(that.activeShapePointsLatlng);
}, false);
//绘制动态图
that.activeShape = await that.drawGraphic(dynamicPositions);
}
that.activeShapePointsLatlng.push(earthPosition);
that.activeShapePoints.push(that.createPoint(earthPosition));
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
//鼠标移动
that.handler.setInputAction(function (event) {
if (Cesium.defined(that.floatingPoint)) {
const newPosition = that.viewer.scene.pickPosition(event.endPosition);
if (Cesium.defined(newPosition)) {
that.floatingPoint.position.setValue(newPosition);
that.activeShapePointsLatlng.pop();
that.activeShapePointsLatlng.push(newPosition);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
//鼠标右键移除动态图层
that.handler.setInputAction(function (event) {
that.terminateShape(that.activeShapePointsLatlng);
that.$emit("getClick", that.coordinateList); // 抛出的事件
that.resetModel();
}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
this.registerMouseEvents()
},
async terminateShape(dataItem) {
let that = this;
let data = dataItem.map((item) => {
const cartographic = Cesium.Cartographic.fromCartesian(item);
const x = Cesium.Math.toDegrees(cartographic.longitude);
const y = Cesium.Math.toDegrees(cartographic.latitude);
return {
x,
y,
};
});
// console.log(data, '转换');
data.push({ x: data[0].x, y: data[0].y }); // 保持第一个点的坐标和最后一个坐标是一致的
const list = data.map((item) => {
return Cesium.Cartesian3.fromDegrees(item.x, item.y);
});
// console.log(list, '转换');
// 创建一个多边形
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(list),
extrudedHeight: Number(this.recordData.gd) * 12.5 ?? 15 * 12.5, // 高度为15
});
// 创建一个 GeometryInstance
let geometryInstance = new Cesium.GeometryInstance({
geometry: polygon,
id: that.recordData,
});
// 设置材质translucent
const color = Cesium.Color.fromCssColorString(this.drawColor);
// 创建 Primitive
that.primitive = new Cesium.Primitive({
name: this.recordData.id?.name ?? Date.now(),
geometryInstances: geometryInstance,
appearance: new Cesium.MaterialAppearance({
material: new Cesium.Material({
fabric: {
type: "Color",
uniforms: {
color,
},
},
}),
translucent: true,
closed: true,
}),
});
// 将 Primitive 添加到场景中
that.viewer.scene.primitives.add(that.primitive);
that.primitiveArray.push(that.primitive);
that.coordinateList = data; // 存放绘制的图形坐标
//移除节点
if (that.activeShapePoints.length) {
that.activeShapePoints.filter((point) => {
that.viewer.entities.remove(point);
});
}
this.$emit("drawEnd", list);
that.viewer.entities.remove(that.floatingPoint); //去除动态点图形(当前鼠标点)
that.viewer.entities.remove(that.activeShape); //去除动态图形
that.floatingPoint = undefined;
that.activeShape = undefined;
that.activeShapePointsLatlng = [];
that.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); // 图形绘制完成以后销毁 鼠标点击事件
},
// 删除区域
deleteArea(areaData) {
try {
if (this.primitiveArray.length > 0) {
this.primitiveArray.forEach((e) => {
// console.log('e', e);
// console.log('e._insta nceIds', e._instanceIds)
// console.log('e._instanceIds[0]-id', e._instanceIds[0]['id'])
if(!e) return;
// 删除单个区域
if (e._instanceIds && e._instanceIds.length > 0 && e._instanceIds[0] && e._instanceIds[0]['id'] && e._instanceIds[0]['id'] == areaData.id) {
!Array.isArray(areaData) && this.viewer.scene.primitives.remove(e);
} else {
// 删除全部
Array.isArray(areaData) && this.viewer.scene.primitives.remove(e);
}
});
}
} catch (error) {
console.log(error);
}
},
// 绘制区域
async drawArea(areaPositionData) {
const that = this;
// 清除之前的区域
that.primitiveArray && that.primitiveArray.length > 0 && await that.deleteArea(areaPositionData);
// 绘制原有区域
areaPositionData && areaPositionData.lenth > 0
areaPositionData.forEach(async (item) => {
// const fxdj = item.gyfxdj ?? item.kzfxdj ?? 0; // 获取方向
const fxdjColor = item["csys"]
? await this.hexToRGBA(item["csys"], 0.3)
: "rgb(255, 255, 255, 0)";
// 判断是否有数据并且格式为[{x: 1, y: 1}]形式
if (item.wzxx && item.wzxx.length > 0 && !Array.isArray(item.wzxx[0])) {
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(item.wzxx),
extrudedHeight: item.height ? Number(item.height) * 12.5 : 15 * 12.5, // 高度为15
});
// 创建一个 GeometryInstance
let geometryInstance = new Cesium.GeometryInstance({
geometry: polygon,
id: item,
});
// const color = Cesium.Color.fromCssColorString('rgba(255, 0, 0, 0.5)');
const color = Cesium.Color.fromCssColorString(fxdjColor);
// 创建 Primitive
that.primitive = new Cesium.Primitive({
geometryInstances: geometryInstance,
appearance: new Cesium.MaterialAppearance({
translucent: true,
closed: true,
material: new Cesium.Material({
fabric: {
type: "Color",
uniforms: {
color,
},
},
}),
}),
});
// 将 Primitive 添加到场景中
that.viewer.scene.primitives.add(that.primitive);
that.primitiveArray.push(that.primitive);
}
});
},
// 添加弹窗
registerMouseEvents() {
const that = this;
that.handler && that.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
const infoBox = document.createElement('div');
infoBox.className = 'infoBox';
that.viewer.container.appendChild(infoBox);
// 鼠标左键按下事件
that.viewer.screenSpaceEventHandler.setInputAction(async function(movement) {
const pickedObject = that.viewer.scene.pick(movement.endPosition);
console.log('pickedObject', pickedObject)
if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id) && Cesium.defined(pickedObject.id) && typeof pickedObject.id === 'object' && typeof pickedObject.id.id === 'string' && pickedObject.id.name!= 'model-factory') {
// const queryByIdRes = await queryById({id: pickedObject.id});
const { name = '', fxfqmc = '', fxdj = '', pgsj = ''} = pickedObject?.id;
const fxfqName = name && name != '' && name != null ? name : (fxfqmc ? fxfqmc : '') ;
// console.log('fxdj', fxdj,Number(fxdj) - 1, riskLevel[Number(fxdj) - 1],riskLevel[Number(fxdj) - 1]['text'])
const fxdjName = fxdj && riskLevel[Number(fxdj) - 1] && riskLevel[Number(fxdj) - 1]['text'] ? riskLevel[Number(fxdj) - 1]['text'] : ''
// 填充气泡弹窗内容
infoBox.innerHTML = '名称:' + fxfqName + '<br>' +
'风险等级:' + fxdjName + '<br>' +
'评估时间:' + `${pgsj && pgsj != null && pgsj !=`` ? pgsj : '' }`;
// 设置气泡弹窗位置
infoBox.style.position = 'absolute';
infoBox.style.top = movement.endPosition.y + 'px';
infoBox.style.left = movement.endPosition.x + 'px';
infoBox.style.display = 'block';
// 设置背景色为白色透明度0.4
infoBox.style.backgroundColor = 'rgba(255, 255, 255, 0.4)';
// 设置边框样式
infoBox.style.border = '1px solid #ccc';
// 设置内边距
infoBox.style.padding = '10px';
// 设置字体样式
infoBox.style.fontFamily = 'Arial, sans-serif';
// 设置字体大小
infoBox.style.fontSize = '14px';
// 设置字体颜色
infoBox.style.color = '#000';
} else {
infoBox.style.display = 'none';
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
},
},
});
</script>
<template>
<!-- <div id="cesiumContainer" style="width: 100%; height: 100%"></div> -->
<div id="cesiumContainer" style="width: 1000px; height: 710px;position: relative"></div>
<div class="infoBox" style="display: none"></div>
</template>
02-14
679
08-04
634
09-27