ArcGISDynamicMapServiceLayer(動態地圖服務)通常用於實時顯示經常變化的數據,支持控制單個圖層可見性,可動態投影。但缺點是顯示效果較差,整個服務出圖較慢;ArcGISTiledMapServiceLayer可以直接加載服務器端的緩存地圖服務,顯示效果好,速度快,但它的缺點正是ArcGISDynamicMapServiceLayer的優點,即不支持動態投影,不能控制圖層可見性,服務器端需要提前生成緩存等。
這裏嘗試自己來在客戶端封裝一個類,創建一種新的客戶端圖層類型。它能夠綜合以上兩個圖層的優點,而克服其各自的缺點。大致總結一下我們要達到的目的:
|
ArcGISDynamicMap ServiceLayer |
ArcGISTiledMap ServiceLayer |
自定義的客戶端圖層 |
實時獲取最新數據 |
Y |
N |
Y |
切片方式顯示服務 |
N |
Y |
Y |
需要提前生成緩存 |
Y |
N |
|
客戶端緩存切片加快顯示速度 |
N |
Y |
Y |
利用subdomain加速緩存加載 |
N |
Y |
Y |
支持動態投影 |
Y |
N |
Y |
動態指定圖像輸出格式 |
Y |
N |
Y |
控制子圖層可見性 |
Y |
N |
Y |
利用LayerDefination過濾數據 |
Y |
N |
Y |
利用TimeExtent顯示時態數據 |
Y |
N |
Y |
其它緩存服務特性 |
N |
Y |
Y |
其它動態服務特性 |
Y |
N |
Y |
首先來解決以緩存服務的方式來顯示動態服務的問題。《ArcGIS客戶端API中加載大量數據的幾種解決辦法(以Silverlight API爲例)》一文中其實已經提到,主要是繼承TiledMapServiceLayer,其中獲取切片的GetUrl()方法,返回值是利用REST SDK中的ExportMap拼接的Url。這樣,我們就並不需要提前切圖,輸入動態地圖服務,從而達到緩存地圖服務的顯示效果。
舉一個例子,如果我想讓自己的服務可以和Google Maps/Bing Maps/ArcGIS Online的服務相疊加(WKID 102100/3857),那麼GetUrl()方法中看其來應該是這樣(裏面包括瞭如何根據level,row,col來計算一個切片的四個角點座標):
1: public override string GetTileUrl(int level, int row, int col)
2: {
3: string baseUrl = @"{0}/export?dpi=96&transparent=true&format=png8&bbox={1}%2C{2}%2C{3}%2C{4}&bboxSR=102100&imageSR=102100&size=256%2C256&f=image";
4:
5: double cornerCoordinate = 20037508.3427892;
6: double originResolution = cornerCoordinate * 2 / 256;
7: double resolution = originResolution;
8: for (int i = 0; i < level; i++)
9: {
10: resolution /= 2;
11: }
12: double xmin, ymin, xmax, ymax;
13: //double resolution = 39135.7584820001;
14: xmin = -cornerCoordinate + resolution * 256 * col;
15: ymin = cornerCoordinate - resolution * 256 * (row + 1);
16: xmax = -cornerCoordinate + resolution * 256 * (col + 1);
17: ymax = cornerCoordinate - resolution * 256 * row;
18:
19: return string.Format(baseUrl, Url, xmin, ymin, xmax, ymax);
20: }
然後再來看下我們自定義圖層實現ArcGISDynamicMapServiceLayer功能的可行性。
關於動態投影。如果想要疊加到WGS84座標的底圖上,只需要將bboxSR和imageSR改成4326即可。這樣便支持了動態投影。
關於“切片”格式ImageFormat。只需修改上面baseUrl中的format參數。這樣一來既不需要在服務器端提前切圖,也能動態改變“切片”的格式。
關於服務加載速度。如果對於出圖速度不滿意,則可以在服務器端發佈若干個相同的服務,輪詢使用每個服務來出圖,可以達到並行加速的目的。
關於DisableClientCache。默認情況下,與ArcGISTiledMapServiceLayer一樣,這些“切片”會緩存在客戶端,便於再次瀏覽。如果服務器端數據有變,那麼就無法看到最新的變化情況,這是緩存服務的一個缺點。在自定義的圖層類型中,我們可以在exportmap操作的Url最後再加一個時間戳參數,比如_ts=DateTime.Now.Ticks.ToString(),那麼就達到動態地圖服務每次都能看到最新結果的目的。
關於控制子圖層的可見性。REST SDK的ExportMap操作中有layers參數可以控制。比如layers=show:2,4,7,則只會顯示第3、5、8圖層內容。
關於圖層內容過濾。ArcGISDynamicMapServiceLayer有LayerDefinitions屬性可以用SQL語句來篩選地圖服務的輸出內容,而REST中的ExportMap方法也提供了layerDefs供我們調用。比如{"0":"POP2000 > 1000000","5":"AREA > 100000"} ,只輸出第一個圖層中POP2000字段大於1000000的要素,第六個圖層中AREA>100000的要素。
關於ArcGIS Server 10中的TimeExtent。ArcGISDynamicMapServiceLayer有一個TimeExtent屬性用來顯示一定時間範圍內的數據,而ExportMap方法也給我們提供了Time參數來實現這個功能;並且還有layerTimeOptions參數來控制每個圖層的時間段(偏移)。
關於服務的元數據。ArcGISDynamicMapServiceLayer和ArcGISTiledMapServiceLayer中,都有一些關於服務元數據的屬性。比如Capabilities,CopyrightText,Description,InitialExtent,FullExtent等,這些在REST的MapService資源中都已經暴露了出來,因此我們可以通過發送請求的方式,在自定義圖層初始化的時候順便取回這些數據。
關於ArcGISTiledMapServiceLayer中的TileInfo。繼承TiledMapServiceLayer類的第一個條件就是得知Tiling Scheme。自然TileInfo也是探囊取物。
細心的朋友已經看出來,其實和ArcGISDynamicMapServiceLayer、ArcGISTiledMapServiceLayer一樣,我們這裏自定的圖層也是對ArcGIS Server REST SDK的一個封裝,但在顯示方式和顯示速度上有所改進。輸入的是動態地圖服務,有緩存服務的效果,但沒有真正做過緩存,所以姑且把它叫做DynamicTileMapServiceLayer。