赞
踩
在ol4里面可以通过Vector Layer的方式进行点的渲染,但是当点的个数比较多的时候,会存在明显的操作不流畅。本文讲述如何利用ImageCanvas接口,对大量的点进行展示,并添加相应的交互。
ol的最终渲染也是通过canvas的方式来渲染的,但是为什么效率会差这么多呢?分析原因,是因为:
1)Vector的渲染方式会保留很多交互相关的操作;
2)ImageCanvas的方式其实是将数据渲染到一个新的画布上,再以图片的方式渲染到map的canvas上;
地图上的渲染查看相关的接口实现起来比较简单,这里重点说一下渲染完后如何交互。在实现地图交互的时候,存在两个技术点:
1)如何判断鼠标经过的位置要触发交互的位置?
我们知道每一个点的大小是指的像素值,所以在判断位置的时候调用view的getResolution()接口,实时计算一个半径,通过鼠标当前点+半径可以创建一个圆,在判断落在圆内的点就为交互的点。代码实现如下:
map.on('pointermove', function (e) { var coord = e.coordinate; var res = map.getView().getResolution(); var _radius = res * r; var _circle = new ol.geom.Circle(coord, _radius); var lonlat = ol.proj.toLonLat(coord); var index = getLonLatIndex(lonlat[0], lonlat[1]); if(index !== -1) { var data = dataCache[index].data; for (var i = 0; i < data.length; i++) { var d = data[i]; var _coord = ol.proj.fromLonLat([d.lon, d.lat]); if (_circle.intersectsCoordinate(_coord)) { map.getTargetElement().style.cursor = 'pointer'; document.getElementById('popup').innerText = d.n; popup.setPosition(_coord); break; } else { map.getTargetElement().style.cursor = 'default'; popup.setPosition(null); } } } });
2)大量数据的检索如何优化?
针对大量数据的检索,在处理的时候做了前端的分区缓存,在通过经纬度去查找对应的分区位置,再去找里面的数据。实现代码如下:
// 1、核心函数,通过经纬度计算分区位置 function getLonLatIndex(lon, lat) { var index = -1; // 在边界内 if(ol.extent.containsCoordinate(chinaB, [lon, lat])) { var idxX = (lon - chinaB[0]) / deltLon, idxY = (lat - chinaB[1]) / deltLat; index = Math.floor(idxY) * numLon + Math.floor(idxX); } return index; } // 2、缓存数据 for(var i = 0;i<data.length;i++) { var d = data[i]; var idx = getLonLatIndex(d.lon, d.lat); if(idx !== -1) { dataCache[idx].data.push(d); } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://openlayers.org/en/v4.6.5/css/ol.css" type="text/css"> <link rel="stylesheet" href="css/demo.css" type="text/css"> </head> <body> <div id="map"></div> <div id="popup"></div> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script> <script src="js/demo.js"></script> <script> var vec_w = getWmsLayer("light"); var data = []; var chinaB = [60, 0, 140, 55]; var deltLon = 8, deltLat = 5.5; var numLon = (chinaB[2] - chinaB[0]) / deltLon, numLat = (chinaB[3] - chinaB[1]) / deltLat; var dataCache = []; // 数据从左下角开始 for(var j =0;j<numLat;j++) { var maxLat = chinaB[1] + (j+1)*deltLat, minLat = chinaB[1] + j*deltLat; for(var i =0;i<numLon;i++) { var maxLon = chinaB[0] + (i+1)*numLon, minLon = chinaB[0] + i*numLon; var dCache = { xmin: minLon, xmax: maxLon, ymin: minLat, yMax: maxLat, data: [] }; dataCache.push(dCache); } } var r = 3; var map = new ol.Map({ controls: ol.control.defaults({ attribution: false }), target: 'map', layers: [vec_w], view: new ol.View({ center: ol.proj.fromLonLat([98.633, 31.607]), zoom:4, minZoom:0, maxZoom:18 }) }); var popup = new ol.Overlay({ element: document.getElementById('popup'), position: null, positioning: 'center-left', offset: [16, 0] }); map.addOverlay(popup); var imageLayer = new ol.layer.Image({ source: null, opacity: 0.85 }); map.addLayer(imageLayer); map.on('click', function (e) { var coord = e.coordinate; var res = map.getView().getResolution(); var _radius = res * r; var _circle = new ol.geom.Circle(coord, _radius); var lonlat = ol.proj.toLonLat(coord); var index = getLonLatIndex(lonlat[0], lonlat[1]); if(index !== -1) { var data = dataCache[index].data; for (var i = 0; i < data.length; i++) { var d = data[i]; var _coord = ol.proj.fromLonLat([d.lon, d.lat]); if (_circle.intersectsCoordinate(_coord)) { console.log(d); break; } } } }); map.on('pointermove', function (e) { var coord = e.coordinate; var res = map.getView().getResolution(); var _radius = res * r; var _circle = new ol.geom.Circle(coord, _radius); var lonlat = ol.proj.toLonLat(coord); var index = getLonLatIndex(lonlat[0], lonlat[1]); if(index !== -1) { var data = dataCache[index].data; for (var i = 0; i < data.length; i++) { var d = data[i]; var _coord = ol.proj.fromLonLat([d.lon, d.lat]); if (_circle.intersectsCoordinate(_coord)) { map.getTargetElement().style.cursor = 'pointer'; document.getElementById('popup').innerText = d.n; popup.setPosition(_coord); break; } else { map.getTargetElement().style.cursor = 'default'; popup.setPosition(null); } } } }); function canvasFunction(extent, res, pixelRatio, size) { var mapSize = map.getSize(); var zoom = map.getView().getZoom(); r = zoom * 0.6; r = r<3 ? 3: r; r = r > 10 ? 10: r; var xOff = (size[0] - mapSize[0]) / 2, yOff = (size[1] - mapSize[1]) / 2; var canvas = document.createElement('canvas'); canvas.setAttribute('width', size[0]); canvas.setAttribute('height', size[1]); var ctx = canvas.getContext('2d'); for(var i = 0;i<data.length;i++) { var d = data[i]; ctx.fillStyle = getValueColor(d["pre_1h"]); ctx.strokeStyle = 'rgba(0,0,0,0.2)'; ctx.strokeWidth = 1; ctx.beginPath(); var coord = ol.proj.fromLonLat([d["lon"], d["lat"]]); var pixel = map.getPixelFromCoordinate(coord); // x, y, r, start, end ctx.arc(pixel[0] + xOff, pixel[1] + yOff, r, 0, 2*Math.PI); ctx.fill(); ctx.stroke(); } return canvas; } function getLonLatIndex(lon, lat) { var index = -1; // 在边界内 if(ol.extent.containsCoordinate(chinaB, [lon, lat])) { var idxX = (lon - chinaB[0]) / deltLon, idxY = (lat - chinaB[1]) / deltLat; index = Math.floor(idxY) * numLon + Math.floor(idxX); } return index; } $.get("datas/data.json", (res) => { data = res.data; // data = getRandomData(); var source = new ol.source.ImageCanvas({ canvasFunction: canvasFunction }); imageLayer.setSource(source); for(var i = 0;i<data.length;i++) { var d = data[i]; var idx = getLonLatIndex(d.lon, d.lat); if(idx !== -1) { dataCache[idx].data.push(d); } } }) </script> </body> </html>
技术博客
CSDN:http://blog.csdn.NET/gisshixisheng
在线教程
https://edu.csdn.net/course/detail/799
https://edu.csdn.net/course/detail/7471
联系方式
类型 | 内容 |
---|---|
1004740957 | |
公众号 | lzugis15 |
niujp08@qq.com | |
webgis群 | 452117357 |
Android群 | 337469080 |
GIS数据可视化群 | 458292378 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。