OpenLayers 分屏对比(地图联动)

注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key

地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。通过创建多个地图,在其中任意一个地图上缩放或者拖动时,其它地图也进行同样的操作。常见的分屏模式有二分屏、四分屏、六分屏和八分屏。本节主要介绍加载地图分屏对比

1. 创建分屏视图

在创建地图函数中需要传入绑定地图ID值,默认创建二分屏,实现偶数地图加载天地图矢量底图,奇数地图加载天地图影像底图。

php 复制代码
/**
 *  创建地图 
 *  mapId:地图ID
 */ 
function createMap(mapId) {
    const num = mapId.replace(/[^d.]/g, "")
    const layer = num % 2 === 0 ? TDTVecLayer : TDTImgLayer
    const vectorMap = new ol.Map({
        target: mapId,
        layers: [
            layer,
            TDTCvaLayer
        ],
        view: new ol.View({
            center: [11421771, 4288300],
            zoom: 5,
            worldsWrap: true,
            minZoom: 1,
            maxZoom: 20,
            projection: projection
        })
    })
    return vectorMap
}

2. 地图分屏操作

地图分屏操作最主要在于根据分屏数量创建地图,通过循环创建地图,并根据位置调整宽高比例,设置地图样式为左浮动。并在点击分屏按钮时切换按钮激活样式,清除销毁的地图元素和清空地图数据。

ini 复制代码
/**
 * 地图分屏操作
 */
function mapSplit() {
    // 二分屏
    document.getElementById('two').addEventListener('click', evt => {
        toogleAciveClass(evt.target)
        maps = []
        removeChildMap(mapsContainer)
        for (let i = 0; i < 2; i++) {
            // 创建地图元素
            const mapId = 'two-' + i
            const mapTarget = document.createElement('div')
            mapTarget.className = 'split-map'
            mapTarget.style.height = "100%"
            mapTarget.style.width = "50%"
            mapTarget.setAttribute('id', mapId)
            mapsContainer.appendChild(mapTarget)
            const map = createMap(mapId)
            maps.push(map)
        }
        mapZoomAndMove()
    })

    // 四分屏
    document.getElementById('four').addEventListener('click', evt => {
        toogleAciveClass(evt.target)
        maps = []
        removeChildMap(mapsContainer)
        for (let i = 0; i < 4; i++) {
            // 创建地图元素
            const mapId = 'four-' + i
            const mapTarget = document.createElement('div')
            mapTarget.className = 'split-map'
            mapTarget.style.height = "50%"
            mapTarget.style.width = "50%"
            mapTarget.setAttribute('id', mapId)
            mapsContainer.appendChild(mapTarget)
            const map = createMap(mapId)
            maps.push(map)
        }
        mapZoomAndMove()
    })
    // 六分屏
    document.getElementById('six').addEventListener('click', evt => {
        toogleAciveClass(evt.target)
        maps = []
        removeChildMap(mapsContainer)
        for (let i = 0; i < 6; i++) {
            // 创建地图元素
            const mapId = 'six-' + i
            const mapTarget = document.createElement('div')
            mapTarget.className = 'split-map'
            mapTarget.style.height = 100 / 3 + "%"
            mapTarget.style.width = '50%'
            mapTarget.setAttribute('id', mapId)
            mapsContainer.appendChild(mapTarget)
            const map = createMap(mapId)
            maps.push(map)
        }
        mapZoomAndMove()
    })
    // 八分屏
    document.getElementById('eight').addEventListener('click', evt => {
        toogleAciveClass(evt.target)
        maps = []
        removeChildMap(mapsContainer)
        for (let i = 0; i < 8; i++) {
            // 创建地图元素
            const mapId = 'eight-' + i
            const mapTarget = document.createElement('div')
            mapTarget.className = 'split-map'
            mapTarget.style.height = "25%"
            mapTarget.style.width = '50%'
            mapTarget.setAttribute('id', mapId)
            mapsContainer.appendChild(mapTarget)
            const map = createMap(mapId)
            maps.push(map)
        }
        mapZoomAndMove()
    })
}

3. 地图联动

地图联动原理很简单,只需要将其它地图对象的View设置为目标对象的视图即可

javascript 复制代码
// 地图联动
function mapZoomAndMove() {
    maps.forEach(map => {
        maps.forEach(targetMap => {
            map.setView(targetMap.getView())
        })
    })
}

4. 按钮渐变色

css 复制代码
  .disable-btn{
    background-color: #c8e7ff;
    border-color: #9e9e9e3d;
  }
  .no-disable-btn{
    color: #d1d1d1;
    background-color: #0167cc;
    border-color: #fff;
    &:hover{
      color:#fff;
      filter: brightness(110%) opacity(100%);
      transition: all .5s ease-in;
      background: linear-gradient(to bottom right, #9a99f1, #0167cc);
    }
    &:focus{
      filter: brightness(120%);
      transition: all .5s ease-in;
      background: radial-gradient(circle at center, #9a99f1, #0167cc);
    }
  }

// 背景色延迟
.tool-bar-item{
  width: 30px;
  height: 30px;
  color: #ffff;
  cursor: pointer;
  border-right: 1px solid #f0f4f76b;
  &:hover{
    background-color:  #248cfba8;
    transition-delay: .25s;
  }
}

5. 完整代码

其中libs文件夹下的包需要更换为自己下载的本地包或者引用在线资源。

xml 复制代码
<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>地图联动</title>
    <meta charset="utf-8" />
    <script src="../libs/js/ol-5.3.3.js"></script>
    <script src="../libs/js/jquery-2.1.1.min.js"></script>
    <script src="../libs/proj4.js"></script>
    <link rel="stylesheet" href="../libs/css/ol.css">
    <style>
        * {
            padding: 0;
            margin: 0;
            font-size: 14px;
            font-family: '微软雅黑';
        }

        html,
        body {
            width: 100%;
            height: 100%;
        }

        #imageMap {
            position: absolute;
            top: 50px;
            bottom: 0;
            left: 0;
            width: 50%;
        }

        #vectorMap {
            position: absolute;
            top: 50px;
            bottom: 0;
            left: 50%;
            width: 50%;

        }

        .split-div {
            position: absolute;
            width: 100%;
            height: 50px;
            line-height: 50px;
            background: linear-gradient(135deg, #ff00cc, #ffcc00, #00ffcc, #ff0066);
            color: #fff;
            text-align: center;
        }

        .split-span {
            border-radius: 5px;
            border: 1px solid #50505040;
            padding: 5px 20px;
            color: #fff;
            margin: 0 10px;
            background: #377d466e;
            transition: background-color 10s ease-in-out 10s;
        }

        .split-span:hover {
            cursor: pointer;
            font-size: 1.25em;
            filter: brightness(120%);
            background: linear-gradient(135deg, #c850c0, #4158d0);
        }

        .active {
            background: linear-gradient(135deg, #c850c0, #4158d0);
        }

        #map-main {
            position: absolute;
            top: 50px;
            bottom: 0;
            left: 0;
            right: 0;
        }

        .clearfix::after {
            display: block;
            content: "";
            clear: both;
        }

        .split-map {
            float: left;
        }
    </style>
</head>

<body>
    <div class="split-div ">
        <span id="two" class="split-span">二分屏</span>
        <span id="four" class="split-span">四分屏</span>
        <span id="six" class="split-span">六分屏</span>
        <span id="eight" class="split-span">八分屏</span>
    </div>
    <div id="map-main" class="clearfix"></div>
</body>

</html>

<script>
    //地图投影坐标系
    const projection = ol.proj.get('EPSG:3857');
    //==============================================================================//
    //============================天地图服务参数简单介绍==============================//
    //================================vec:矢量图层==================================//
    //================================img:影像图层==================================//
    //================================cva:注记图层==================================//
    //======================其中:_c表示经纬度投影,_w表示球面墨卡托投影================//
    //==============================================================================//
    const TDTImgLayer = new ol.layer.Tile({
        title: "天地图影像图层",
        source: new ol.source.XYZ({
            url: "http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=2a890fe711a79cafebca446a5447cfb2",
            attibutions: "天地图注记描述",
            crossOrigin: "anoymous",
            wrapX: false
        })
    })
    const TDTCvaLayer = new ol.layer.Tile({
        title: "天地图影像注记图层",
        source: new ol.source.XYZ({
            url: "http://t0.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=2a890fe711a79cafebca446a5447cfb2",
            attibutions: "天地图注记描述",
            crossOrigin: "anoymous",
            wrapX: false
        })
    })

    const TDTVecLayer = new ol.layer.Tile({
        title: "天地图影像图层",
        source: new ol.source.XYZ({
            url: "http://t0.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=2a890fe711a79cafebca446a5447cfb2",
            attibutions: "天地图注记描述",
            crossOrigin: "anoymous",
            wrapX: false
        })
    })

    /**
     *  创建地图 
     *  mapId:地图ID
     */  
    function createMap(mapId) {
        const num = mapId.replace(/[^d.]/g, "")
        const layer = num % 2 === 0 ? TDTVecLayer : TDTImgLayer
        const vectorMap = new ol.Map({
            target: mapId,
            layers: [
                layer,
                TDTCvaLayer
            ],
            view: new ol.View({
                center: [11421771, 4288300],
                zoom: 5,
                worldsWrap: true,
                minZoom: 1,
                maxZoom: 20,
                projection: projection
            })
        })
        return vectorMap
    }

    // 分屏地图数组
    let maps = []
    /**
     * 默认二分屏
     */
    const mapsContainer = document.getElementById("map-main")
    for (let i = 0; i < 2; i++) {
        // 创建地图元素
        const mapId = 'two-' + i
        const mapTarget = document.createElement('div')
        mapTarget.className = 'split-map'
        mapTarget.style.height = "100%"
        mapTarget.style.width = "50%"
        mapTarget.setAttribute('id', mapId)
        mapsContainer.appendChild(mapTarget)
        const map = createMap(mapId)
        maps.push(map)
    }
    mapZoomAndMove()
    /**
     * 地图分屏操作
     */
    function mapSplit() {
        // 二分屏
        document.getElementById('two').addEventListener('click', evt => {
            toogleAciveClass(evt.target)
            maps = []
            removeChildMap(mapsContainer)
            for (let i = 0; i < 2; i++) {
                // 创建地图元素
                const mapId = 'two-' + i
                const mapTarget = document.createElement('div')
                mapTarget.className = 'split-map'
                mapTarget.style.height = "100%"
                mapTarget.style.width = "50%"
                mapTarget.setAttribute('id', mapId)
                mapsContainer.appendChild(mapTarget)
                const map = createMap(mapId)
                maps.push(map)
            }
            mapZoomAndMove()
        })

        // 四分屏
        document.getElementById('four').addEventListener('click', evt => {
            toogleAciveClass(evt.target)
            maps = []
            removeChildMap(mapsContainer)
            for (let i = 0; i < 4; i++) {
                // 创建地图元素
                const mapId = 'four-' + i
                const mapTarget = document.createElement('div')
                mapTarget.className = 'split-map'
                mapTarget.style.height = "50%"
                mapTarget.style.width = "50%"
                mapTarget.setAttribute('id', mapId)
                mapsContainer.appendChild(mapTarget)
                const map = createMap(mapId)
                maps.push(map)
            }
            mapZoomAndMove()
        })
        // 六分屏
        document.getElementById('six').addEventListener('click', evt => {
            toogleAciveClass(evt.target)
            maps = []
            removeChildMap(mapsContainer)
            for (let i = 0; i < 6; i++) {
                // 创建地图元素
                const mapId = 'six-' + i
                const mapTarget = document.createElement('div')
                mapTarget.className = 'split-map'
                mapTarget.style.height = 100 / 3 + "%"
                mapTarget.style.width = '50%'
                mapTarget.setAttribute('id', mapId)
                mapsContainer.appendChild(mapTarget)
                const map = createMap(mapId)
                maps.push(map)
            }
            mapZoomAndMove()
        })
        // 八分屏
        document.getElementById('eight').addEventListener('click', evt => {
            toogleAciveClass(evt.target)
            maps = []
            removeChildMap(mapsContainer)
            for (let i = 0; i < 8; i++) {
                // 创建地图元素
                const mapId = 'eight-' + i
                const mapTarget = document.createElement('div')
                mapTarget.className = 'split-map'
                mapTarget.style.height = "25%"
                mapTarget.style.width = '50%'
                mapTarget.setAttribute('id', mapId)
                mapsContainer.appendChild(mapTarget)
                const map = createMap(mapId)
                maps.push(map)
            }
            mapZoomAndMove()
        })
    }
    mapSplit()
    // 移除子元素
    function removeChildMap(mapsContainer) {
        const childNodes = Array.from(mapsContainer.children)
        if (childNodes.length) {
            childNodes.forEach(element => {
                mapsContainer.removeChild(element)
            });
        }
    }
    // 地图联动
    function mapZoomAndMove() {
        maps.forEach(map => {
            maps.forEach(targetMap => {
                map.setView(targetMap.getView())
            })
        })
    }
    /**
     * 切换激活样式
     */
    function toogleAciveClass(target) {
        // 判断split-div子元素是否激活,并切换激活样式
        const splitsEle = document.querySelector('.split-div')
        for (let element of splitsEle.children) {
            if (target === element) {
                target.classList.add('active')
            } else {
                element.classList.remove('active')
            }
        }

    }
</script>

OpenLayers示例数据下载,请回复关键字:ol数据

全国信息化工程师-GIS 应用水平考试资料,请回复关键字:GIS考试
【GIS之路】 已经接入了智能助手,欢迎关注,欢迎提问。

欢迎访问我的博客网站-长谈GIShttp://shanhaitalk.com

都看到这了,不要忘记点赞、收藏 + 关注

本号不定时更新有关 GIS开发 相关内容,欢迎关注 !

相关推荐
后海 0_o17 分钟前
2025前端微服务 - 无界 的实战应用
前端·微服务·架构
Scabbards_19 分钟前
CPT304-2425-S2-Software Engineering II
前端
小满zs24 分钟前
Zustand 第二章(状态处理)
前端·react.js
程序猿小D27 分钟前
第16节 Node.js 文件系统
linux·服务器·前端·node.js·编辑器·vim
萌萌哒草头将军29 分钟前
🚀🚀🚀Prisma 发布无 Rust 引擎预览版,安装和使用更轻量;支持任何 ORM 连接引擎;支持自动备份...
前端·javascript·vue.js
狼性书生43 分钟前
uniapp实现的简约美观的星级评分组件
前端·uni-app·vue·组件
书语时1 小时前
ES6 Promise 状态机
前端·javascript·es6
拉不动的猪1 小时前
管理不同权限用户的左侧菜单展示以及权限按钮的启用 / 禁用之其中一种解决方案
前端·javascript·面试
西陵1 小时前
前端框架渲染DOM的的方式你知道多少?
前端·javascript·架构
小九九的爸爸1 小时前
我是如何让AI帮我还原设计稿的
前端·人工智能·ai编程