SuperMap iClient3D for WebGL三维场景与二维地图联动

作者:Lzzzz

在城市规划,应急救援,旅游规划等项目场景中,普遍存在通过二维地图定位区域或路线,三维场景展示布局细节的情况,那么,如何使三维场景与二维地图联动起来呢,一起来看看如何实现吧!

最终效果

实现步骤

  • 监听二维地图的平移事件,并更新三维场景的相机位置。
  • 在三维场景移动时,获取相机位置,同时更新二维地图的中心点。

关键代码

定义信号变量

定义信号变量,保证地图联动效果和场景联动效果同一时间只能触发一个 防止循环调用。

javascript 复制代码
        // 监听鼠标进入地图和 SuperMap3D 容器的区域,以确定当前激活的是哪个
        var activeMap = true;
        document.getElementById('map').addEventListener('pointerenter', () => {
            activeMap = true;
        });
        // 监听鼠标进入 SuperMap3D 容器的区域,以确定当前激活的是地图还是场景
        document.getElementById('Container').addEventListener('pointerenter', () => {
            activeMap = false;
        });

地图监听

javascript 复制代码
// 监听地图中心变化,并更新 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 // 立即移动
                });
            };
        });

场景监听

javascript 复制代码
        // 监听相机位置变化事件,以更新 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]);
        });

项目完整代码

html 复制代码
<!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>
相关推荐
八荒启·交互动画2 天前
# Web特效020—让 Web 特效真正动起来:时间循环应该怎么接
前端·webgl·网页特效·八荒启-交互动画·八荒启
李航19832 天前
用 DeepDraw 几何引擎开发建筑设计软件(十):推挤工具
python·3d
八荒启·交互动画2 天前
Web特效019-Web特效的定义与边界核心算法手写一遍:先跑起来,再谈高级效果
前端·webgl·网页特效·八荒启-交互动画·八荒启
八荒启·交互动画2 天前
Web特效011—Web特效的定义与边界为什么忽快忽慢:时间、频率与采样的秘密
webgl·网页特效·八荒启-交互动画·八荒启·web特效
八荒启·交互动画3 天前
Web特效008—一个 `getContext(‘webgl‘)`,浏览器到底交出了什么?
webgl·八荒启-交互动画
xhload3d4 天前
图扑智慧工厂 | 继电器产线仿真态势管控平台
物联网·低代码·webgl·数字孪生·可视化·智慧工厂·工业互联网·hightopo
iNeuOS工业互联网4 天前
大模型(DeepSeek)辅助 3D 实时建模 + 拖拽配置:业务可视化应用快速构建实践(标注、巡检与视角控制等)
人工智能·物联网·3d·语言模型·工业互联网
Zldaisy3d4 天前
点亮高端制造轻量化新图景:铝基材料增材制造进展与挑战
3d·制造
事界见闻4 天前
网页版AI 3D工具通常能完成哪些基础工作?生成、处理与导出流程对比
人工智能·3d
数字新视界5 天前
国产信创动环监控系统赋能智能环境安全新未来
物联网·3d·数字孪生·三维可视化·数据可视化