在經過第一篇的簡單學習之後,我們開始了解一些稍微有點兒意思的東西,進一步掌握和學習利用 sharpmap進行開發的技巧。
這次,我們主要是跟大家一起學習一下如何根據地圖上的一個點,來查詢這個點所在的對象的信息, 並顯示到點擊的位置。這非常有用,比如說一個想把一個房子顯示在地圖上,我們用鼠標一點,便知道這 個房子裡住的什麼人,干什麼的,以及其它相關信息。
同樣的,我們還是使用sharpmap提供的ajax控件,環境和第一篇一模一樣。但是這裡,我們要引用一 個叫做NetTopologySuite的類庫。它經常和SharpMap一起使用,這次我們只使用其中的一個小部分,廢話 不多說,開始做。
這裡我們使用asp.net ajax 1.0,首先引用了dll,並且拖上scripmanager並設置為 EnablePageMethods=true,這樣我們就可以在頁面中寫靜態方法來實現AJAX。
在MapClicked方法(AjaxMapControl控件提供的方法,直接寫在js中即可,表示單擊的時候發生一些 事情)中,我們調用我們寫的js,根據兩個點來返回一個字符串。這個字符串就是拼好的html,直接顯示 出來。
function MapClicked(event,obj) { var mousePos = SharpMap_GetRelativePosition (event.clientX,event.clientY,obj.container); var pnt = SharpMap_PixelToMap(mousePos.x,mousePos.y,obj); var field = document.getElementById('dataContents'); //field.innerHTML = "You clicked map at: " + pnt.x + "," + pnt.y; GetData(pnt.x, pnt.y); }
這個方法裡面的SharpMap_GetRelatiovePosition和 SharpMap_PixelToMap方法根據鼠標在屏幕上的坐 標計算出鼠標點在地圖上的坐標,再調用我們自己寫的GetData方法即可。在GetData方法中,我們使用了 PageMethods來調用一個後台方法,並返回一個字符串。
PageMethods.GetData(x, y, GetDataSuccess);
然後,在GetDataSuccess中調用一個寫好的用來顯示這些返回數據的方法(此方法來自網絡,js源碼 如下)。
<script type="text/javascript"> <!-- var ns4 = document.layers; var ns6 = document.getElementById && !document.all; var ie4 = document.all; offsetX = 0; offsetY = 20; var toolTipSTYLE = ""; function initToolTips() { if (ns4 || ns6 || ie4) { if (ns4) toolTipSTYLE = document.toolTipLayer; else if (ns6) toolTipSTYLE = document.getElementById ("toolTipLayer").style; else if (ie4) toolTipSTYLE = document.all.toolTipLayer.style; if (ns4) document.captureEvents(Event.MOUSEMOVE); else { toolTipSTYLE.visibility = "visible"; toolTipSTYLE.display = "none"; } document.onclick = moveToMouseLoc; } } function toolTip(msg, fg, bg) { if (toolTip.arguments.length < 1) // hide { if (ns4) toolTipSTYLE.visibility = "hidden"; else toolTipSTYLE.display = "none"; } else // show { if (!fg) fg = "#777777"; //fore color if (!bg) bg = "#FFFFFF"; //bg color var content = msg; if (ns4) { toolTipSTYLE.document.write(content); toolTipSTYLE.document.close(); toolTipSTYLE.visibility = "visible"; } if (ns6) { document.getElementById("toolTipLayer").innerHTML = content; toolTipSTYLE.display = 'block' } if (ie4) { document.all("toolTipLayer").innerHTML = content; toolTipSTYLE.display = 'block' } } } function moveToMouseLoc(e) { if (ns4 || ns6) { x = e.pageX; y = e.pageY; } else { x = event.x + document.body.scrollLeft; y = event.y + document.body.scrollTop; } toolTipSTYLE.left = x + offsetX; toolTipSTYLE.top = y + offsetY; return true; } //--> </script>
需要指出的是,這個效果需要做一些初始化的工作:
<div id="toolTipLayer" style="position:absolute;visibility: hidden;z- index:10000"> </div> <script type="text/javascript"> initToolTips(); </script>
這樣,我們在前台的工作就基本完成了。
當然,如果想要更好看一些,再寫一個css幫助從後台傳來的html進行淡化。
.clarity { background-color:#4d7d99; filter:alpha(opacity=80,Style=0); }
OK,現在轉去後台。
在根據兩個點查詢對象數據時,我們首先要初始化需要初始化shapefile,也就是你要查詢的那個層的 數據源。
new SharpMap.Data.Providers.ShapeFile(filepath true);
然後遍歷shapefile裡面的每一個feature,對比傳入的點和feature所在的Geometry,如果傳入的點在 feature所在Geometry之內(within方法)的話,就讀取當前feature的一個attribute(通常是某個業務對 象的ID),這樣,根據這個ID就能取到業務對象的值,然後Build一下HTML,返回就OK了。主要代碼如下:
public string GetInfo(double x, double y) { SharpMap.Data.Providers.ShapeFile oShape= (SharpMap.Data.Providers.ShapeFile)GetShapeFile(filepath); if (!oShape.IsOpen) { oShape.Open(); } uint iFeature = (uint)oShape.GetFeatureCount(); SharpMap.Geometries.Point oPoint = new SharpMap.Geometries.Point(x, y); GisSharpBlog.NetTopologySuite.Geometries.Geometry oPt = SharpMap.Converters.NTS.GeometryConverter.ToNTSGeometry(oPoint, new GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory()); StringBuilder sb = new StringBuilder(); // find a record string graveInfo = string.Empty; for (uint i = 0; i < iFeature; i++) { GisSharpBlog.NetTopologySuite.Geometries.Geometry oPoly = SharpMap.Converters.NTS.GeometryConverter.ToNTSGeometry(oShape.GetFeature(i).Geometry, new GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory()); if (oPt.Within(oPoly)) { if (oShape.GetFeature(i)[someId].ToString().Length > 0) { return BuildGraveInfoTable(name, value); } } } return string.emtpy; }
這裡把sharpfile的Geometry都轉換成了NTS 的,這樣,使用NTS的Within方法進行比較。sharpmap自 己的方法在我的測試中是不能用的,希望大家在使用過程中做些嘗試,看看是否是我自己的代碼有問題, 總之,我是用的NTS。
到這裡,我們就實現了根據點來查詢對象數據的功能,我們只需要在shapefile中存儲一個attribute (比如對象的ID),然後取出來顯示出去就OK了。
同理的,我們也可以實現根據一個用戶ID來找到這個對象在地圖中的位置,並顯示在地圖中間。
代碼如下:
public SharpMap.Geometries.Point GetPointByID(string Id) { SharpMap.Data.Providers.ShapeFile oShape = (SharpMap.Data.Providers.ShapeFile)GetShapeFile(filePath); oShape.Open(); uint i = 0; uint iFeature = (uint)oShape.GetFeatureCount(); SharpMap.Geometries.Point oPt = null; for (i = 0; i < iFeature; i++) { GisSharpBlog.NetTopologySuite.Geometries.Geometry oPoly = SharpMap.Converters.NTS.GeometryConverter.ToNTSGeometry(oShape.GetFeature(i).Geometry, new GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory()); if (oShape.GetFeature(i)["Id"].ToString() == Id) { oPt = new SharpMap.Geometries.Point (oPoly.InteriorPoint.X, oPoly.InteriorPoint.Y); } } return oPt; }
找到這個點之後,設置一下控件的地圖的中心點,就OK了。
ajaxMap.Map.Center = pCenter;
雖然東西很簡單,但是還是費了我很多功夫。很大一部分原因是因為sharpmap自己提供的方法不太完 善,導致很多時間花費在了追蹤問題上。不過這種追蹤對理解開源的代碼也是很有好處的。
在這個例子中,我使用了遍歷地圖中所有feature的方法來定位一個對象,這樣非常的耗費資源,效率 並不好。如果地圖對象比較少還可以,一旦超過一定的數量級,可能會出現性能問題。以後我會在這個基 礎上進行改進,利用其它方法來實現這個功能(事實上我已經進行了一些嘗試,只是還沒有成功。如果有 人成功了,希望給我一些建議,謝謝)。
今天就到這裡,感謝大家的關注,希望多多拍磚,共同進步。
在下一篇中,我將和大家共同學習關於根據attribute的值來填充地圖上對象的顏色,設置他們的樣式 以及一些有趣的小玩意兒。希望大家繼續關注,謝謝。