7.4 KiB
7.4 KiB
title | date | author | sidebar | tags | categories | ||
---|---|---|---|---|---|---|---|
Openlayers卷帘 | 2020-12-25 | ac | false |
|
|
Openlayers卷帘
“卷帘”功能可以分为两部分:
- 控件元素的拖动。
- 地图图层渲染流程的控制,对上层图层进行裁剪。
首先我们需要一个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
实例时,会先触发map
的precompose
事件,再依次触发layers
集合中每个图层的precompose
事件和postcompose
事件,在所有layer都渲染完成后,才会触发map
的postrender
事件。
实现原理
卷帘实现原理:在客户端监听上层图层的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; //兼容IE浏览器
// 鼠标点击元素那一刻相对于元素左侧边框的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离
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>