1. 前言
本篇文章将讲述一个使用cesium实现的非常基础的小功能——鼠标悬浮在cesium椭球体上的时候,显示对应的经纬度值。通过该功能的实现,了解与其相关的构造函数和属性。
2. 在cesium中添加label标签
2.1 回顾Entity
在添加标签前,需要知道实体Entity的概念。Cesium中的所有空间数据都使用Entity API来表示。Entity API以一种有效提供灵活的可视化的方式,以便对Cesium进行渲染。
在八青妹的上篇文章Cesium(六)加载不同的矢量数据kml中浅浅提到了Entity,代码如下:
const dataSource = await viewer.dataSources.add(
Cesium.KmlDataSource.load("/bikeRide.kml", options)
);
const rider = dataSource.entities.getById("tour");
//在 Cesium 中将视图飞到一个名为 `tour` 的实体。
viewer.flyTo(rider).then(function () {
……
});
这里用到了实体中的id对象,该id是kml文件中的,可以在添加到cesium之后,在实体中拿到,然后来使用。
2.2 实体位置 Cesium.PositionProperty()
Cesium.PositionProperty 是用于定义实体(Entity)在场景中位置的属性。它可以表示一个静态位置、一个随时间变化的位置,或者其他位置属性。使用方法如下:
viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222), });
2.3 实体外观之 Cesium.LabelGraphics(options)
下面介绍的是实体中的label文字标签,构造函数new Cesium.LabelGraphics(options)用来实现包含实体位置的二维标签。options的常用可选项如下:
- text:标签显示的文本内容。
- font:标签文本的字体样式和大小,例如
'24px sans-serif'。 - fillColor:标签文本的填充颜色。
- outlineColor:标签文本的轮廓颜色。
- outlineWidth:标签文本的轮廓宽度。
- style:标签文本的样式,可以是
Cesium.LabelStyle.FILL、Cesium.LabelStyle.OUTLINE或Cesium.LabelStyle.FILL_AND_OUTLINE。 - showBackground:是否显示标签的背景。
- backgroundColor:标签背景的颜色。
- backgroundPadding:标签背景的填充大小。
- horizontalOrigin:标签文本的水平对齐方式,可以是
Cesium.HorizontalOrigin.LEFT、Cesium.HorizontalOrigin.CENTER或Cesium.HorizontalOrigin.RIGHT。 - verticalOrigin:标签文本的垂直对齐方式,可以是
Cesium.VerticalOrigin.TOP、Cesium.VerticalOrigin.CENTER或Cesium.VerticalOrigin.BOTTOM。 - pixelOffset:标签文本的像素偏移量,用于调整标签位置。
- pixelOffsetScaleByDistance:根据距离缩放像素偏移量。
- scale:标签的缩放比例。
- translucency:标签的透明度。
- show:是否显示标签。
2.4 实体外观之 Cesium.BillboardGraphics(options)
除了文字标签,也常常需要添加图片logo-billboard,构造函数new Cesium.BillboardGraphics(options)用于处理图像或图标的视觉元素。options的常用可选项如下:
- image:图像的路径,可以是 URL 或 Base64 编码的图像数据。
- show:是否显示图像。
- scale:缩放比例。
- horizontalOrigin:水平对齐方式,可以是
Cesium.HorizontalOrigin.LEFT、Cesium.HorizontalOrigin.CENTER或Cesium.HorizontalOrigin.RIGHT。 - verticalOrigin:垂直对齐方式,可以是
Cesium.VerticalOrigin.TOP、Cesium.VerticalOrigin.CENTER或Cesium.VerticalOrigin.BOTTOM。 - pixelOffset:像素偏移量,用于调整图像位置。
- color:图像的颜色。
- rotation:旋转角度(弧度)。
- alignedAxis:旋转轴。
- heightReference:高度参考。
- width:图像宽度。
- height:图像高度。
- scaleByDistance:根据距离缩放图像大小。
- translucency:透明度。
- sizeInMeters:指定图像的大小是否以米为单位。
- distanceDisplayCondition:距离显示条件,控制图像显示的距离范围。
- imageSubRegion:图像的子区域,用于显示图像的部分区域。
2.5 静态效果
接下来,将positon、label、billboard相结合,在指定的坐标上展示文字和图标。
// 创建一个 Cesium 场景
var viewer = new Cesium.Viewer('cesiumContainer');
// 添加一个实体用于显示标签和图标
var entity = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222),
label: {
text: 'Hello, Cesium!',
font: '24px sans-serif',
fillColor: Cesium.Color.WHITE,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM
},
billboard: {
image: '/vite.svg', // 图标的路径
width: 32, // 图标宽度
height: 32, // 图标高度
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -50) // 图标偏移量
}
});
// 定位到标签位置
viewer.zoomTo(entity);
效果如下:
除了positon、label、billboard这个属性,还有rectangle(设置矩形)、polygon(设置多边形)、polyline(设置多线段)等多种选型可供使用。可查看cesium- Entity官网了解。
3.获取鼠标当前经纬度
在上面案例的基础上添加三个功能,一是鼠标悬浮mouse over如何在cesium上监听,二是如何获取当前鼠标位置的坐标,三是在label上显示该坐标。
3.1 添加鼠标移动事件监听器
使用 Scene 的 screenSpaceCameraController 来监听鼠标移动事件。
const scene = viewer.scene;
const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
3.2 获取鼠标位置的地理坐标
用户输入事件类型使用Cesium.ScreenSpaceEventType来定义。可选择的属性有(来源官网cesium/ScreenSpaceEventType):
LEFT_DOWN: 当左键按下时触发。LEFT_UP: 当左键释放时触发。LEFT_CLICK: 当左键点击时触发。LEFT_DOUBLE_CLICK:当左键双击时触发。RIGHT_DOWN:当右键按下时触发。RIGHT_UP:当右键释放时触发。RIGHT_CLICK: 当右键点击时触发。MIDDLE_DOWN:当中键按下时触发。MIDDLE_UP:当中键释放时触发。MIDDLE_CLICK:当中键点击时触发。MOUSE_MOVE: 当鼠标移动时触发。WHEEL:当鼠标滚轮滚动时触发。PINCH_START:当捏合手势开始时触发。PINCH_END: 当捏合手势结束时触发。PINCH_MOVE: 当捏合手势移动时触发。
结合上述两个概念,看下使用案例:
const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
// 鼠标移动监听
handler.setInputAction(function (event) {
console.log('MOUSE_MOVE:',event);
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
打印出来的event如下所示:
具备开始坐标和结束坐标。开始坐标指的移动前一步的坐标,结束坐标为当前坐标。
viewer.camera.pickEllipsoid(windowPosition, ellipsoid, result)是cesium相机中用户从鼠标位置获取对应地球表面(椭球体)上的三维坐标的方法。根据和]鼠标的位置和相机的视角,返回地球表面(椭球体)上的笛卡尔坐标(Cartesian3)。scene.globe.ellipsoid表示地球的椭球体对象。写法如下
const cartesian = viewer.camera.pickEllipsoid(
event.endPosition,
scene.globe.ellipsoid,
);
如果鼠标光标位于地球表面(椭球体)上,pickEllipsoid 会返回一个 Cartesian3 对象,包含该点的三维坐标(经度、纬度和高度),如果光标不在椭球体上,返回值将是 undefined。所以我们在显示经纬度的时候要判断下是否在椭球体上。获得Cartesian3后,需要将其转为经纬度。写法如下:
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(2);
const latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(2);
console.log("经度:" + longitude, "---纬度:" + latitude);
3.3 显示坐标信息
最后,显示的坐标与实体上的label标签进行绑定。
entity.label.text =
`经度: ${` ${longitudeString}`.slice(-7)}\u00B0` +
`\n纬度: ${` ${latitudeString}`.slice(-7)}\u00B0`;
这里可以更改 entity.label上的属性信息,也可以更改entity.billboard上的属性信息,例如通过 entity.billboard.scale、 entity.billboard.color等直接更改。
4. 综合
onMounted(async () => {
const viewer = new Cesium.Viewer("cesiumContainer");
var entity = viewer.entities.add({
label: {
font: "24px sans-serif",
fillColor: Cesium.Color.WHITE,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
billboard: {
image: "/vite.svg", // 图标的路径
width: 32, // 图标宽度
height: 32, // 图标高度
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -50), // 图标偏移量
},
});
const scene = viewer.scene;
const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
// 鼠标移动监听
handler.setInputAction(function (event) {
const cartesian = viewer.camera.pickEllipsoid(
event.endPosition,
scene.globe.ellipsoid
);
if (cartesian) {//鼠标在地球上
//获取笛卡尔坐标
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
//经纬度转换
const longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(2);
const latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(2);
entity.position = cartesian;
entity.label.show = true;
entity.label.text =
`Lon: ${` ${longitude}`.slice(-7)}\u00B0` +
`\nLat: ${` ${latitude}`.slice(-7)}\u00B0`;
} else {//鼠标不在地球上
console.log("未在地球上");
entity.label.show = false;
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);//鼠标移动事件监听
});
效果如下: