Openlayers 卷帘功能

卷帘

在这里插入图片描述
“卷帘”功能可以分为两部分:

  1. 控件元素的拖动。这里控件仿照ArcGIS for JS上的样式。
  2. 地图图层渲染流程的控制,对上层图层进行裁剪。

首先我们需要一个DOM组件作为拖动的“卷帘”,将其放在map容器内部,避免影响页面其他要素。

<div id="map" class="map">
    <div id="swipeContainer">
        <div id="swipeDiv">
            <div class="handle"></div>
        </div>
    </div>
</div>

在设置样式时,将map元素设为相对定位,则其内部的子元素的绝对定位将参考map元素的位置,即“卷帘”的拖动位置将参考map元素进行。根据“卷帘”组件拖动的位置,利用地图渲染相关的事件,对图层进行处理实现卷帘效果。

地图渲染相关的事件:

  • precompose:未渲染,layers或layer被渲染前触发
  • postcompose:layer图层渲染后触发,可以在事件源中获取用于渲染图层的上下文context,也可以得到canvas元素。图层的渲染其实就是将从数据源中请求得到的矢量数据,通过计算转换绘制在content上下文中或将请求得到的图片嵌入到上下文中相应的位置
  • postrender:map被渲染完成后触发

当初始化map实例时,会先触发mapprecompose事件,再依次触发layers集合中每个图层的precompose事件和postcompose事件,在所有layer都渲染完成后,才会触发mappostrender事件。

卷帘实现原理:在客户端监听上层图层的postcompose事件,获取渲染的上下文content,对其进行裁剪,让下层图层数据可见。

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="css/ol.css" type="text/css">
    <style>
        .map {
            height: 400px;
            width: 100%;
            position: relative;
        }
        #swipeContainer {
            position: absolute;
            opacity: 0.8;
            width: 0.625rem;
            height: 100%;
            /* margin: 0 auto; */
            top: 0;
            left: 50%;
            background-color: rgba(50, 50, 50, 0.75);
            cursor: col-resize;
            z-index: 2;
        }

        #swipeContainer:hover {
            opacity: 0.5;
        }

        #swipeDiv {
            border: solid 0.5px #ffffff;
            height: 100%;
            width: 0px;
            margin: 0 auto;
        }

        #swipeDiv .handle {
            width: 51px;
            height: 24px;
            margin-top: -12px;
            margin-left: -20px;
            top: 50%;
            left: 0;
            position: absolute;
            z-index: 30;
            font-family: "CalciteWebCoreIcons";
            speak: none;
            font-size: 12px;
            font-style: normal;
            font-weight: normal;
            font-variant: normal;
            text-transform: none;
            text-indent: 0;
            line-height: 1;
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
            background-color: black;
            color: white;
            opacity: 0.6;
        }

        *,
        *:before,
        *:after {
            -moz-box-sizing: border-box;
            -webkit-box-sizing: border-box;
            box-sizing: border-box;
        }

        .handle:before {
            margin: 0 18px 0 5px;
            content: "\0399\0399\0399";
            width: 20px;
            height: 24px;
            line-height: 2;
        }

        .handle:after {
            content: "\0399\0399\0399";
            width: 20px;
            height: 24px;
            line-height: 2;
        }
    </style>
    <script src="lib/ol.js"></script>
    <title>卷帘</title>
</head>
<body>
<h2>卷帘(裁剪图层)</h2>
<div id="map" class="map">
    <div id="swipeContainer">
        <div id="swipeDiv">
            <div class="handle"></div>
        </div>
    </div>
</div>
<script type="text/javascript">

    window.onload = function () {
        var map = initMap();
        initSwipeDom(map);
        swipeLayer(map);
    }
    function initMap() {
        var bingKey = 'AmosL5A0GtVryl4sXNZm6U5EQMD6brAd5E8AJPGJf8AUU1saDYXDkb5CwQFijans';
        var roadLayer = new ol.layer.Tile({
            id:'road',
            source: new ol.source.BingMaps({key: bingKey, imagerySet: 'Road'}),
            name: "Bing道路图层"
        });
        var imageLayer = new ol.layer.Tile({
            id:'aerial',
            source: new ol.source.BingMaps({key: bingKey, imagerySet: 'Aerial'}),
            name: "Bing影像图层"
        });
        var map = new ol.Map({
            view: new ol.View({
                center: [12614553, 2648165],
                zoom: 12,
                minzoom: 6,
                maxzoom: 15,
            }),
            layers: [
                roadLayer,
                imageLayer
            ],
            target: "map"
        });
        return map;
    }

    function initSwipeDom(map) {
        var swipe = document.getElementById("swipeContainer");
        var obj = {};
        swipe.onmousedown = function(event) {
            var e = event || window.event; 
            // 鼠标点击元素那一刻相对于元素左侧边框的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离
            obj.diffX = e.clientX - this.offsetLeft;
            document.onmousemove = function(event) {
                var e = event || window.event;
                var moveX = e.clientX - obj.diffX;
                if (moveX < 0) {
                    moveX = 0
                } else if (moveX > window.innerWidth - swipe.offsetWidth) {
                    moveX = window.innerWidth - swipe.offsetWidth
                }
                swipe.style.left = moveX + 'px';
                
                //重新渲染图层
                map.render();
            };
            document.onmouseup = function() {
                this.onmousemove = null;
                this.onmouseup = null;
            }
        };
    }
    function swipeLayer(map) {
        var layers = map.getLayers();
        var topLayer = layers.item(layers.getLength() - 1);
        topLayer.on('precompose', function(event) {
            var swipe = document.getElementById("swipeContainer");
            var ctx = event.context;
            //计算图层在canvas画布上需要显示的范围
            var mapSize = map.getSize();
            var height = event.context.canvas.height;
            var width = event.context.canvas.width;
            var swipeWidth = swipe.offsetLeft*width/mapSize[0];
            var tl = [swipeWidth,0];
            var tr = [width,0];
            var bl = [swipeWidth,height];
            var br = [width,height];

            ctx.save();
            //绘制裁剪路径
            ctx.beginPath();
            ctx.moveTo(tl[0], tl[1]);
            ctx.lineTo(bl[0], bl[1]);
            ctx.lineTo(br[0], br[1]);
            ctx.lineTo(tr[0], tr[1]);
            ctx.closePath();
            //裁剪,裁剪路径以外的部分不会绘制在canvas上下文中
            ctx.clip();
        });
        topLayer.on('postcompose', function(event) {
            var ctx = event.context;
            ctx.restore();
        });
    }
</script>
</body>
</html>
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值