一、点位上图
①在Cesium中,每个自定义的地图元素被视为一个entity对象,如果我们要添加点位到地图上,那就必须先创建一个entity对象。
var entity = new Cesium.Entity({
position: position,
});
以上代码我们创建了一个entity对象,只需要给予一个坐标参数就可以创建成功。
②但是,仅仅只是一个坐标点在一般情况下是没办法满足我们的需求的,大多数时候我们都需要为我们的点位添加一个icon图标或者点位作为指示。这里就需要用到它另外一个参数,billboard。
// 若是没有配置billboard并且不把这个参数设置为undefined,则可能会显示系统自带的billboard。
var billboard = new Cesium.BillboardGraphics({
image: 'path/to/image.png',
scale: 1.0,
width: 30, // 图标的宽度
height: 30, // 图标的高度
depthTest: false, // 禁用深度测试
disableDepthTestDistance: Number.POSITIVE_INFINITY, // 禁用深度测试
// 调整图标的位置
pixelOffset: {
x: 0,
y: -12
}
});
entity.billboard = billboard
③有时候我们还想在点位图标下方添加简短的文本名称,这个时候可以使用label这个参数
var label = new Cesium.LabelGraphics({
text: entity.name,
scale: 0.5,
pixelOffset: new Cesium.Cartesian2(0, 15), // 调整文本位置偏移
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 1.0,
style: Cesium.LabelStyle.FILL_AND_OUTLINE
});
entity.label = label
④至此,常用的点位设置已经完成,最后把点位加到地图中,大功告成。
viewer.entitys.add(entity)
二、点击弹窗
地图上加了点位之后,虽然显得没那么单调了,但是如果我们跟地图的互动仅仅只有拖动缩放,那可能也是相对死板无趣的,这个时候就可以考虑多添加一些交互事件,譬如点击图标的时候出现弹窗。
这里稍微讲一下加入弹窗的方法和原理。
我们没办法像插入点位那样,把我们的弹窗写成entity直接插入到地图内部,因为entity说到底也是有一定限制的,它大概率不能符合我们插入弹窗的需求。
那既然没办法从内部攻破,我们就在外部进行操作,让弹窗看起来好像就是在地图内部中。
总结起来就是:
1、在浏览器的视图中用绝对定位加入我们的弹窗html元素
2、定义每次点击地图触发的事件,获取到相关经纬度数据,并且判断是否点击到了点位。
3、若是判断是点击到了点位,那么我们就可以获取到点击到的entity的信息。拿到这个信息就可以把对应信息显示在弹窗上。
4、拿到entity的信息里面有经纬度的信息,我们需要把经纬度信息转化成浏览器视图中x,y坐标,这样就可以根据这个坐标来定位我们的弹窗,让弹窗显示在对面点位上方。
5、监听地图的缩放和拖动事件,时刻去改变已显示弹窗的位置,达到视角如何变化,弹窗依旧处于点位上方的效果。
①首先要明白,cesium没有让你把弹窗插到它组件内的渠道,所以我们需要在html代码中添加我们自己的弹窗,还可以自定义样式。
<div class="info_box" ref="infoBox" id="infobox">
<div class="info_title">
<img src="../../assets/images/map/u93.svg" alt="" />
<p>{{ modalData.name }}</p>
<i class="el-icon-close" @click="closeInfoBox"></i>
</div>
<div class="info_body">
<img src="../../assets/images/map/u94.svg" alt="" />
<div class="info_content">
<div
class="content_line"
v-for="(val, key, i) in modalData"
:key="i"
v-if="key != 'name'"
>
<p class="text">{{ key }}</p>
<p class="val">{{ val }}</p>
</div>
</div>
</div>
</div>
②上面的代码看看就行了,是我个人的弹窗代码,各位可以根据自己的需求写一个弹窗和弹窗样式。接下来我们可以创建一个infobox对象,这个是cesium自带的对象,可以让我们控制html页面元素的属性。
this.infoBox = new Cesium.InfoBox(document.getElementById("infobox"));
③监听地图点击事件,判断是否点击到了点位。
// 监听 Viewer 的 pick 事件
this.viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
// 获取点击的位置
var pickedObject = that.viewer.scene.pick(movement.position);
// 判断是否选中了一个实体
if (Cesium.defined(pickedObject) && pickedObject.id instanceof Cesium.Entity) {
var entity = pickedObject.id;
if (entity.position) {
// 显示弹窗
that.infoBox.container.style.visibility = 'visible';
// 获取位置信息
that.entityPosition = entity.position.getValue(that.viewer.clock.currentTime);
// 传递数据,由于我定义了一个map.js文件,所以没办法把点位数据直接传递给页面,只能用eventBus传递两个文件的数据
eventBus.$emit('data-changed', entity.properties)
} else {
that.infoBox.container.style.visibility = 'hidden';
}
} else {
// 隐藏弹窗
that.infoBox.container.style.visibility = 'hidden';
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
④监听拖动和缩放事件,并且时时改变弹窗位置,让弹窗不管如何都一直在点位上方。(这里要注意弹窗元素的层级问题,z-index)
// 监听 Viewer 的 postRender 事件,在地图移动时更新弹窗位置
this.viewer.scene.postRender.addEventListener(function () {
try {
if (that.entityPosition !== null) {
that.modalSetting()
}
} catch (error) {
console.log(error)
}
});
// 弹窗位置设置事件
modalSetting() {
let screenPosition = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.viewer.scene, this.entityPosition);
if (screenPosition) {
let leftOffset = screenPosition.x - this.infoBox.container.clientWidth / 2 + 225;
let topOffset = screenPosition.y - this.infoBox.container.clientHeight - 20;
this.infoBox.container.style.left = leftOffset + 'px';
this.infoBox.container.style.top = topOffset + 'px';
}
}
三、为什么我的点位图标那么模糊?
这是因为cesium像素的设置问题,这里只需要几行代码设置便可以切换到高清画质。
this.viewer.scene.fxaa = false
this.viewer.scene.postProcessStages.fxaa.enabled = false
if (Cesium.FeatureDetection.supportsImageRenderingPixelated()) { //判断是否支持图像渲染像素化处理
this.viewer.resolutionScale = window.devicePixelRatio;
}