作者:Lzzzz
在城市规划,应急救援,旅游规划等项目场景中,普遍存在通过二维地图定位区域或路线,三维场景展示布局细节的情况,那么,如何使三维场景与二维地图联动起来呢,一起来看看如何实现吧!
最终效果
实现步骤
- 监听二维地图的平移事件,并更新三维场景的相机位置。
- 在三维场景移动时,获取相机位置,同时更新二维地图的中心点。
关键代码
定义信号变量
定义信号变量,保证地图联动效果和场景联动效果同一时间只能触发一个 防止循环调用。
// 监听鼠标进入地图和 SuperMap3D 容器的区域,以确定当前激活的是哪个
var activeMap = true;
document.getElementById('map').addEventListener('pointerenter', () => {
activeMap = true;
});
// 监听鼠标进入 SuperMap3D 容器的区域,以确定当前激活的是地图还是场景
document.getElementById('Container').addEventListener('pointerenter', () => {
activeMap = false;
});
地图监听
// 监听地图中心变化,并更新 SuperMap3D 的相机位置
map.getView().on('change:center', () => {
if (activeMap) {
const center = map.getView().getCenter();
const cartographic = SuperMap3D.Cartographic.fromCartesian(viewer.camera.position);
const height = cartographic.height; // 获取高度
// 更新 MySuperMap3D 的相机位置
const cartesian = SuperMap3D.Cartesian3.fromDegrees(center[0], center[1], height); // 设定一定高度
viewer.camera.flyTo({
destination: cartesian,
duration: 0 // 立即移动
});
};
});
场景监听
// 监听相机位置变化事件,以更新 OpenLayers 地图的视点
viewer.camera.changed.addEventListener(() => {
if (activeMap) return;
const camera = viewer.camera;
// 从相机的世界坐标获取经纬度
const cartographic = SuperMap3D.Cartographic.fromCartesian(camera.position);
// 获取高度并打印以检查
const latitude = SuperMap3D.Math.toDegrees(cartographic.latitude);
const longitude = SuperMap3D.Math.toDegrees(cartographic.longitude);
// 更新 OpenLayers 地图的视点
map.getView().setCenter([longitude, latitude]);
});
项目完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<title>地图场景联动</title>
<link href="../../Build/SuperMap3D/Widgets/widgets.css" rel="stylesheet">
<link href="./css/bootstrap.min.css" rel="stylesheet">
<link href="./css/pretty.css" rel="stylesheet">
<link href="./css/bootstrap-select.min.css" rel="stylesheet">
<script src="./js/jquery.min.js"></script>
<script src="./js/bootstrap.min.js"></script>
<script src="./js/bootstrap-select.min.js"></script>
<script src="./js/config.js"></script>
<script type="text/javascript" src="../../Build/SuperMap3D/SuperMap3D.js"></script>
<script type="text/javascript" src="/examples/js/include-web.js"></script>
<script type="text/javascript" src="/examples/dist/openlayers/include-openlayers.js"></script>
</head>
<body>
<div id="Container"></div>
<div id='loadingbar' class="spinner">
<div class="spinner-container container1">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
<div class="spinner-container container2">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
<div class="spinner-container container3">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
</div>
<div id="map" class="map" style="width:400px;height: 450px; position: absolute;top:580px">
</div>
<script>
function onload(SuperMap3D) {
var EngineType = getEngineType();
var viewer = new SuperMap3D.Viewer('Container', {
contextOptions: {
contextType: Number(EngineType), // Webgl2:2 ; WebGPU:3
}
});
viewer.scenePromise.then(function(scene){
init(SuperMap3D, scene, viewer);
});
}
function init(SuperMap3D, scene, viewer) {
viewer.resolutionScale = window.devicePixelRatio;
viewer.imageryLayers.addImageryProvider(new SuperMap3D.TiandituImageryProvider({
credit : new SuperMap3D.Credit('天地图全球影像服务 数据来源:国家地理信息公共服务平台 & 四川省测绘地理信息局'),
token: URL_CONFIG.TOKEN_TIANDITU
}));
var imageryLayers = viewer.imageryLayers;
//初始化天地图全球中文注记服务,并添加至影像图层
var labelImagery = new SuperMap3D.TiandituImageryProvider({
mapStyle : SuperMap3D.TiandituMapsStyle.CIA_C, //天地图全球中文注记服务(经纬度投影)
token: URL_CONFIG.TOKEN_TIANDITU
});
imageryLayers.addImageryProvider(labelImagery);
var map = new ol.Map({
target: 'map',
view: new ol.View({
center: [0,0],
zoom: 1,
projection: "EPSG:4326",
multiWorld: true
}),
layers: [new ol.layer.Tile({
source: new ol.source.Tianditu({
key: "1d109683f4d84198e37a38c442d68311",
projection: "EPSG:4326"
})
}), new ol.layer.Tile({
source: new ol.source.Tianditu({
key: "1d109683f4d84198e37a38c442d68311",
isLabel: true,
projection: "EPSG:4326"
})
})]
});
// 监听鼠标进入地图和 SuperMap3D 容器的区域,以确定当前激活的是哪个
var activeMap = true;
document.getElementById('map').addEventListener('pointerenter', () => {
activeMap = true;
});
// 监听鼠标进入 SuperMap3D 容器的区域,以确定当前激活的是地图还是场景
document.getElementById('Container').addEventListener('pointerenter', () => {
activeMap = false;
});
// 监听地图中心变化,并更新 SuperMap3D 的相机位置
map.getView().on('change:center', () => {
if (activeMap) {
const center = map.getView().getCenter();
const cartographic = SuperMap3D.Cartographic.fromCartesian(viewer.camera.position);
const height = cartographic.height; // 获取高度
// 更新 MySuperMap3D 的相机位置
const cartesian = SuperMap3D.Cartesian3.fromDegrees(center[0], center[1], height); // 设定一定高度
viewer.camera.flyTo({
destination: cartesian,
duration: 0 // 立即移动
});
};
});
// 监听相机位置变化事件,以更新 OpenLayers 地图的视点
viewer.camera.changed.addEventListener(() => {
if (activeMap) return;
const camera = viewer.camera;
// 从相机的世界坐标获取经纬度
const cartographic = SuperMap3D.Cartographic.fromCartesian(camera.position);
// 获取高度并打印以检查
const latitude = SuperMap3D.Math.toDegrees(cartographic.latitude);
const longitude = SuperMap3D.Math.toDegrees(cartographic.longitude);
// 更新 OpenLayers 地图的视点
map.getView().setCenter([longitude, latitude]);
});
$('#loadingbar').remove();
}
if (typeof SuperMap3D !== 'undefined') {
window.startupCalled = true;
onload(SuperMap3D);
}
</script>
</body>
</html>