文章版權由作者李曉暉和博客園共有,若轉載請於明顯處標明出處:http://www.cnblogs.com/naaoveGIS/
1.背景
與離線瓦片方案一樣,同樣是為了解決移動端網速和流量問題,但是卻不僅僅於此。傳統的矢量數據的展示一般分為兩種方案:
- 通過WMS動態獲取范圍內的矢量數據圖片(矢量數據由后台處理成一張圖片返回),在前端疊加展示。
優點——渲染壓力在后端,前端無壓力。后台對圖片更容易做緩存(前端把地圖切分成格網,以WMS請求模擬WMTS請求)。
缺點——當前端需要交互時,必須進行動態的根據坐標查詢地理服務器(I查詢)。響應稍慢,對后端壓力大。 - 通過WFS服務獲取范圍內的矢量數據文本(geojson、pbf等格式),前端解析返回數據動態渲染。
優點——由於是前端渲染展示,交互便捷,並且可以在前段只有控制樣式。
缺點——后台和前端在獲取數據和展示數據上均有壓力,當數據量特別大時,前端渲染耗費性能容易卡頓。
而該方案上,當我們將SHP矢量數據以一定算法處理成文本文件存放到移動端后,既可以避免動態獲取數據對服務端的壓力,也可以擁有WFS方案上在前端實時渲染數據時的樣式制定和交互便捷的優點。
整個方案優點總結為:
- 規避手機網速問題
- 規避手機流量問題
- 減少服務端壓力
- 前端要素展示樣式可定制
- 要素交互快速響應
2.兩種離線算法,兩種離線矢量數據處理方案的描述對比
2.1方案一(分級矢量切片方案)
方案描述
矢量切片方案在我之前的文章中均有描述:項目角度談矢量切片運用以及Geoserver處理自定義規格矢量切片方案以及WebGIS中矢量切圖的初步研究。簡單敘述為:
- 把矢量數據當做瓦片處理,根據切圖原點、瓦片大小、各級別分辨率,先在不同級別對SHP進行抽稀簡化,然后將該級別的SHP切分成對應矢量數據塊,再處理成文本格式。
- 將矢量切片上傳至移動端,H5地圖請求獲取本地矢量切片,解析渲染。
方案分析
- 優點: 各級別數據抽稀切片,使得各級別數據量加載均可控制,前端渲染數量也處於可控狀態。
- 缺點:由於要切不同級別下的數據,矢量切片比較耗費時間,而且切圖數據量大。不利於快速實施。
2.2方案二(固定網格切片方案)
方案描述
- 以固定幾何大小的網格對SHP數據切片處理成文本。
- 前端實時根據此時的可視范圍,基於預制的網格切片大小,算出此時范圍下對應的各切片,請求加載,解析渲染。
方案分析
- 優點:只需根據預制的網格大小將矢量數據一次切割生成,效率比較高。
- 缺點:在地圖級別很小顯示全圖時,加載的切片數量過多導致前端渲染壓力非常大。
2.3方案選型
- 方案二優於方案一最大的地方在於實施更快速。
- 方案二最大的缺點是在低地圖級別時顯示的數據過量問題,這里可以通過兩個手段規避。
控制顯示層級——即只讓地圖縮放至某個級別上時才加載該矢量數據。
控制顯示數量——將網格數據進一步以責任網格打包,固定人員只展示固定責任網格范圍內的數據。
3.矢量數據網格切分打包工具的實現
3.1SHP數據網格切分詳細描述
- 獲得該圖層的幾何范圍,依據切圖原點、網格大小,算出該圖層對應的網格數量(colnums、rownums)以及網格的起始切片的行列編號(startcolnum、startrownum)。
- 以colnums和rownums作為雙循環遍歷結束點,依次將圖層中的要素切片,處理成文本文件。
代碼描述:
//計算格網行列號 int colNums = 0, rowNums = 0; colNums = Convert.ToInt32(Math.Ceiling((_maxX - _minX) / inputGridSize)); rowNums = Convert.ToInt32(Math.Ceiling((_maxY - _minY) / inputGridSize));
3.2基於單元網格的已有切片打包描述
選用單元網格圖層進行打包,主要原因為單元網格為最小划分網格,變動相對較少,減少實施次數。利用網格將已有的切片再進行整合打包,可進一步控制前端展示時的矢量數據數量。
- 遍歷獲取網格圖層中的網格要素,得到各要素的幾何范圍。
- 依據幾何范圍、網格大小、切圖原點,算出該范圍內包含的瓦片編號。
- 將這些瓦片拷貝至以(要素編碼\部件類型編號)命名的文件夾中。
- 遍歷處理完所有數據拷貝后,進行整體的文件壓縮。
注意:
瓦片的打包路徑規范為:
工具界面為:
4.H5地圖前端展示實現
4.1詳細描述
前端展示所用算法與網格打包時所用算法相同。JS獲取本地數據的思想方法也與我在移動端H5地圖離線瓦片方案中描述的移動端讀取本地瓦片的方法相同。不做累述,核心代碼如下:
var originx=parseFloat(gridClipParams[0]); var originy=parseFloat(gridClipParams[1]); var size=parseFloat(gridClipParams[2]); var vectorSource = new VectorSource({ format:format, url:function(extent) { var temurl=GeosService.queryContent(url,servicelayerid,where,extent); if(useMobileCache){ var col=Math.floor(Math.abs((extent[0]-originx))/size); var row=Math.floor(Math.abs((extent[1]-originy))/size); //本地測試url //temurl="http://192.168.32.135:8080/gis/tilemap/11010100100907/"+subtypeid+"/"+row+"/"+col+".json"; temurl =self.offlineURL+encodeURIComponent(temurl)+"&row="+row+"&col="+ col+"&layername="+subtypeid; } return temurl; }, strategy: function(extent,resolution){ var minx=extent[0]-size; var miny=extent[1]-size; var maxx=extent[2]+size; var maxy=extent[3]+size; var m=Math.ceil((maxx-minx)/size); var n=Math.ceil((maxy-miny)/size); var extentArr=new Array(); for(var i=0;i<m;i++){ for(var j=0;j<n;j++){ var temextent=[]; var temminx=minx+i*size; var temminy=miny+j*size; var temmaxx=minx+(i+1)*size; var temmaxy=miny+(j+1)*size; temextent=[temminx,temminy,temmaxx,temmaxy]; extentArr.push(temextent); } } return extentArr; } });
4.2成果展示
由於部件打包是以1000米的網格進行划分后再打包,可以看見有的不在單元網格區划內的部件也展示在了地圖上。所以網格切分的大小是一個必須根據項目進行調整的參數。
5.移動端打包上傳詳細描述
我將打包上傳單獨進行描述,是因為這一塊整合時需要格外注意文件的合並方式。
- 手機服務端獲取到責任網格與單元網格的對應關系。
- 將責任網格對應的所有單元網格下的文件進行合並。合並規則為增蓋方式。合並后的文件夾名稱為責任網格命名。
責任網格打包文件夾的路徑說明: \責任網格編碼\部件小類\行號\列號.json
-----歡迎轉載,但保留版權,請於明顯處標明出處:http://www.cnblogs.com/naaoveGIS/
如果您覺得本文確實幫助了您,可以微信掃一掃,進行小額的打賞和鼓勵,謝謝 ^_^