这篇笔记主要记录
- 使用
primitive加载点位 - 使用
primitive删除点位 - 使用
primitive显示隐藏点位 - 给点位增加点击弹窗事件
地图打点是常见的需求,可以通过Entity或者Primitive实现,通过Primitive加载大量点位性能更好。
使用primitive加载点位
通过PrimitiveCollection添加 new Cesium.BillboardCollection(), 文档描述
定义增加点位方法,addedBillboards为添加的点位列表,把点位存起来,方便点位清除
let addedBillboards = [] // 点位列表
const imageUrl = '/yxkj.png'
const billboards = scene.primitives.add(new Cesium.BillboardCollection());
const addBillboard = () => {
// 随机生成50个经纬度点位
for (let i = 0; i < 50; i++) {
const longitude = 113.5 + Math.random() * 5
const latitude = 24.5 + Math.random() * 5.5
// 因为通过`primitives.add()`方法返回的就是传的参数`primitive`,
// 所以`billboards`可以调用`new Cesium.BillboardCollection`的`add`方法,
const billboard = billboards.add({
position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
image: imageUrl,
scale: 1.0,
})
// 添加的点位列表,方便清除点位使用
addedBillboards.push(billboard)
}
// 要请求渲染 因为使用了配置 requestRenderMode: true 不然地图会不响应 要操作地图点位才会出现
viewer.scene.requestRender()
}
上面代码中通过BillboardCollection的add方法,参考文档
如下图,点位正常上图
使用primitive删除点位
先前在添加的方法中,我们定义了addedBillboards,保存了添加的点位,那么我们就调用remove方法清除,看下remove文档,传入参数billboard就可以
const removeBillboard = () => {
if (addedBillboards.length > 0) {
for (const billboard of addedBillboards) {
billboards.remove(billboard)
}
addedBillboards.length = 0 // 点位都清除后 把addedBillboards清空
} else {
alert('没有点位可以清除!')
}
viewer.scene.requestRender()
}
点位正常清除GIF
使用primitive显示隐藏点位
看下文档描述, 有show属性,默认为true,我们如果想切换可见性,添加的时候默认给隐藏,然后点击切换按钮的时候,切换show属性,这样第一次点击就会是可见的
隐藏可见性代码
// 加载点位 可见性变成动态传参
const addBillboard = (visibility = true) => {
for (let i = 0; i < 50; i++) {
const longitude = 113.5 + Math.random() * 5
const latitude = 24.5 + Math.random() * 5.5
const billboard = billboards.add({
position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
image: imageUrl,
scale: 1.0,
show: visibility,
})
addedBillboards.push(billboard)
}
viewer.scene.requestRender()
}
// 默认给隐藏
addBillboard(false)
// 切换可见性
function toggleBillboardVisibility() {
for (const billboard of addedBillboards) {
billboard.show = !billboard.show
}
viewer.scene.requestRender()
}
给点位增加点击弹窗事件
我们经常需要加载点位信息,比如这个点位是一个加油站,我们可能会想知道这个加油站名称、位置、负责人联系方式、姓名、油品种类等等。 cesium支持点击事件,我们要做的事,确保我们点击这个点位,能够获取这个点位信息。
看下cesium事件文档,
- 用户事件处理器,
new Cesium.ScreenSpaceEventHandler(element)接受的参数是要执行用户事件的元素 - 用户输入事件方法,
setInputAction(action, type, modifier)用户输入事件触发的函数 - 事件类型 这里我们要加的是
LEFT_CLICK,左键点击鼠标
写方法啦 先改造下先前添加点位方法,写一点数据到点位信息里去
const addBillboard = (visibility = true) => {
for (let i = 0; i < 50; i++) {
const longitude = 113.5 + Math.random() * 5
const latitude = 24.5 + Math.random() * 5.5
const billboard = billboards.add({
position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
image: imageUrl,
scale: 1.0,
show: visibility,
id: {
// 把数据点位放到id里,看了下文档没有data属性,而id是文档提供给我们的可以任何数据类型
data: {
name: '点位' + i,
description: ' 🐷 🐷.',
},
},
})
addedBillboards.push(billboard)
}
viewer.scene.requestRender()
}
文档里没有data属性,而id是文档提供给我们的,可以任何数据类型,所以把数据放到id里
添加事件方法
function addCesiumEvent() {
viewer.screenSpaceEventHandler.setInputAction(function anyname(movement) {
const pickedObject = viewer.scene.pick(movement.position)
// 判断我们点击了点位 并且点位是primitive
if (
Cesium.defined(pickedObject) &&
pickedObject.primitive instanceof Cesium.Billboard
) {
const billboard = pickedObject.primitive
let { data } = billboard.id
alert('点击点位: ' + data.name + data.description)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
验证下, 可以看到每个点位点击都可以获取到对应的点位id
完整代码
<template>
<div>
<div id="cesiumContainer" ref="cesiumContainer"></div>
<div id="controls">
<button @click="addBillboard">添加点位</button>
<button @click="removeBillboard">清除点位</button>
<button @click="toggleBillboardVisibility">显示/隐藏点位</button>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import * as Cesium from 'cesium'
import 'cesium/Build/Cesium/Widgets/widgets.css'
const cesiumContainer = ref(null)
let viewer
let billboards
const addedBillboards = []
const imageUrl = '/yxkj.png'
const defaultAccessToken =
'你的ion token'
function initCesium() {
viewer = new Cesium.Viewer(cesiumContainer.value, {
geocoder: false,
homeButton: false,
sceneModePicker: false,
baseLayerPicker: false,
navigationHelpButton: false,
animation: false,
timeline: false,
fullscreenButton: false,
vrButton: false,
selectionIndicator: false,
maximumRenderTimeChange: Infinity, // 无操作时自动渲染帧率,设为数字会消耗性能,Infinity为无操作不渲染
shadows: false, // 是否显示光照投射的阴影
// targetFrameRate: 10, // 帧率
shouldAnimate: false,
requestRenderMode: true,
cesiumLogo: false,
// sceneMode: Cesium.SceneMode.SCENE3D,
// terrainExaggeration: 3,
infoBox: false,
})
}
// 增加点位
const addBillboard = (visibility = true) => {
for (let i = 0; i < 50; i++) {
const longitude = 113.5 + Math.random() * 5
const latitude = 24.5 + Math.random() * 5.5
const billboard = billboards.add({
position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
image: imageUrl,
scale: 1.0,
show: visibility,
id: {
data: {
name: '点位' + i,
description: ' 🐷 🐷.',
},
},
})
addedBillboards.push(billboard)
}
viewer.scene.requestRender()
}
// 清除点位
const removeBillboard = () => {
if (addedBillboards.length > 0) {
for (const billboard of addedBillboards) {
billboards.remove(billboard)
}
addedBillboards.length = 0 // Clear the array after removing all billboards
} else {
alert('No billboards to remove!')
}
viewer.scene.requestRender()
}
// 显示/隐藏点位
function toggleBillboardVisibility() {
// 如果没有打点 就打点并默认隐藏
if (!addedBillboards.length) {
addBillboard(false)
}
for (const billboard of addedBillboards) {
billboard.show = !billboard.show
}
viewer.scene.requestRender()
}
// 点击事件
function addCesiumEvent() {
viewer.screenSpaceEventHandler.setInputAction(function anyname(movement) {
const pickedObject = viewer.scene.pick(movement.position)
if (
Cesium.defined(pickedObject) &&
pickedObject.primitive instanceof Cesium.Billboard
) {
const billboard = pickedObject.primitive
let { data } = billboard.id
alert('点击点位: ' + data.name + data.description)
// Perform any action you want with the clicked billboard
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
onMounted(() => {
Cesium.Ion.defaultAccessToken = defaultAccessToken
initCesium()
viewer.cesiumWidget.creditContainer.style.display = 'none'
billboards = viewer.scene.primitives.add(new Cesium.BillboardCollection())
addCesiumEvent()
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(118.0, 27.0, 1750000.0),
})
})
</script>
<style scoped>
@import url('https://cesium.com/downloads/cesiumjs/releases/1.85/Build/Cesium/Widgets/widgets.css');
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
#controls {
position: absolute;
top: 10px;
left: 10px;
z-index: 1;
background: rgba(255, 255, 255, 0.8);
padding: 10px;
border-radius: 5px;
}
button {
margin: 5px;
padding: 10px;
}
</style>