上效果
功能点
- 测量分析
- 相机位置切换
- geojson数据加载
- 地图打点,显示信息
- 点击回传数据
- 二三位切换
这里二三维切换通上篇openlayers分享,技术交流+V:bloxed
<template>
<div class="h100 w100">
<div style="width:100%; height:100%; background-color: pink;" ref="xe2Container"></div>
<slot name="toolbar"></slot>
<slot name="mode"></slot>
<!-- 体积分析弹窗 begin-->
<div id="panel" v-show="drawType=='volume'">
<div class="box">
<label for="">基准面高度</label>
<el-input size="small" v-model="AnalyseForm.planeHeight" type="number" />
<label for="">采样间距</label>
<el-input size="small" v-model="AnalyseForm.planeDistance" type="number" />
<label for="">挖方体积</label>
<p id="cutVolume">{{AnalyseForm.cutVolume }}</p>
<label for="">填方体积</label>
<p id="fillVolume">{{ AnalyseForm.fillVolume }}</p>
<label for="">分析进度</label>
<p id="progress">{{ AnalyseForm.progress }}</p>
</div>
<div class="btn">
<el-button @click="resetPlane">重新绘制基准面</el-button>
<el-button @click="startAnalyse">开始分析</el-button>
</div>
</div>
<!-- end -->
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { ESObjectsManager,ESTerrainLayer,ES3DTileset ,ESGeoJson, ESLocationMeasurement, ESDistanceMeasurement, ESHeightMeasurement, ESAreaMeasurement, ESVolumeMeasurement} from 'esobjs-xe2-plugin/dist-node/esobjs-xe2-plugin-main';
import { CzmGlobeMaterial } from 'xbsj-xe2/dist-node/xe2-cesium-objects';
import { PickedInfo } from "xbsj-xe2/dist-node/xe2-base-objects";
import { ca } from "element-plus/es/locale";
const xe2Container = ref<HTMLElement | null>(null)
//实例化一个场景对象管理器
const objm:any = ref<any>(new ESObjectsManager());
//@ts-ignore
window.g_objm = objm.value;
const czmViewer = ref<any>(null)
const eSTerrainLayer = ref<any>(null);
const sceneObject = ref<any>(null);
const sceneStaions = ref<any[]>([]);
const sceneMeasure = ref<any>(null);
const drawType = ref<any>("")
const emit = defineEmits(["mapSingleClick"]); // 自定义事件 会回传也是point数据
const measureArr = ref<any[]>([]);
const AnalyseForm = reactive<any>({
planeHeight: 0,
planeDistance: 1,
cutVolume: "0.00(立方米)",
fillVolume: "0.00(立方米)",
progress: "0%"
})
onMounted(() => {
if (!xe2Container.value) return;
init3Dview();
})
const init3Dview = () => {
czmViewer.value = objm.value.createCesiumViewer(xe2Container.value);
// 监听视口状态
czmViewer.value.statusChanged.don((status:string) => {
if (status == 'Created') {
// 视口创建完成,飞到初始视角位置
objm.value.activeViewer.flyIn(
[110.1465,22.41115, 919.4948053805265],
[283.14016420232184, -1.81201260919955, 0.026583596819532502],
3
);
}
})
// czmViewer.value.changeToWalk([110.105931,22.422299, 200.4948053805265])
objm.value.createSceneObjectFromJson({
"id": "9812a65f-0de0-4f7b-b234-809c0c2fb8ef",
"type": "ESImageryLayer",
"url": "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"
});
eSTerrainLayer.value = objm.value.createSceneObject(ESTerrainLayer);
// // cesium官方地形
eSTerrainLayer.value.url = "ion://1";
//token需要到cesium官网申请 https://ion.cesium.com/
objm.value.activeViewer.ionAccessToken =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIwZjlmNzA1MC1iYTk0LTQxYzktYThlYS02ZTc0MDI0ZDgxZTAiLCJpZCI6MjU1MDQ4LCJpYXQiOjE3MzE1MTM0NDB9.XiIX1mau6Mwp-S5AOau-MslPFT2MzRSLuJ4pday8jkc";
sceneObject.value = objm.value.createSceneObject(CzmGlobeMaterial);
objm.value.activeViewer.rain = 0;
objm.value.activeViewer.cloud = 1;
}
const changeElevation = ()=>{
sceneObject.value.shadingMode = "none"
}
const addStation = (stations: any[]) => {
if(sceneStaions.value.length){
sceneStaions.value.forEach((item:any)=>{
try {
if (item) objm.value.destroySceneObject(item)
} catch (error) {
console.info(error)
}
})
}
stations.forEach((point, index) => {
let sceneStaion = objm.value.createSceneObject(ESGeoJson,index+point.stcd);
let data = {
"type": "FeatureCollection",
"name":"stations",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [point.lng, point.lat],
iconUrl: point.icon,
},
iconUrl: point.icon,
properties: {
id: index + point.stcd,
name: point.stnm,
type: point.sttp,
info: point,
iconUrl: point.icon,
},
id:index + point.stcd,
}]
}
sceneStaion.url = data
// 额外存储属性
sceneStaion.extras = data
// 图片是否显示
sceneStaion.imageShow = true
// 图片url地址
sceneStaion.imageUrl = point.icon
// 图片大小
sceneStaion.imageSize = [60, 60]
// 图片锚点
sceneStaion.imageAnchor = [0.5, 1]
// 图片偏移
sceneStaion.imageOffset = [0, 0]
// 文字颜色
sceneStaion.textColor = [1, 1, 1, 1]
// 文字大小
sceneStaion.textFontSize = 12
// 文字背景颜色
// sceneStaion.textBackgroundColor = [1, 1, 1, 1]
// 文字锚点
sceneStaion.textAnchor = [0.5, 1]
// 用于显示的属性
sceneStaion.textProperty = "name"
// 文字的偏移值
sceneStaion.textOffset = [-10, -60]
// 是否被拾取
sceneStaion.allowPicking = true
// 贴地模式
sceneStaion.heightReference = "CLAMP_TO_GROUND"
// 被拾取
sceneStaion.pickedEvent.don((e:any) => {
const point = e.childPickedInfo.geojsonPickInfo.properties;
const attachedInfo = PickedInfo.getFinalAttachedInfo(e)
switch (attachedInfo.viewersPickingPointerEventFuncType[0]) {
case 'click':
mapSingleClick(point.info);
break;
case "pointerHover":
// alert("悬浮拾取:" + name)
break;
default:
break;
}
})
sceneStaions.value.push(sceneStaion)
});
}
const mapSingleClick = (point: any) => {
emit("mapSingleClick", point);
};
const clear = ()=>{
drawType.value = ""
measureArr.value.forEach((item:any) => {
if (item) objm.value.destroySceneObject(item)
})
measureArr.value.length = 0
sceneMeasure.value.editing = false;
sceneMeasure.value?.clear();
}
const zoomInOut = (number: any) => {
const cameraPosition= objm.value.activeViewer.getCurrentCameraInfo();
const position = cameraPosition.position;
const rotation = cameraPosition.rotation;
const newposition = [position[0], position[1], position[2]+(number*1000) ];
const newrotation = [rotation[0], rotation[1], rotation[2] ];
console.log(newposition)
objm.value.activeViewer.flyIn(
[...newposition],
[...newrotation],
1
);
}
const toCenter = (coordinates?: any[]) => {
const newCoordinates =coordinates ? [...coordinates, 789.4948053805265] : [110.1465,22.41115, 919.4948053805265]
objm.value.activeViewer.flyIn(
newCoordinates,
[29.015034176609266, -29.191968119807054, 359.9990548222274],
3
);
}
const draw = (measureType: any) => {
drawType.value = measureType;
switch (measureType) {
case "point":
createPoint();
break;
case "line":
createDistance();
break;
default:
case "height":
createHeight();
break;
case "area":
createArea();
break;
case "volume":
createVolume();
break;
}
}
const createPoint = ()=>{
sceneMeasure.value = objm.value.createSceneObject(ESLocationMeasurement);
sceneMeasure.value.editing = true;
measureArr.value.push(sceneMeasure.value);
}
const createDistance = ()=>{
sceneMeasure.value = objm.value.createSceneObject(ESDistanceMeasurement);
sceneMeasure.value.editing = true;
measureArr.value.push(sceneMeasure.value);
}
const createHeight = ()=>{
sceneMeasure.value = objm.value.createSceneObject(ESHeightMeasurement);
sceneMeasure.value.editing = true;
measureArr.value.push(sceneMeasure.value);
}
const createArea = () => {
sceneMeasure.value = objm.value.createSceneObject(ESAreaMeasurement);
sceneMeasure.value.editing = true;
measureArr.value.push(sceneMeasure.value);
}
const createVolume = ()=>{
sceneMeasure.value = objm.value.createSceneObject(ESVolumeMeasurement);
sceneMeasure.value.editing = true;
sceneMeasure.value.depthTest=true;
sceneMeasure.value.points = [];
sceneMeasure.value.editing = true;
jionDon();
measureArr.value.push(sceneMeasure.value);
}
const resetPlane = ()=>{
sceneMeasure.value.clear();
sceneMeasure.value.editing = false;
sceneMeasure.value.points = [];
sceneMeasure.value.editing = true;
}
const startAnalyse = () => {
sceneMeasure.value.clear();
sceneMeasure.value.planeDistance = AnalyseForm.planeDistance;
sceneMeasure.value.planeHeight = AnalyseForm.planeHeight;
sceneMeasure.value.start();
}
const jionDon = ()=>{
// 监听基准面设置到UI上
sceneMeasure.value.planeHeightChanged.don((val:any) => {
if (val) AnalyseForm.planeHeight= Number(val).toFixed(2)
})
// 监听挖方体积
sceneMeasure.value.cutVolumeChanged.don((val:any) => {
AnalyseForm.cutVolume = val.toFixed(2) + '(立方米)'
})
// 监听填方体积
sceneMeasure.value.fillVolumeChanged.don((val:any) => {
AnalyseForm.fillVolume= val.toFixed(2) + '(立方米)'
})
// 监听进度
sceneMeasure.value.progressChanged.don((val:any) => {
AnalyseForm.progress = val.toFixed(2) + "%"
})
}
defineExpose({
czmViewer, //地图
/**
@desc 添加站点
@param [{
stcd:0000,
stnm:"xxxx",
sttp:'',
icon:'xxxx',
lng:number,
lat:number
}
data:[{name:'xx',value:'',unit:''}] //data地图鼠标悬浮展示内容
}]
*/
addStation,
/**
* 缩放 地图
* @param {number} zoom 缩放级别
*/
zoomInOut,
/**
* 地图中心点
* @param {number} center 地图中心点参数格式 [lng,lat]
* @param {number} zoom 缩放级别 15
*/
toCenter,
/**
* 清除地图分析
*/
clear,
/**
* 地图分析
* @param {string} type 分析类型 'area' 面积 'line' 距离
*/
draw,
});
</script>
<style scoped>
#panel{
position: absolute;
box-sizing: border-box;
right: 460px;
top: 20px;
width: 330px;
background: #3e4249;
border-radius: 8px;
padding: 20px;
color: #d6deea;
border: 1px solid #939e8f;
animation-name: enter;
animation-duration: 1.5s;
animation-fill-mode: forwards;
animation-delay: 0.7s;
}
.box {
display: grid;
grid-template-columns: 90px 1fr;
align-items: center;
}
.box label {
padding-right: 10px;
}
.btn {
padding-top: 10px;
text-align: center;
}
.btn button {
}
label {
line-height: 30px;
}
</style>