WebGis013-图层探查控件

本文详细介绍了如何在WebGIS应用中实现图层探查控件,通过监听地图DOM元素的鼠标移入移出事件,动态裁剪上层图层,以在地图固定显示的同时,展示特定区域的辅助图层。实现步骤包括创建地图对象,添加图层,监听鼠标事件,以及在图层渲染前后进行裁剪操作。此外,还提供了一个修复初次渲染时图层未裁剪问题的方法。该功能有助于地图的辅助分析和错误检测。
摘要由CSDN通过智能技术生成

WebGis013-图层探查控件

有前面一下demo可知,每个地图canvas能被看到的只有一个地图图层(除了文字注记图层)。然而有这么一种场景:地图固定一直显示,需要在指定区域内显示另外一种图层。这样的需求前面和图层相关的图层控件就是做不了的。不过实现起来也比较方便。图层探查的原理是在客户端显示时,裁剪上层图层,这样一来地图就可以看到了,上层图层作为对照层也可以看到。这样就可以完成辅助错做或分析。

实现步骤如下

  1. 在mapControls文件夹下创建layerSearch.html 并创建好地图对象,地图依次引入天地图影像、矢量图层

  2. 注册地图dom对象的鼠标移入和移除事件,事件内做重新渲染地图操作

    1. 在鼠标移入移除地图dom对象时获取/置空鼠标相对于地图dom元素内的坐标位置

    2. 地图内渲染时图层是依次渲染的

    3. 给上层图层也就是"天地图矢量图层"注册渲染前/后的事件。

      ​ 渲染前事件做:

      1. 获取canvas对象

      2. 获取当前屏幕的像素比

      3. 保存当前canvas的物理状态----只有第一张影像图层,矢量图层还不曾绘制

      4. 如果鼠标坐标属性不为空-----就是鼠标在地图dom元素内

        1. 开启一个新的画笔轨迹

        2. 就以鼠标焦点为圆心,半径为指定参数画一个圆形

        3. 设置画笔的粗细

        4. 调用strokeStyle设置框选区域的边框样式

        5. 调用canvas上下文对象的stroke方法框选

          [注记]在canvas绘图中,fillXXX()与填充区域相关,strokeXXX()与绘制边框相关

        6. 调用canvas的stroke方法进行绘制边框

        7. 裁剪图层二

    4. 在渲染完第二个图层之后

      ​ 渲染后事件做:

      1. 获取canvas对象
      2. 恢复到先前保存的画好的图层一的状态
    5. 在最后会加上键盘控件以控制裁剪区域大小

    6. 代码如下

      <!DOCTYPE html>
      <html>
      	<head>
      		<meta charset="utf-8">
      		<title></title>
      		<link rel="stylesheet" type="text/css" href="../../css/ol.css" />
      		<script src="../../js/ol.js" type="text/javascript" charset="utf-8"></script>
      
      		<style type="text/css">
      			* {
      				box-sizing: border-box;
      			}
      
      			body {
      				margin: 0px;
      				padding: 0px;
      				height: 100vh;
      			}
      
      			#map {
      				height: 100%;
      			}
      
      		</style>
      	</head>
      	<body>
      		<div id="map"></div>
      		<script type="text/javascript">
      			// 创建地图对象
      			var map = new ol.Map({
      				// 绑定到指定DOM元素上
      				target: "map",
      				// 定义图层集变量
      				layers: [],
      				// 定义地图初始状态的参数
      				view: new ol.View({
      					// 设置初始中心
      					center: ol.proj.fromLonLat([112.388,34.655]),
      					// 设置初始缩放级别
      					zoom: 13
      				})
      			});
      			// 创建图层对象
      			var img_w = new ol.layer.Tile({
      				name: "天地图矢量图层",
      				source: new ol.source.XYZ({
      					url: "http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=9b0042eb1f01265c357f96da559ae11c"
      				})
      			})
      			
      			var vec_w = new ol.layer.Tile({
      				name: "天地图矢量图层",
      				source: new ol.source.XYZ({
      					url: "http://t0.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=9b0042eb1f01265c357f96da559ae11c"
      				})
      			})
      			
      			// 将图层对象绑定到地图上去
      			map.addLayer(img_w)
      			map.addLayer(vec_w)
      			
      			// 获取地图dom元素
      			var mapDom = document.querySelector("#map");
      			
      			// 给dom元素绑定鼠标移入事件
      			// 定义鼠标相对于dom元素的坐标位置
      			var mousePosition = null;
      			mapDom.addEventListener("mousemove",e=>{
      				mousePosition = map.getEventPixel(e)
      				// console.log(mousePosition);
      				// 鼠标每次移入都重新渲染地图对象
      				map.render()
      			})
      			// 给dom元素绑定鼠标移出事件
      			mapDom.addEventListener("mousemout",e=>{
      				// 将鼠标的相对坐标置空
      				mousePosition = null
      				// console.log(mousePosition);
      				// 鼠标每次移出同样重新渲染地图对象
      				map.render()
      			})
      			
      			/**
      			 * 此时因为矢量图层是后添加的,所以影像地图始终看不到
      			 * 所以需要对矢量图层进行裁剪
      			 * 
      			 * 也就是在每次渲染矢量图层前将其裁剪为合适大小然后渲染
      			 * 
      			 */
      			
      			
      			// 定义一个变量用以动态保存透视区域大小
      			var radius = 50
      			// 给天地图矢量图层注册渲染前事件
      			vec_w.on("precompose",(e)=>{
      				// 可以看到每次鼠标移动时都会执行下面输出语句
      				// console.log(e);
      				
      				// 获取矢量图层的canvas对象
      				var cxt = e.context;
      				// 获取当前屏幕像素比
      				var pixelRatio = e.frameState.pixelRatio;
      				
      				// 保存当前图层状态
      				cxt.save();
      				
      				// 另起一段新画笔轨迹
      				cxt.beginPath()
      				// 如果鼠标在地图dom元素内部
      				if(mousePosition){
      					// console.log(mousePosition);
      					cxt.arc(mousePosition[0]*pixelRatio,mousePosition[1]*pixelRatio,radius*pixelRatio,2*Math.PI,false)
      					// 设置画笔粗细
      					cxt.lineWidth = 5 * pixelRatio;
      					// 设置画笔颜色
      					cxt.strokeStyle = "#FF0000",
      					// 绘制边框
      					cxt.stroke()
      					// 裁剪图层
      					cxt.clip()
      				}
      			})
      			
      			vec_w.on("postcompose",(e)=>{
      				// 获取矢量图层的canvas对象
      				var cxt = e.context;
      				
      				/**
      				 * 这个canvas方法虽是说恢复为上次保存的状态
      				 * 然实不知,为何不加此恢复代码,二层图层将不能继续绘制。
      				 * 
      				 * 莫非是,像分支或世界线一样,地图图层一就没了。
      				 * 		没了但图层二还在啊,为何不能在图层二上继续绘制。2021-06-24
      				 * 
      				 */
      				// console.log("执行渲染结束方法");
      				cxt.restore();
      			})
      			
      			
      			// 给dom对象添加键盘事件以动态调整透视区域大小
      			document.addEventListener('keydown',e=>{
      				
      				// console.log(e);
      				
      				if(e.which==187){
      					radius = Math.min(radius+25,150)
      				}else if(e.which==189){
      					radius = Math.max(radius-25,25)
      				}
      			})
      			
      		</script>
      	</body>
      </html>
      
      
    7. 预览图如下
      在这里插入图片描述

    8. 2021-06-25 发现一个BUG:在页面初次渲染完成时图层二没有裁剪,也就是说图层二直接覆盖在图层以上。解决思路:在地图加载完成后调用map.render()无果。决定在页面渲染完成之后手动触发鼠标移动事件从而渲染地图数据。

      // 创建一个事件
      var mouseEvent = document.createEvent("MouseEvents")
      // 初始化事件
      mouseEvent.initEvent("mousemove",true)
      // 触发事件
      mapDom.dispatchEvent(mouseEvent)
      

      但此时透视区域则默认在左上角零点,就先这样吧。
      在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值