EarthSDK2.0快速入门文档:EarthSDK2.0快速入门教程 - 飞书云文档 (feishu.cn)
EarthSDK2 JS API文档:EarthSDK2 JS API文档 (wolai.com)
EarthSDK2 官方示例:示例首页 (earthsdk.com)
Cesium示例:Hello World - Cesium Sandcastle
B站视频链接(地球可视化实验室):https://www.bilibili.com/video/BV16x421277N?vd_source=0f546fec3e50c4412e6098c8166be74a
环境搭建
webpack:如何引入EartrhSDK_哔哩哔哩_bilibili
npm i esobjs-xe2-plugin
npm i vue-xe2-plugin
vite:vite项目搭建好后,先安装XE2依赖esobjs-xe2-plugin,两个插件vite-plugin-externals 和 vite-plugin-static-copy。示例地址:earthsdk-demos: 基于earthsdk开发的用户交互界面,以及几个最小的和vue配合的示例 - Gitee.com
vue基础环境搭建:VUE基础环境搭建 - 飞书云文档 (feishu.cn)
安装配置ESSS信令服务器:如果要启动像素流服务,那么要求机器上最少有 nvidia 2060 以上的显卡,显卡配置太低,可能无法正确启动服务。ESSS信令服务器下载地址:https://bjxbsj.cn/esss.html或者 https://bjxbsj.cn/downcenter.html
安装成功之后 ,桌面图标运行,会在默认浏览器里打开 http://localhost:8086/login.html
默认用户名:admin,默认密码: admin1234
新版本使用分布式和官方文档步骤有变化,只需要将压缩包地址添加进编辑里面就行了
本地更新里面添加
代码演示:
<template>
<div style="width: 100%; height: 100%;" ref="xe2Container"></div>
<div class="header">
<select v-model="onlineUrl" @change="switchOnlineImage(onlineUrl)">
<option value="https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}">谷歌</option>
<option value="https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}">高德</option>
<option value="https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}">Arcgis</option>
</select>
<button @click="createESLocationMeasurement()">点位测量</button>
<button @click="createESDistanceMeasurement()">距离测量</button>
<button @click="createESHeightMeasurement()">高度测量</button>
<button @click="createESAreaMeasurement()">面积测量</button>
<button @click="createESDirectionMeasurement()">方位角测量</button>
<button @click="destroyMeasurement()">清除测量</button>
</div>
<div class="switch">
<button @click="switchCesiumViewer">切换Cesium视口</button>
<button @click="switchUEViewer">切换UE视口</button>
<button @click="flyIn([114.05565611710809, 32.23032890173555, 550640.6629355564], [349.4892794691355, -50.19016063219766, 0.0023330016021228077], 2)">初始位置</button>
</div>
<div class="mode">
<select name="" id="" @change="createESPolygonFence($event)">
<option value="danger">围栏样式1</option>
<option value="checkerboard">围栏样式2</option>
<option value="warning">围栏样式3</option>
<option value="cord">围栏样式4</option>
<option value="scanline">围栏样式5</option>
<option selected value="honeycomb">围栏样式6</option>
</select>
<button @click="destroyfence()">清除围栏</button>
<select name="" id="" @change="createESPipeFence($event)">
<option value="purple">紫色</option>
<option selected value="blue">蓝色</option>
</select>
<select name="" id="" @change="createESPath($event)">
<option value="singleArrow">单箭头路径</option>
<option selected value="multipleArrows">多箭头路径</option>
</select>
<button @click="destroyPath()">清除路径</button>
<select name="" id="" @change="createESAlarm($event)">
<option value="cylinder">柱状</option>
<option selected value="circle">圆形</option>
</select>
<button @click="destroyAlarm()">清除警告</button>
<select name="" id="" @change="createESHuman($event)">
<option value="worker">工人</option>
<option selected value="police">警察</option>
<option selected value="pedestrian">路人</option>
</select>
<label for="">人员跟随</label><input type="checkbox" v-model="follow">
<button @click="createESImageLabel()">图片标签</button>
<button @click="createESGeoPolygon()">贴地多边形</button>
<button @click="createESApertureEffect()">光圈特效</button>
</div>
<div class="weather">
<div class="control-group">
<label for="">时间线</label>
<input type="range" min="0" max="1" step="0.01" @input="changeCurrentTime($event)">
</div>
<div class="control-group">
<label for="">云</label>
<input type="range" min="0" max="1" step="0.01" @input="changeCloud($event)">
</div>
<div class="control-group">
<label for="">雨</label>
<input type="range" min="0" max="1" step="0.01" @input="changeRain($event)">
</div>
<div class="control-group">
<label for="">雪</label>
<input type="range" min="0" max="1" step="0.01" @input="changeSnow($event)">
</div>
<div class="control-group">
<label for="">大气</label>
<input type="checkbox" value="true" @change="changeAtmosphere()">
</div>
</div>
<div class="tile">
<!-- <button v-for="(item, index) in tileData" :key="item.id" @click="flyToById(item.id)">{{ item.name }}</button> -->
<button v-for="(item) in tileData" :key="item.id" @click="flyToById(item.id)">{{ item.name }}</button>
</div>
<div>
</div>
</template>
<!-- 1.创建dom元素用来加载视口
2.创建ESObjectManager对象管理器
3.创建视口对象
4.加载影像
-->
<script setup>
import { ESApertureEffect, ESLocationMeasurement, ESObjectsManager } from 'esobjs-xe2-plugin/dist-node/esobjs-xe2-plugin-main';
import { PickedInfo } from 'xbsj-xe2/dist-node/xe2-base-objects'
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { ESApertureEffect, ESPipeFence, ESGeoPolygon, ESHuman, ESImageLabel, ESPath, ESImageryLayer, ESTerrainLayer, ES3DTileset, ESAlarm, ESPolygonFence, ESDistanceMeasurement, ESHeightMeasurement, ESAreaMeasurement, ESDirectionMeasurement } from 'esobjs-xe2-plugin/dist-node/esobjs-xe2-plugin-main';
//ESLocationMeasurement出错
// //VUE3和EarthSDK2双向绑定
// import { createVueDisposer, toVueRef } from 'vue-xe2-plugin/dist-node/components/xe2/tools'
// const d = createVueDisposer(onBeforeUnmount)
const objm = new ESObjectsManager();
const onlineUrl = ref("https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}")
window.g_objm = objm //控制台打印
const xe2Container = ref(null)
const follow = ref(false)
let humanArr = []
onMounted(() => {
const dom = xe2Container.value;
if (!dom) return;
//监听每个视口创建
objm.viewerCreatedEvent.don((viewer) => {
//监听点击事件
viewer.clickEvent.don(e => {
console.log(e)
if(e.screenPosition && follow.value) {
viewer.pickPosition(e.screenPosition).then(position => {
humanArr.forEach(h => {
h.animation="walking"
h.smoothMove(position, 5)
})
})
}
})
viewer.hoverEvent.don((e) => {
viewer.pick(e.screenPosition, "hover").then(res => {
if (res && res.sceneObject) {
res.sceneObject.show = false
}
})
})
viewer.mouseMoveEvent.don((e) => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
viewer.pick(e.screenPosition, "mouseMove").then(res => {
})
})
})
//创建一个cesium视口,并且绑定一个div容器
objm.createCesiumViewer(dom)
//监听视口状态
objm.activeViewer.statusChanged.don((val) => {
console.log('监听视口的变化', val)
if(val == 'Created') {
//视口加载成功,飞行到视口位置
flyIn([114.05565611710809, 32.23032890173555, 550640.6629355564], [349.4892794691355, -50.19016063219766, 0.0023330016021228077], 2)
}
})
//json用来初始化基础场景
objm.jsonLoadingEvent.don((e) => {
switch (e.type) {
case "init":
console.log('json加载初始化')
break;
case "loading":
console.log('json正在加载')
break;
case "loaded":
console.log('json加载完成')
break;
default:
break;
}
}),
objm.json =
{
"asset": {
"type": "ESObjectsManager",
"version": "0.1.0",
"createdTime": "2022-06-17T05:54:41.744Z",
"modifiedTime": "2024-08-15T03:55:36.741Z",
"name": "图层管理"
},
"viewers": [
{
"id": "dffeff37-9e5f-4b4a-b6be-ff45866ec9d0",
"type": "ESCzmViewer",
"show": true,
"globeShow": true,
"ionAccessToken": "",
"apiKey": "",
"apiUrl": "",
"secretKey": "",
"speechVoiceMode": "",
"hoverTime": 2,
"debug": false,
"lonLatFormat": "DECIMAL_DEGREE",
"fov": 60,
"currentTime": 1723694400000,
"simulationTime": 1723651200000,
"timeSync": false,
"rain": 0,
"snow": 0,
"cloud": 0,
"fog": 0,
"depthOfField": 0,
"atmosphere": true,
"sun": true,
"moon": true,
"name": "undefined_ined"
}
],
"sceneTree": {
"root": {
"children": [
{
"name": "新建场景",
"children": [
{
"name": "全球影像",
"sceneObj": {
"id": "ae103185-08c7-4ed0-b6d4-15ad77bbbf66",
"type": "ESImageryLayer",
"url": "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
"rectangle": [
-180,
-90,
180,
90
],
"maximumLevel": 18,
"name": "全球影像",
"allowPicking": true
},
"children": []
}
]
},
{
"name": "白色多边形",
"sceneObj": {
"id": "ae8a1669-7a96-444c-be98-52271882b096",
"type": "ESGeoPolygon",
"name": "白色多边形",
"collision": false,
"allowPicking": true,
"filled": true,
"points": [
[
92.30165158602695,
37.73367318112731,
0
],
[
96.7317906007983,
31.18275916765977,
-3.1324159463573503e-9
],
[
108.61925826702146,
38.78492432980533,
-1.3969838619232178e-9
],
[
109.40519719194107,
38.646291090285246,
2.1339280972982942e-9
]
]
},
"children": []
},
{
"name": "红色多边形",
"sceneObj": {
"id": "47f0cb3a-c41e-45e5-aca3-c856229906c6",
"type": "ESGeoPolygon",
"name": "红色多边形",
"collision": false,
"allowPicking": true,
"filled": true,
"fillStyle": {
"color": [
1,
0,
0,
1
],
"material": "",
"materialParams": {},
"ground": false
},
"points": [
[
119.44521014612961,
49.984659637438604,
-1.3969838619232178e-9
],
[
108.18857245543923,
45.58726924876385,
0
],
[
129.56630372382782,
38.28146324973777,
1.6130980174698654e-9
],
[
139.05473862053634,
46.04777650297759,
-2.7152485655831642e-9
],
[
139.05473862053634,
46.04777650297759,
-2.7152485655831642e-9
]
]
},
"children": []
},
{
"name": "蓝色相机",
"sceneObj": {
"id": "660dd9b8-4971-477b-95b7-6094114772eb",
"type": "ESImageLabel",
"position": [
94.03816148546012,
44.18957674755954,
-5.276388813417216e-9
],
"name": "蓝色相机",
"allowPicking": true,
"renderMode": 4
},
"children": []
}
]
}
},
"viewCollection": [],
"lastView": {
"position": [
110.83065300892005,
34.521990035435024,
11467536.204733359
],
"rotation": [
3.053332494204976e-13,
-89.8898693403468,
0
]
}
}
//Cesium加载官方地形需要ionAccessToken
objm.activeViewer.ionAccessToken = "自己的token";
//添加地形图形
addTerrainLayer()
//添加影像图层
addImageLayer()
//监听当前激活视口变化
objm.activeViewerChanged.don((viewer)=> {
if (viewer.typeName == "ESUeViewer") {
viewer.sunSkyControlled = true
}
})
// create3DTileset()
//加载3dtilset
init3Dtiles()
})
//切换Cesium视口
const switchCesiumViewer = () => {
const dom = xe2Container.value;
if (!dom) return;
objm.switchToCesiumViewer(dom)
}
//切换UE视口
const switchUEViewer = () => {
const dom = xe2Container.value;
if (!dom) return;
objm.switchToUEViewer(dom, "http://localhost:8086/", "demo")
}
//加载影像图层
const addTerrainLayer = () => {
const sceneObj = objm.createSceneObject(ESTerrainLayer,'image123')
if (sceneObj) return
sceneObj.url = "ion://1"
}
//添加影像图层
const addImageLayer = () => {
const sceneObj = objm.createSceneObject(ESImageryLayer)
if (!sceneObj) return
sceneObj.url = "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"
//设置层级关系
sceneObj.zIndex = 10
}
//任意切换在线影像
const switchOnlineImage = (url) => {
//获取影像图层
const imageLayer = objm.getSceneObjectById('image123')
//设置图层的url地址
if (!imageLayer) return
imageLayer.url = url
}
//根据位置和姿态信息飞行定位
const flyIn = (position, rotation, duration) => {
objm.activeViewer.flyIn(position, rotation, duration)
}
let startTime = 1710864010000
let endTime = 1710950410000
const changeCurrentTime = ($event) => {
objm.activeViewer.currentTime = Number($event.target.value) * (endTime - startTime) + startTime
}
const changeCloud = ($event) => {
objm.activeViewer.cloud = Number($event.target.value)
}
const changeRain = ($event) => {
objm.activeViewer.rain = Number($event.target.value)
}
const changeSnow = ($event) => {
objm.activeViewer.snow = Number($event.target.value)
}
const changeAtmosphere = () => {
objm.activeViewer.atmosphere = !objm.activeViewer.atmosphere
}
//创建3DTileset
const create3DTileset = () => {
const tileset = objm.createSceneObject(ES3DTileset)
if (!tileset) return
tileset.url = "https://image.giiiis.com/shanghai/tileset.json"
tileset.materialMode = 'technology'
tileset.editing = true
window.tileset = tileset
//3dtileset需要先加载,做一个延迟
setTimeout(() => {
tileset.flyTo()
},2000)
}
const tileData = ref([
{
id: "tile1",
name: "倾斜数据",
url: "https://image.giiiis.com/dayanta/tileset.json"
}, {
id: "tile2",
name: "白模数据",
url: "https://image.giiiis.com/shanghai/tileset.json"
}, {
id: "tile3",
name: "点云数据",
url: "https://image.giiiis.com/dianyun/tileset.json"
}, {
id: "tile4",
name: "BIM数据",
url: "https://image.giiiis.com/bim/tileset.json"
}, {
id: "tile5",
name: "人工建模",
url: "https://image.giiiis.com/changfang/tileset.json"
}, {
id: "tile6",
name: "管线数据",
url: "https://www.pipeser.com/3dtiles/phipxrow1/tileset.json"
}
])
//初始化3DTileset数据
const init3Dtiles = () => {
tileData.value.forEach(item => {
const tileset = objm.createSceneObject(ES3DTileset, item.id)
if(tileset) {
tileset.url = item.url
}
})
}
//3DTileset根据id进行飞行定位
const flyToById = (id) => {
const tileset = objm.getSceneObjectById(id)
if (tileset) {
tileset.flyTo()
}
}
let measurementArr = []
//点位测量
const createESLocationMeasurement = () => {
const sceneObj = objm.createSceneObject(ESLocationMeasurement)
if(!sceneObj) return
sceneObj.editing = true
measurementArr.push(sceneObj)
}
//距离测量
const createESDistanceMeasurement = () => {
const sceneObj = objm.createSceneObject(ESDistanceMeasurement)
if(!sceneObj) return
sceneObj.editing = true
measurementArr.push(sceneObj)
}
//高度测量
const createESHeightMeasurement = () => {
const sceneObj = objm.createSceneObject(ESHeightMeasurement)
if(!sceneObj) return
sceneObj.editing = true
measurementArr.push(sceneObj)
}
//面积测量
const createESAreaMeasurement = () => {
const sceneObj = objm.createSceneObject(ESAreaMeasurement)
if(!sceneObj) return
sceneObj.editing = true
measurementArr.push(sceneObj)
}
//方位角测量
const createESDirectionMeasurement = () => {
const sceneObj = objm.createSceneObject(ESDirectionMeasurement)
if(!sceneObj) return
sceneObj.editing = true
measurementArr.push(sceneObj)
}
//清除测量
const destroyMeasurement = () => {
measurementArr.forEach(item => {
objm.destroySceneObject(item)
item = undefined
})
}
let fenceArr = []
//创建电子围栏
const createESPolygonFence = ($event) => {
const sceneObj = objm.createSceneObject(ESPolygonFence)
if (!sceneObj) return
sceneObj.materialMode = $event.target.value
sceneObj.height = 30
sceneObj.editing = true
fenceArr.push(sceneObj)
// window.fence = sceneObj
}
//清除围栏
const destroyfence = () => {
fenceArr.forEach(item => {
objm.destroySceneObject(item)
item = undefined
})
}
let pathArr = []
//创建路径
const createESPath = ($event) => {
const sceneObj = objm.createSceneObject(ESPath)
if (!sceneObj) return
sceneObj.materialMode = $event.target.value
//线样式设置,在父类中
sceneObj.stroked = true
sceneObj.strokeWidth = 10
sceneObj.speed = 40
sceneObj.editing = true
pathArr.push(sceneObj)
window.path = sceneObj
}
//清除路径
const destroyPath = () => {
pathArr.forEach(item => {
objm.destroySceneObject(item)
item = undefined
})
}
let alarmArr = []
//创建警告
const createESAlarm = ($event) => {
const sceneObj = objm.createSceneObject(ESAlarm)
if (!sceneObj) return
sceneObj.mode = $event.target.value
sceneObj.radius = 100
sceneObj.editing = true
alarmArr.push(sceneObj)
}
const destroyAlarm = () => {
alarmArr.forEach(item => {
objm.destroySceneObject(item)
item = undefined
})
}
let imageArr = []
//创建图片标签
const createESImageLabel = () => {
const sceneObj = objm.createSceneObject(ESImageLabel)
if (!sceneObj) return
sceneObj.editing = true
window.image = sceneObj
imageArr.push(sceneObj)
}
//创建人员
const createESHuman = ($event) => {
const sceneObj = objm.createSceneObject(ESHuman)
if (!sceneObj) return
sceneObj.editing = true
//人员样式设置
sceneObj.mode = $event.target.value
humanArr.push(sceneObj)
}
//创建贴地多边形
const createESGeoPolygon = () => {
const sceneObj = objm.createSceneObject(ESGeoPolygon)
if (!sceneObj) return
sceneObj.editing = true
sceneObj.filled = true
sceneObj.fillColor = [1, 1, 1, 1]
sceneObj.fillGround = true
window.p = sceneObj
sceneObj.pickedEvent.don((e) => {
const result = PickedInfo.getFinalAttachedInfo(e)
switch (result) {
case 'hover':
sceneObj.fillColor = [0, 1, 0, 1]
break;
case 'mouseMove':
sceneObj.fillColor = [1, 1, 1, 1]
break;
default:
sceneObj.fillColor = [1, 0, 0, 1]
break;
}
})
}
//管道电子围栏
const createESPipeFence = ($event) => {
const sceneObj = objm.createSceneObject(ESPipeFence)
if (!sceneObj) return
sceneObj.editing = true
//样式设置
sceneObj.materialMode = $event.target.value
sceneObj.width = 30
sceneObj.height = 30
}
const createESApertureEffect = () => {
const sceneObj = objm.createSceneObject(ESApertureEffect)
if(!sceneObj) return
sceneObj.editing = true
//半径设置
sceneObj.radius = 500
window.aperture = sceneObj
}
</script>
<style>
body,
html,
#app,
.container {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.switch {
position: absolute;
right: 10px;
top: 20px;
}
.header {
color: azure;
position: absolute;
left: 8px;
top: 50px;
}
.mode {
color: azure;
position: absolute;
left: 502px;
top: 50px;
}
.weather {
background-color:white;
position: absolute;
right: 10px;
top: 150px;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.control-group {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.tile {
display: flex;
flex-direction: column;
align-items: flex-start;
position: absolute;
left: 10px;
top: 100px;
padding: 10px;
}
</style>