天天看點

MapGis前端開發筆記一

一.開發環境:MapGIS IGServer10.0、OpenLayers3

二.需求分析:前端界面的道路網通過捕捉周邊的點要素個數,以此作為權重來對道路網進行顔色帶的渲染。

三.思路:1.由于路網的線要素較長,故首先要将線要素進行劃分,合理來說,應該是按照距離劃分的。2.對新的道路做緩沖區分析,緩沖區半徑自定義。3.通過緩沖區與周圍點要素進行空間查詢,得到每個緩沖區查詢到的點要素個數。4.将所有的點個數進行資料标準化,設定門檻值,進行顔色的渲染。

四.實作:

1.擷取道路。通過Zondy.Service.QueryDocFeature()的屬性查詢方法進行查詢,得到釋出的mapx檔案中所有的線要素,回調函數傳回值是個數組,這是中地的要素,要使用var format = new Zondy.Format.PolygonJSON(); var linesFeatureArr= format.read(result);得到ol的feature。

2.生成新道路。通過周遊線要素數組,通過getGeometry()得到線要素的geometry,再通過getCoordinates()得到geometry的節點坐标。通過自己寫個小方法去對線要素進行截取,最後得到的是很多個點坐标的數組。

var gLine=new Zondy.Object.GLine(
    new Zondy.Object.AnyLine([new Zondy.Object.Arc(zondy_pointArr2)])
);
var LinGeom=new Zondy.Object.FeatureGeometry({
    LinGeom:[gLine]
});
           

通過上面這個方法去得到中地的FeatureGeometry,用于做緩沖區。再通過下面這個得到ol的feature,用于添加到地圖上。現在,我就得到了兩個數組,一個是中地的線要素數組zondyRoadFeatureArr,一個是ol的線要素數組olRoadFeatureArr。

var roadSub_feature=new ol.Feature({
    type: 'route',
    geometry:new ol.geom.LineString(ol_pointArr2)
});
           

3.生成緩沖區。通過Zondy.Service.FeatureBuffBySingleRing()和zondyRoadFeatureArr生成緩沖區,該緩沖區作為面要素存在hdf裡面,傳回值裡面含有這個面要素的url,url=data.results[0].Value,将所有的緩沖區的url放在一個數組裡,bufferUrlArr。

4.查詢緩沖區。通過Zondy.Service.QueryLayerFeature和bufferUrlArr查詢出緩沖區要素,這個傳回值是一個中地的FeatureGeometry。因為要用它作為一個浏覽器上繪制的多邊形進行查詢點要素,是以要将其轉換為Zondy.Object.Polygon()。如何轉換?

//将中地的要素轉換為ol的
var format = new Zondy.Format.PolygonJSON();
var bufferFeature = format.read(result);
//将ol的要素轉換為中地的polygon
var bufferPolygon=new Zondy.Object.Polygon();
bufferPolygon.setByOL(bufferFeature[0].values_.geometry);
           

得到了一個緩沖區的要素,放到一個數組裡,就有了一個緩沖區要素的數組bufferFeatureArr。

5.查詢點要素。通過Zondy.Service.QueryDocFeature()和bufferFeatureArr進行查詢,傳回結果result.TotalCount即是點要素的個數,将其放在一個數組裡,就會有一個存到點要素個數的數組ptNumberArr。

4、5.修正!這個時候思路錯了!

需求是為了得到各個緩沖區内捕捉到的點的個數,原來的方法是通過矢量圖層查詢到緩沖區,将其作為幾何多邊形去向IG Server發送請求,去查詢點的個數。這樣太笨了!

正确的方法:通過查詢,能夠得到所有的緩沖區和點的個數,全部轉換為ol類型的,然後将緩沖區存到ol的ol.source.Vector裡,而該類有個方法叫getFeatureInExtent(extent),即在ol裡面,也是支援空間查詢的。這樣就不需要去請求伺服器了,就會快得多,并且後面的密度分析裡面同樣是這個道理,能夠大大提高效率!不過學到的Promise和async function(){await Promise}還是很有用的,雖然走了一些彎路,但是卻看到了不一樣的風景!

至此,共有5個數組。分别是zondyRoadFeatureArr,olRoadFeatureArr,bufferUrlArr,bufferFeatureArr,ptNumberArr。其中關系是這樣的:zondyRoadFeatureArr→bufferUrlArr→bufferFeatureArr→ptNumberArr,而olRoadFeatureArr還沒有用上,那麼就通過ptNumberArr的索引與olRoadFeatureArr索引一一對應的關系,将其渲染出不同的顔色。

五.遇到的坑:

1.緩存區生産失敗。原因:緩沖區執行時候的參數寫法錯誤,注意格式是下面這個樣子的,點線面生産緩沖區都要使用Zondy.Object.FeatureGeometry這個類,但是Zondy.Object.GLine、Zondy.Object.GPoint、Zondy.Object.Region這些的格式要注意一下,而這些跟Zondy.Object.PolyLine、Zondy.Object.Polygon是不一樣的,前者是複雜的,是裡面有很多内容,後者是簡單的,隻是一個多邊形。而在生成緩沖區的時候,需要用前者,在作為繪制多邊形查詢的時候,比如拉框查詢的這個“矩形”,要轉換為後者。

var gLine=new Zondy.Object.GLine(
    new Zondy.Object.AnyLine([new Zondy.Object.Arc(zondy_pointArr2)])
);
var LinGeom=new Zondy.Object.FeatureGeometry({
    LinGeom:[gLine]
});
           

2.生成的緩沖區隻要少數個成功。列印出緩沖區的url,發現有的url是列印不出來的,也就是說緩沖區執行失敗了。原因:緩沖區在生成的時候,需要對其命名,而命名的函數是通過getCurrentTime函數得到目前的時間來避免名字一樣,而這個命名函數原先寫的隻能達到秒級,而一秒可能執行多個緩沖區,故達到了毫秒,結果發現毫秒也可能出現錯誤,那麼就毫秒+Math.random()來實作。

3.js中淺拷貝與深拷貝的問題。

var a=[1,2];
var b=a;
a.pop();
console.log(b);
           

比如說,上面這個列印出來的是[1]。解釋:Javascript有五種基本資料類型(也就是簡單資料類型),它們分别是:Undefined,Null,Boolean,Number和String。還含有一種複雜的資料類型(也叫引用類型),就是對象。基本資料類型存儲在棧中,對象存在堆中,棧中的變量儲存的是這個值本身,通過“=”是來建立副本;而堆中的變量儲存并不是這個對象本身,而是指向這個對象的指針,故通過“=”複制到的隻不過是一個變量的指針位址而已,是以,兩個變量最終指向的都是一個對象。詳見下一篇轉載的部落格。而es6的解決辦法如下所示,即通過[...a]來實作深拷貝。

var a=[1,2];
var b=[...a];
a.pop();
console.log(b);
           

4.同樣的資料每次生成的結果都不一樣。原因:

var test=[1,2,3,4,5];
   $.each(test,function (index,value) {
       setTimeout(function () {
           console.log(value);
       },Math.random()*1000);
   })
           

這個代碼列印出來的是1-5,但是順序每次都不同。因為setTimeout是個異步方法,而異步的時間随機,誰時間短就先運作誰,而不是誰排在前面先運作誰。而我們的的代碼中,從得到zondyRoadFeatureArr這一刻起,zondyRoadFeatureArr的索引和olRoadFeatureArr的索引是一一對應的,而zondyRoadFeatureArr要經過多次異步方法處理,首先是緩沖區分析,其次是查詢緩沖區,然後查詢點要素。即zondyRoadFeatureArr經過了三次異步處理最後得到ptNumberArr,而這些異步處理的時間是不确定的,故zondyRoadFeatureArr的索引早已和ptNumberArr的索引發生了偏差,也就導緻了ptNumberArr和olRoadFeatureArr的索引不能一一對應。

注意:若把代碼改為這樣,是不會列印出1-5的,而是5個undefined。

var test = [1, 2, 3, 4, 5];
for (var i = 1; i < 6; i++) {
    setTimeout(function () {
        console.log(test[i]);
    }, Math.random() * 1000);
}
           

原因:var是全局變量,最後列印的是5個test[6],是以為undefined。而将其var i改為let i就可以達到$.each這個效果了,let隻在塊級作用域有效。

對于上面4中的問題怎麼辦呢?以生存緩沖區為例。

首先在執行緩存區分析的時候,這個回調函數要這樣寫:

function generateBuffer(){ 
return new Promise(function (resolve,reject) {
    bufferService.execute(function (data) {
        resolve(data);
    },"post", false, "json", function (err) {
        resolve(err);
    })
})
}
           

其次在調用生成緩存區函數的時候這樣寫:

const promises=newZondyRoadFeature.map(function (value) {
    return generateBuffer(value)
});
Promise.all(promises).then(function (results) {
    results.forEach(function (result) {
        layerBufferSuccess(result);
    })
});
           

而之前是這樣寫的:

生成緩沖區:

function generateBuffer() {      
        bufferService.execute(success(data) {
               ...
        })
           
}
           

調用的時候:

newZondyRoadFeature.map(function (value) {
       generateBuffer(value)
});
           

繼續閱讀