WebGis013-图层探查控件
有前面一下demo可知,每个地图canvas能被看到的只有一个地图图层(除了文字注记图层)。然而有这么一种场景:地图固定一直显示,需要在指定区域内显示另外一种图层。这样的需求前面和图层相关的图层控件就是做不了的。不过实现起来也比较方便。图层探查的原理是在客户端显示时,裁剪上层图层,这样一来地图就可以看到了,上层图层作为对照层也可以看到。这样就可以完成辅助错做或分析。
实现步骤如下
-
在mapControls文件夹下创建layerSearch.html 并创建好地图对象,地图依次引入天地图影像、矢量图层
-
注册地图dom对象的鼠标移入和移除事件,事件内做重新渲染地图操作
-
在鼠标移入移除地图dom对象时获取/置空鼠标相对于地图dom元素内的坐标位置
-
地图内渲染时图层是依次渲染的
-
给上层图层也就是"天地图矢量图层"注册渲染前/后的事件。
渲染前事件做:
-
获取canvas对象
-
获取当前屏幕的像素比
-
保存当前canvas的物理状态----只有第一张影像图层,矢量图层还不曾绘制
-
如果鼠标坐标属性不为空-----就是鼠标在地图dom元素内
-
开启一个新的画笔轨迹
-
就以鼠标焦点为圆心,半径为指定参数画一个圆形
-
设置画笔的粗细
-
调用strokeStyle设置框选区域的边框样式
-
调用canvas上下文对象的stroke方法框选
[注记]在canvas绘图中,fillXXX()与填充区域相关,strokeXXX()与绘制边框相关
-
调用canvas的stroke方法进行绘制边框
-
裁剪图层二
-
-
-
在渲染完第二个图层之后
渲染后事件做:
- 获取canvas对象
- 恢复到先前保存的画好的图层一的状态
-
在最后会加上键盘控件以控制裁剪区域大小
-
代码如下
<!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>
-
预览图如下
-
2021-06-25 发现一个BUG:在页面初次渲染完成时图层二没有裁剪,也就是说图层二直接覆盖在图层以上。解决思路:在地图加载完成后调用map.render()无果。决定在页面渲染完成之后手动触发鼠标移动事件从而渲染地图数据。
// 创建一个事件 var mouseEvent = document.createEvent("MouseEvents") // 初始化事件 mouseEvent.initEvent("mousemove",true) // 触发事件 mapDom.dispatchEvent(mouseEvent)
但此时透视区域则默认在左上角零点,就先这样吧。
-