借鉴自:Openlayers 卷帘功能_openlayers 卷帘分析-CSDN博客
原理
其实就是两个图层,通过裁剪上面图层的大小,来控制下方图层的展示大小
所以除了map以外,还需要一个用来控制裁剪的工具(这个工具可以自己写样式,div也好,官网示例用的input也好)
步骤
创建好一个至少包含两个底图图层的Map实例(map的样式定位要设置relative,让控制工具能按照map的位置来偏移)
对控制工具添加
onmousedown
,并在拖拽过程中在onmousemove
事件中对这个控制工具的位置进行变换控制工具的位置一旦变化,就同时更新map上方图层的裁剪
map图层裁剪的刷新需要用到prerender,postrender
这两个事件(ol6中是这两个,ol5中是precompose,postcompose
)
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Layer Swipe</title>
<script src="./v6.12.0-dist/ol.js"></script>
<link rel="stylesheet" href="./v6.12.0-dist/ol.css">
<style>
.map {
margin: auto;
width: 90%;
height: 400px;
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>
</head>
<body>
<div id="map" class="map">
<div id="swipeContainer">
<div id="swipeDiv">
<div class="handle"></div>
</div>
</div>
</div>
<script>
const vec = new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://t4.tianditu.com/DataServer?T=img_w&tk={密钥}&x={x}&y={y}&l={z}',
maxZoom: 20,
}),
});
const aerial = new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://t4.tianditu.com/DataServer?T=vec_w&tk={密钥}&x={x}&y={y}&l={z}',
maxZoom: 20,
}),
});
const zhuji = new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://t4.tianditu.com/DataServer?T=cva_w&tk={密钥}&x={x}&y={y}&l={z}',
maxZoom: 20,
}),
});
const map = new ol.Map({
layers: [vec, aerial, zhuji], // zhuji这个图层可以忽略
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([116, 33]),
zoom: 12,
}),
});
window.map = map;
var swipe = document.getElementById("swipeContainer");
var obj = {};
swipe.onmousedown = function (event) {
var e = event || window.event;
// map容器左侧和浏览器左侧的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离
obj.diffX = e.clientX - this.offsetLeft;
document.onmousemove = function (event) {
var e = event || window.event;
// 控制工具距离map容器左侧的距离 = 鼠标移动时位置相对于浏览器最左边的距离-map容器左侧和浏览器左侧的距离
var moveX = e.clientX - obj.diffX;
// 控制工具距离map容器左侧的距离不能小于0 也不能大于map容器宽度
if (moveX < 0) {
moveX = 0
} else if (moveX > document.getElementById("map").offsetWidth) {
moveX = document.getElementById("map").offsetWidth
}
swipe.style.left = moveX + 'px';
//重新渲染图层->prerender->postrender
map.render();
};
document.onmouseup = function () {
this.onmousemove = null;
this.onmouseup = null;
}
};
aerial.on('prerender', function (event) {
var swipe = document.getElementById("swipeContainer");
var ctx = event.context;
//计算图层在canvas画布上需要显示的范围
var mapSize = map.getSize(); // [map的宽度, map的高度]
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();
});
aerial.on('postrender', function (event) {
const ctx = event.context;
ctx.restore();
});
</script>
</body>
</html>
评论区