当前位置: 首页 > news >正文

OpneLayers 创建地图卷帘

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

地图卷帘主要用于比较两个或多个叠加在一起的地图图层或影像之间的差异,是一种地图可视化技术。允许用户通过鼠标或其他交互方式,模拟将上层影像或图层像窗帘一样卷起或滑动,从而逐渐露出下层的影像或图层,使用户能够直观地比较图层的区别。本节主要介绍地图卷帘

1. 创建卷帘要素

创建卷帘开关结构并设置样式,添加鼠标按下、松开和移动事件,用于记录卷帘开关位置并更新卷帘图层宽度。在鼠标按下事件中开启鼠标移动事件。

<div class="swipe-content" onmouseup="mouseUp()"><div class="handle" onmousedown="mouseDown()" onmouseout="mouseOut()"></div>
</div>

卷帘开关样式

/* 卷帘滑动块样式 */
.swipe-content {display: none;position: absolute;top: 50px;left: 50%;opacity: 0.8;width: 2px;height: calc(100% - 50px);margin-left: -1px;background-color: #00A0E9;z-index: 2;
}.handle {position: absolute;height: 40px;width: 40px;border-radius: 50%;background-color: #cee9ff;background-image: url('swipe.jpg');rotate: 90deg;background-size: 100% 100%;cursor: e-resize;margin-left: -20px;top: 50%;margin-top: -20px;
}

2. 卷帘开关移动事件

在卷帘开关拖动事件中需要计算小球偏移量,即小球宽度的一半,根据拖动的距离设置左右边界阈值。在拖动完成后更新开关位置并重新渲染地图。

function swipeMove(evt) {const ballEle = document.querySelector(".handle")const ballEleRect = ballEle.getBoundingClientRect()const ballWidthOfHalf = ballEleRect.width / 2const mapSize = map.getSize()const offsetLeft = target.offsetLeftswipeValue = offsetLeftconst rect = target.offsetParent.getBoundingClientRect()let leftDistance = evt.clientX - rect.xif (leftDistance <= ballWidthOfHalf) {leftDistance = ballWidthOfHalf}if (leftDistance >= mapSize[0] - ballWidthOfHalf) {leftDistance = mapSize[0] - ballWidthOfHalf}// 更新要素位置target.style.left = leftDistance + "px"map.render()
}

3. 监听地图渲染前事件

在地图渲染前计算卷帘图层宽度并裁剪图层。

TDTVecLayer.on("prerender", event => {const ctx = event.context;const mapSize = map.getSize();const width = swipeValue;const tl = ol.render.getRenderPixel(event, [width, 0]);const tr = ol.render.getRenderPixel(event, [mapSize[0], 0]);const bl = ol.render.getRenderPixel(event, [width, mapSize[1]]);const br = ol.render.getRenderPixel(event, mapSize);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();ctx.clip();
});

4. 监听地图渲染后事件

地图渲染完成后只需保存上下文即可。

TDTVecLayer.on("postrender", (event) => {const ctx = event.context;ctx.restore();
});

5. 完整代码

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

<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>地图卷帘</title><meta charset="utf-8" /><script src="../../js/ol9.2.4.js"></script><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/9.2.4/ol.min.css"><style>* {padding: 0;margin: 0;font-size: 14px;font-family: '微软雅黑';}html,body {position: relative;width: 100%;height: 100%;overflow: hidden;}#map {position: absolute;top: 50px;bottom: 0;left: 0;right: 0;}#top-content {position: absolute;width: 100%;height: 50px;line-height: 50px;background: linear-gradient(135deg, #ff00cc, #ffcc00, #00ffcc, #ff0066);color: #fff;text-align: center;}.swipe-btn {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;}.swipe-btn:hover {cursor: pointer;filter: brightness(120%);background: linear-gradient(135deg, #c850c0, #4158d0);}.active {background: linear-gradient(135deg, #c850c0, #4158d0);}/* 卷帘滑动块样式 */.swipe-content {display: none;position: absolute;top: 50px;left: 50%;opacity: 0.8;width: 2px;height: calc(100% - 50px);margin-left: -1px;background-color: #00A0E9;z-index: 2;}.handle {position: absolute;height: 40px;width: 40px;border-radius: 50%;background-color: #cee9ff;background-image: url('swipe.jpg');rotate: 90deg;background-size: 100% 100%;cursor: e-resize;margin-left: -20px;top: 50%;margin-top: -20px;}</style>
</head><body><div id="top-content"><span class="swipe-btn open-swipe active" onclick="openSwipe()">打开卷帘</span><span class="swipe-btn open-swipe" onclick="closeSwipe()">关闭卷帘</span></div><div id="map" title="地图显示"></div><div class="swipe-content" onmouseup="mouseUp()"><div class="handle" onmousedown="mouseDown()" onmouseout="mouseOut()"></div></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 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})})const TDTImgCvaLayer = 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 map = new ol.Map({target: "map",view: new ol.View({center: [104.0635986160487, 30.660919181071225],zoom: 5,worldsWrap: true,minZoom: 1,maxZoom: 20,projection: "EPSG:4326"}),layers: [TDTImgLayer, TDTImgCvaLayer]})map.on('click', evt => {console.log(evt.coordinate)})/*** 初始化卷帘图层宽度,即地图宽度的一半*/const target = document.querySelector(".swipe-content")const mapSize = map.getSize()const halfWidth = mapSize[0] / 2let swipeValue = halfWidth/*** 默认打开卷帘*/map.addLayer(TDTVecLayer)target.style.display = "block"/*** 打开卷帘*/function openSwipe() {toogleAciveClass(event.target)target.style.display = "block"map.addLayer(TDTVecLayer)}/*** 关闭卷帘*/function closeSwipe() {toogleAciveClass(event.target)target.style.display = "none"map.removeLayer(TDTVecLayer)}/*** 卷帘图层渲染前事件* 计算卷帘图层宽度,即拖动距离,裁剪图层*/ TDTVecLayer.on("prerender", event => {const ctx = event.context;const mapSize = map.getSize();const width = swipeValue;const tl = ol.render.getRenderPixel(event, [width, 0]);const tr = ol.render.getRenderPixel(event, [mapSize[0], 0]);const bl = ol.render.getRenderPixel(event, [width, mapSize[1]]);const br = ol.render.getRenderPixel(event, mapSize);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();ctx.clip();});/*** 卷帘图层渲染完成事件* 保存图层上下文*/ TDTVecLayer.on("postrender", (event) => {const ctx = event.context;ctx.restore();});/*** 卷帘开关按下事件* 记录鼠标按下位置距离地图左侧边缘的距离*/ function mouseDown(evt) {const ballEle = document.querySelector(".handle")// 禁用浏览器默认拖放行为ballEle.ondragstart = function () {return false}swipeValue = target.offsetLeftmap.getTargetElement().addEventListener('mousemove', swipeMove)}/*** 卷帘开关拖动事件* 根据拖动小球的一般宽度计算偏移量,控制左右边界距离。* 更新开关位置并重新渲染地图。*/ function swipeMove(evt) {const ballEle = document.querySelector(".handle")const ballEleRect = ballEle.getBoundingClientRect()const ballWidthOfHalf = ballEleRect.width / 2const mapSize = map.getSize()const offsetLeft = target.offsetLeftswipeValue = offsetLeftconst rect = target.offsetParent.getBoundingClientRect()let leftDistance = evt.clientX - rect.xif (leftDistance <= ballWidthOfHalf) {leftDistance = ballWidthOfHalf}if (leftDistance >= mapSize[0] - ballWidthOfHalf) {leftDistance = mapSize[0] - ballWidthOfHalf}// 更新要素位置target.style.left = leftDistance + "px"map.render()}function mouseUp(evt) {map.getTargetElement().removeEventListener('mousemove', swipeMove)}function mouseOut() {// this.map.getTargetElement().removeEventListener('mousemove',this.swipeMove)}/*** 切换激活样式*/function toogleAciveClass(target) {// 判断top-content子元素是否激活,并切换激活样式const swipeBtnLike = document.querySelector('#top-content')for (let element of swipeBtnLike.children) {if (target === element) {target.classList.add('active')} else {element.classList.remove('active')}}}
</script>

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

全国信息化工程师-GIS 应用水平考试资料,请回复关键字:GIS考试

【GIS之路】 已经接入了智能助手,欢迎关注,欢迎提问。

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

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

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

http://www.xdnf.cn/news/992395.html

相关文章:

  • 系统设计基本功:流量与存储需求估算
  • 40 C 语言日期与时间函数详解:time、ctime、difftime、clock(含 UTC/本地时间转换)
  • PostGIS实现波段添加导入【ST_AddBand】
  • Linux相关问题整理
  • 如何利用智能助手提升工作效率:从入门到实践
  • C语言学习20250611
  • Docker容器技术介绍,应用场景,安装应用以及项目部署
  • AUTOSAR图解==>AUTOSAR_TR_ModelingShowCases
  • D. Plus Minus Permutation
  • day28/60
  • 常用的免费网络API接口
  • 脑机新手指南(九):高性能脑文本通信:手写方式实现(上)
  • 【navigator.clipboard】复制链接弹出详情信息(模拟电商app)、页面中粘贴图片、复制文本自动添加版权信息
  • CentOS7自带的yum依然无法联网到官方源
  • 自我推荐一下
  • 关于亚马逊WOOT折扣力度
  • 中国北方GNSS业务站网积雪深度数据集(GSnow-CHINA v1.0, 12h/24h, 2013-2...
  • 【烧脑算法】三指针的降维打击:三线并行锁定解题细节
  • 数据隐私是什么?如何做好数据隐私规范?
  • Nuttx之mm_extend
  • Python数据类型大全:整型、浮点、字符串与布尔值
  • Codeforces 1029 Div3(ABCDE)
  • Windows10下利用VS2019编译JpegLib
  • seo优化新利器:AI如何让内容批量生成与排名提升双管齐下?
  • Gremlin创建schema(包括实体和关系)
  • 【质数】埃氏筛法、线性筛法(欧拉筛法)
  • 【Linux系统编程】System V
  • Java锁机制对决:ReadWriteLock vs StampedLock
  • 从0到1落地一个RAG智能客服系统
  • ConcurrentHashMap详解:原理、实现与并发控制