概述
在ol4里面可以通过Vector Layer的方式进行点的渲染,但是当点的个数比较多的时候,会存在明显的操作不流畅。本文讲述如何利用ImageCanvas接口,对大量的点进行展示,并添加相应的交互。
实现效果
实现分析
1.效率差异如何得来?
ol的最终渲染也是通过canvas的方式来渲染的,但是为什么效率会差这么多呢?分析原因,是因为:
1)Vector的渲染方式会保留很多交互相关的操作;
2)ImageCanvas的方式其实是将数据渲染到一个新的画布上,再以图片的方式渲染到map的canvas上;
2.交互如何实现
地图上的渲染查看相关的接口实现起来比较简单,这里重点说一下渲染完后如何交互。在实现地图交互的时候,存在两个技术点:
1)如何判断鼠标经过的位置要触发交互的位置?
我们知道每一个点的大小是指的像素值,所以在判断位置的时候调用view的getResolution()接口,实时计算一个半径,通过鼠标当前点+半径可以创建一个圆,在判断落在圆内的点就为交互的点。代码实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25map.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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 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); } }
实现源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173<!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 |
最后
以上就是欣慰哈密瓜最近收集整理的关于ol4通过ImageCanvas实现大量点的展示以及交互的实现概述实现效果实现分析实现源码的全部内容,更多相关ol4通过ImageCanvas实现大量点内容请搜索靠谱客的其他文章。
发表评论 取消回复