cesium 添加点位自定义弹窗跟随场景移动 完整代码演示可直接copy使用
1 效果图:
2 深入理解
就是原始点位的数据
id>property
点位真实渲染到球体上的笛卡尔坐标系
id>_polyline 的路径下 可以通过
3 代码示例
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.85/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
<script src="https://unpkg.com/@turf/turf/turf.min.js"></script>
<script src="https://cesium.com/downloads/cesiumjs/releases/1.85/Build/Cesium/Cesium.js"></script>
<script src="https://cdn.staticfile.net/vue/2.7.0/vue.min.js"></script>
</head><body>
<div id="app">
<button @click="mapClick">主动触发点位弹窗</button>
<button @click="removeLayer('site_layer')">清除点位图层</button>
<div id="cesiumContainer">
<div id="popup">
<div class="cesium-popup" @closeMap="closeMapPop" v-if="popVisible" ref="overlay">
<div class="pop_header">
<p class="rhpk_info"> {{ overlayChartObj.name }}基本信息</p>
<div class="map_close" @click="closeMapPop">x</div>
</div>
<sitePop>
<div class="button_box">
<div>自动监测</div>
</div>
</sitePop>
</div>
</div>
</div>
</div><script>
var viewer = null
new Vue({
el: '#app',
data: {
popVisible: false,
overlayChartObj: {},
list: [
{ longitude: 109.306058, latitude: 30.86751, id: 0, name: "标点一" },
{ longitude: 109.306058, latitude: 30.56751, id: 1, name: "标点二" },
]
},
mounted() {
this.mapCreate()
},
methods: {
async mapCreate() {
Cesium.Ion.defaultAccessToken =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2ZjZlMzAxNS1jY2ZmLTQ0MzctYTE1MS0zNzMxZjhkZjlhYTgiLCJpZCI6MTIyNTg4LCJpYXQiOjE2NzQ5NzMxNTB9.GKIVHIsKN-AWd4vjLOIPm9Fji8tIEvZd5AXf-rTvFk0";
viewer = new Cesium.Viewer('cesiumContainer', {
geocoder: false,
homeButton: false,
animation: false,
fullscreenButton: false,
sceneModePicker: false,
timeline: true, 。
navigationHelpButton: false,
baseLayerPicker: false,
infoBox: false,
scene3DOnly: false,
selectionIndicator: false,
baselLayerPicker: false,
});
let terrainProvider = Cesium.createWorldTerrain({ //添加世界地形能看到山脉的高低起伏
requestVertexNormals: true, //开启地形光照
requestWaterMask: true, // 开启水面波纹
});
viewer.terrainProvider = terrainProvider;
viewer.debugShowFramesPerSecond = true//显示当前的帧率信息,这样你就可以实时观察到地图的渲染性能
viewer.scene.screenSpaceCameraController.minimumZoomDistance = 1;// 设置了摄像机的最小缩放距离
viewer.camera.setView({ // 相机视口
destination: Cesium.Cartesian3.fromDegrees(109.306058, 30.86751, 8000),
orientation: {
heading: Cesium.Math.toRadians(0), //控制视口左右旋转,也就是沿Y轴旋转,0时为正北方向
pitch: Cesium.Math.toRadians(-25), // 控制视口上下旋转,也就是沿X轴旋转,-90时为俯视地面
roll: 0, // 控制视口翻转角度,也就是沿Z轴旋转,0时为不翻转
},
//奉节 坐标
});
this.handlePinClick(); // 注册点位点击事件
this.bindMapMove(); // 注册场景移动事件
this.renderSiteCesiumPoint(this.list)
},
}
})
</script></body>
</html>
完整代码示例
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><link href="https://cesium.com/downloads/cesiumjs/releases/1.85/Build/Cesium/Widgets/widgets.css" rel="stylesheet"><script src="https://unpkg.com/@turf/turf/turf.min.js"></script><script src="https://cesium.com/downloads/cesiumjs/releases/1.85/Build/Cesium/Cesium.js"></script><script src="https://cdn.staticfile.net/vue/2.7.0/vue.min.js"></script><style>#cesiumContainer {width: 1920px;height: 1080px;}#cesiumContainer .cesium-widget-credits {display: none;}.cesium-popup {position: relative;width: 267px;min-height: 152px;background: pink;/* background: url(~@/assets/images/mapPop.png) no-repeat; */background-size: cover;}.cesium-popup .pop_header {width: 431px;height: 57px;line-height: 57px;/* background: url(~@/assets/images/mapHeader.png) no-repeat 100% 100%; */}.cesium-popup .rhpk_info {font-size: 18px;font-weight: bold;color: #fff;padding-left: 70px;box-sizing: border-box;}.cesium-popup .map_close {position: absolute;top: 16px;right: 20px;width: 29px;height: 29px;/* background: url(~@/assets/images/mapClose.png) no-repeat 100% 100%; */cursor: pointer;}.cesium-popup .map_con {padding: 20px 20px;width: 100%;box-sizing: border-box;}.cesium-popup .info {display: flex;font-size: 16px;color: #fff;margin-bottom: 20px;}.cesium-popup .title {width: 85px;font-weight: 400;color: #57bcd2;}.cesium-popup .button_box {position: absolute;bottom: 30px;left: 0px;width: 100%;display: flex;justify-content: flex-end;}.cesium-popup .button_box div {width: 100px;height: 27px;/* background: url(~@/assets/images/mapButton.png) no-repeat 100% 100%; */line-height: 27px;text-align: center;cursor: pointer;margin: 0 10px;}</style>
</head><body><div id="app"><button @click="mapClick">主动触发点位弹窗</button><button @click="removeLayer('site_layer')">清除点位图层</button><div id="cesiumContainer"><div id="popup"><div class="cesium-popup" @closeMap="closeMapPop" v-if="popVisible" ref="overlay"><div class="pop_header"><p class="rhpk_info"> {{ overlayChartObj.name }}基本信息</p><div class="map_close" @click="closeMapPop">x</div></div><sitePop><div class="button_box"><div>自动监测</div></div></sitePop></div></div></div></div><script>var viewer = nullnew Vue({el: '#app',data: {popVisible: false,overlayChartObj: {},list: [{ longitude: 109.306058, latitude: 30.86751, id: 0, name: "标点一" },{ longitude: 109.306058, latitude: 30.56751, id: 1, name: "标点二" },]},mounted() {this.mapCreate()},methods: {async mapCreate() {Cesium.Ion.defaultAccessToken ="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2ZjZlMzAxNS1jY2ZmLTQ0MzctYTE1MS0zNzMxZjhkZjlhYTgiLCJpZCI6MTIyNTg4LCJpYXQiOjE2NzQ5NzMxNTB9.GKIVHIsKN-AWd4vjLOIPm9Fji8tIEvZd5AXf-rTvFk0";viewer = new Cesium.Viewer('cesiumContainer', {geocoder: false,homeButton: false, animation: false, fullscreenButton: false,sceneModePicker: false,timeline: true, 。navigationHelpButton: false, baseLayerPicker: false, infoBox: false, scene3DOnly: false, selectionIndicator: false,baselLayerPicker: false,});let terrainProvider = Cesium.createWorldTerrain({ //添加世界地形能看到山脉的高低起伏requestVertexNormals: true, //开启地形光照requestWaterMask: true, // 开启水面波纹});viewer.terrainProvider = terrainProvider;var lastCameraHeight = 0;var heightStableCount = 0;var threshold = 5; // 高度稳定的阈值var maxStableCount = 30; // 达到稳定的帧数function isTerrainProvider() {var cameraHeight =viewer.camera.positionCartographic.height;if (Math.abs(cameraHeight - lastCameraHeight) < threshold) {heightStableCount++;} else {heightStableCount = 0;}if (heightStableCount >= maxStableCount) {console.log("地形加载完成");// 在这里执行地形加载完成后的操作viewer.scene.preRender.removeEventListener(isTerrainProvider);}lastCameraHeight = cameraHeight;}viewer.debugShowFramesPerSecond = true//显示当前的帧率信息,这样你就可以实时观察到地图的渲染性能viewer.scene.screenSpaceCameraController.minimumZoomDistance = 1;// 设置了摄像机的最小缩放距离viewer.camera.setView({ // 相机视口destination: Cesium.Cartesian3.fromDegrees(109.306058, 30.86751, 8000),orientation: {heading: Cesium.Math.toRadians(0), //控制视口左右旋转,也就是沿Y轴旋转,0时为正北方向pitch: Cesium.Math.toRadians(-25), // 控制视口上下旋转,也就是沿X轴旋转,-90时为俯视地面roll: 0, // 控制视口翻转角度,也就是沿Z轴旋转,0时为不翻转},//奉节 坐标});this.handlePinClick(); // 注册点位点击事件this.bindMapMove(); // 注册场景移动事件this.renderSiteCesiumPoint(this.list)},renderSiteCesiumPoint(projectList) {this.removeLayer('site_layer')for (let i = 0; i < projectList.length; i++) {const pro = projectList[i];let longitude = pro.longitude || 0let latitude = pro.latitude || 0let imgUrl = `./site.png`;viewer.entities.add({position: Cesium.Cartesian3.fromDegrees( // 设置点位的经纬度和高度longitude,latitude,240),name: pro.name,id: `site_layer_${pro.id}`, // site_layer就是自定义layerName后续可通过这个移除property: pro,polyline: {show: true, //是否显示,默认显示// 关键点在设置一条竖直的线positions: Cesium.Cartesian3.fromDegreesArrayHeights([longitude,latitude,0,longitude,latitude,240,]),width: 1, //线的宽度(像素),默认为1material: Cesium.Color.fromCssColorString("#069BBF").withAlpha(1),},billboard: {width: 33, // 点位的大小height: 33,image: imgUrl,verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 设置垂直方向的对齐方式},});}},removeLayer(layerName) { // 根据图层名移除对应的图层组let entityList = [];let count = 0while (count < 8) {viewer.entities.values.forEach(function (entity) {if (entity._id.includes(layerName)) {viewer.entities.remove(entity);}});count++;}},// 点击地图上的点handlePinClick(data = null, typePop = null) {const cesiumViewer = viewer;const tt = this;if (data != null && typePop != null) {console.log('主动触发', data, typePop)tt.overlayChartObj = Object.assign(data, {layer: typePop});tt.getProjDetailPop({x: 951.25,y: 600}, data);return}const handle3D = new Cesium.ScreenSpaceEventHandler(cesiumViewer.scene.canvas);handle3D.setInputAction((movement) => {const pick = cesiumViewer.scene.pick(movement.position);console.log("pick===>", pick, pick.id); // pick.id是点击后获取对应的实体console.log("pick===>",pick.id.polyline.positions.value.getValue());if (!pick.id) {console.log("清除监听事件===>", pick, pick.id);this.popVisible = false;// 清除监听事件cesiumViewer.scene.postRender.removeEventListener(this.bindMapMove);return;}const obj = pick.id.property;// 解决点击不同点数据不更换问题if (tt.overlayChartObj != {}) {tt.popVisible = false;tt.overlayChartObj = {};}const coordinate = movement.position;console.log("coordinate===>", coordinate);if (pick.id._id.includes("rhpwk_layer")) {tt.overlayChartObj = Object.assign(obj, {layer: "rhpwk_layer"});tt.getProjDetailPop(coordinate, obj);} else if (pick.id._id.includes("site_layer")) {tt.overlayChartObj = Object.assign(obj, {layer: "site_layer" //使用site_layer类型的点位弹窗});tt.getProjDetailPop(coordinate, obj);} else if (pick.id._id.includes("camera_layer")) {tt.overlayChartObj = Object.assign(obj, {layer: "camera_layer"});tt.getProjDetailPop(coordinate, obj);} else if (pick.id._id.includes("wry_layer")) {tt.overlayChartObj = Object.assign(obj, {layer: "wry_layer"});tt.getProjDetailPop(coordinate, obj);}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);},getProjDetailPop(coordinate, obj) {this.showOverlayChart(coordinate, obj);},// 显示showOverlayChart(position, data) {const pop = document.getElementById("popup");pop.style.position = "absolute";pop.style.top = position.y + "px";pop.style.left = position.x + "px";pop.style.zIndex = 99;this.overlayChartObj = data;this.popVisible = true;},bindMapMove() {const cesiumViewer = viewer;console.log('cesiumViewer', cesiumViewer)const tt = this;cesiumViewer.scene.preRender.addEventListener(() => {if (!tt.popVisible) return;const scratch = Cesium.Cartesian2();const position = Cesium.Cartesian3.fromDegrees(Number(tt.overlayChartObj.longitude),Number(tt.overlayChartObj.latitude),300);const canvasPosition = cesiumViewer.scene.cartesianToCanvasCoordinates(position,scratch);if (Cesium.defined(canvasPosition)) {tt.setPopPosition(canvasPosition);}});},setPopPosition(position) {const pop = document.getElementById("popup");pop.style.top = position.y + "px";pop.style.left = position.x + "px";},closeMapPop() {this.popVisible = false;// 清除监听事件viewer.scene.postRender.removeEventListener(this.bindMapMove);},// 主动触发点位弹窗mapClick() {this.handlePinClick(this.list[0], 'site_layer') // 点位数据 及弹窗类型},}})</script></body></html>