本文是vue+ts实现的,想要转为react,只需要修改以下几部分内容
1. 将 reactive 定义的数据直接改写为 let定义
2. 将 watch 监听的内容改成对应的监听写法
3. 将 ref 定义的字段改写为对应的写法
该模块实现的功能:
通过点击鹰眼图的某一位置,对应主地图切换到对应的经纬度位置
在主地图中拖拽,鹰眼图中的点也跟着变化
实现鹰眼图的原理
1. 要获取左上角和右下角的经纬度,用来确定当前区域的一个范围。
2. 要通过点击鹰眼图,将坐标转换为主地图中的经纬度。通过公式计算
3. 在主地图中拖拽,将经纬度转换为鹰眼图中的坐标,来实现点的对应
1.获取主地图区域的左上角,右下角的经纬度
经纬度是WGS84格式
const coord1 = reactive({
latitude: 29.67098,
longitude: 106.48518,
});
const coord2 = reactive({
latitude: 29.66891,
longitude: 106.48912,
});
2.计算经纬度的差值,算一下差值是几比几,决定鹰眼图的大小
// 差值
const difference = reactive({
longitude: Math.abs(coord1.longitude - coord2.longitude),
latitude: Math.abs(coord1.latitude - coord2.latitude),
});
3. 创建鹰眼图,鹰眼图的宽高要根据经纬度的宽高比来决定
<div id="eye">
<div class="dot" id="move-dot"></div>
</div>
4. 坐标转经纬度,经纬度转坐标有一个公式
公式解释:
我们用的经纬度是左上角的经纬度,因为eye的div左上角对应的是坐标系的(0,0)
求的主地图的经度 = eye点击的x坐标 * (经度的差值 / eye的高度) + 左上角的经度
5. 监听eye的点击函数
onMounted(() => {
// createMainCesium(); // 1.创建主地图,省略
handlerMoveDot(); // 2.定义鼠标移动事件
});
// 创建点击函数
function handlerMoveDot() {
const eyeBox = document.getElementById("eye");
const dot = document.getElementById("move-dot");
if (eyeBox && dot) {
eyeBox.addEventListener("click", (e) => {
moveX.value = e.offsetX;
moveY.value = e.offsetY;
dot.style.left = moveX.value + "px";
dot.style.top = moveY.value + "px";
});
}
}
// dot的变化更新主地图的经纬度
watch([moveX, moveY], () => {
const longitude =
moveX.value * (difference.longitude / 164) + coord1.longitude;
const latitude = coord1.latitude - moveY.value * (difference.latitude / 173);
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, 500);
viewerRef.value.camera.flyTo({
destination: position,
duration: 2.0,
// 相机的角度,自行调整,不需要先注释
orientation: {
heading: 2 * Math.PI,
pitch: -1 * (Math.PI / 6),
roll: 2 * Math.PI,
},
});
});
截至目前为止,实现了坐标转经纬度
接下来,实现 经纬度转坐标
1. 页面一进来,计算主地图左上角、右下角的经纬度中心,来显示在鹰眼图对应的位置
这段代码放到渲染完viewer之后
const cartographic = getCartographicCenter();
dotInitPosition(cartographic);
// 初始化页面是找经纬度的中心
function getCartographicCenter() {
const centerLongitude = (coord1.longitude + coord2.longitude) / 2;
const centerLatitude = (coord1.latitude + coord2.latitude) / 2;
return {
longitude: centerLongitude,
latitude: centerLatitude,
};
}
// 笛卡尔坐标转换屏幕坐标,用作dot的初始位置
function dotInitPosition(cartesian: ScreenPosition) {
let x, y;
x = (cartesian.longitude - coord1.longitude) * (164 / difference.longitude);
y = (coord1.latitude - cartesian.latitude) * (173 / difference.latitude);
const dot = document.getElementById("move-dot");
if (dot) {
dot.style.left = x + "px";
dot.style.top = y + "px";
}
}
2. 监听在主地图上移动的函数
onMounted(() => {
handlerMoveView(); // 3.定义地图的鼠标移动事件
});
// 监听地图的移动事件
function handlerMoveView() {
const viewer = viewerRef.value;
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((e) => {
// 这里如果获取不到值,百度一下,换其他方式拿经纬度
const ray = viewer.camera.getPickRay(e.position);
if (ray?.origin) {
const cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(
ray?.origin,
);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
// 计算公式还用初始化的那个就行
dotInitPosition({ longitude, latitude });
}
}, Cesium.ScreenSpaceEventType.LEFT_UP);
}