openlayers中單擊獲取要素
目錄
一、引言
以前在做arcgis js開發的時候,就開始糾結單擊獲取要素使用哪種方法,當時是因為arcgis server正好提供了arcgis定制的服務IdentifyTask,所以當時用了arcgis server查詢的。
總結一下查詢方法有如下幾種:

這四種各有優缺點,下面詳細介紹前兩種方法,后面兩種方法涉及到的知識比較多,不方便展開,僅提供思路==
二、前台方法
1、interaction中select方法
針對矢量數據源,openlayers中提供了select交互類方面鼠標選擇。
-
/*overlay*/
-
// Popup showing the position the user clicked
-
var popup = new ol.Overlay({
-
element: document.getElementById('popup'),
-
autoPan:true,
-
autoPanMargin:100,
-
positioning:'center-right'
-
});
-
map.addOverlay(popup);
-
-
/*select*/
-
var selectSingleClick = new ol.interaction.Select();
-
map.addInteraction(selectSingleClick);
-
/*前端第一種*/
-
selectSingleClick.on( 'select', function(e) {
-
var features=e.target.getFeatures().getArray();
-
var element = popup.getElement();
-
if (features.length>0)
-
{
-
var feature=features[0];
-
var type=feature.getGeometry().getType();
-
var property=feature.getProperties();
-
var coordinate = ol.extent.getCenter(feature.getGeometry().getExtent());
-
var hdms="點名:"+property["Text"];
-
hdms=hdms+ "<br/>";
-
hdms = hdms+ "圖層名::"+property["Layer"];
-
hdms=hdms+ "<br/>";
-
hdms = hdms+ "位置:"+coordinate[0]+"-"+coordinate[1];
-
-
$(element).popover( 'destroy');
-
popup.setPosition(coordinate);
-
// the keys are quoted to prevent renaming in ADVANCED mode.
-
$(element).popover({
-
'placement': 'top',
-
'animation': false,
-
'html': true,
-
'content': hdms
-
});
-
$(element).popover( 'show');
-
}
-
else
-
{
-
$(element).popover( 'destroy');
-
-
}
-
-
});
這里popup是個overlay覆蓋物,用於彈出框顯示得到的feature要素。
2、map中forEachFeatureAtPixel方法
針對矢量數據源,通過鼠標點擊坐標與map坐標對比,獲取選中要素,openlayers提供了相關函數。
-
/*前端第二種*/
-
map.on( "click", function(e) {
-
var element = popup.getElement();
-
$(element).popover( 'destroy');
-
map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
-
//do something
-
var type=feature.getGeometry().getType();
-
var property=feature.getProperties();
-
var coordinate = ol.extent.getCenter(feature.getGeometry().getExtent());
-
var hdms="點名:"+property["Text"];
-
hdms=hdms+ "<br/>";
-
hdms = hdms+ "圖層名::"+property["Layer"];
-
hdms=hdms+ "<br/>";
-
hdms = hdms+ "位置:"+coordinate[0]+"-"+coordinate[1];
-
-
$(element).popover( 'destroy');
-
popup.setPosition(coordinate);
-
// the keys are quoted to prevent renaming in ADVANCED mode.
-
$(element).popover({
-
'placement': 'top',
-
'animation': false,
-
'html': true,
-
'content': hdms
-
});
-
$(element).popover( 'show');
-
})
-
});
這里省略了popup,與上個例子中類似。
三、gis server方法
1、wms中getfeatureinfo
針對沒有顯示到地圖上,但是有wms的圖層數據,我們可以使用getfeatureinfo從geoserver(或者其他支持wms的gis服務器)獲取要素,這個是跟ogc標准相關的,與具體的gis服務器無關。
-
var format = 'image/png';
-
var wmsLayer = new ol.layer.Tile({
-
//visible: false,
-
source: new ol.source.TileWMS({
-
url: 'http://localhost:8080/geoserver/xcy/wms',
-
params: {'FORMAT': format,
-
'VERSION': '1.1.1',
-
tiled: true,
-
"STYLES": '',
-
"LAYERS": 'xcy:polygon'
-
//"exceptions": 'application/vnd.ogc.se_inimage',
-
//tilesOrigin: 8176078.237520734 + "," + 704818.0275364731
-
},
-
serverType: 'geoserver',
-
crossOrigin: 'anonymous'
-
})
-
});
-
-
map.on( 'singleclick', function(evt) {
-
document.getElementById('info').innerHTML = '';
-
var viewResolution = /** @type {number} */ (view.getResolution());
-
var url = wmsLayer.getSource().getGetFeatureInfoUrl(
-
evt.coordinate, viewResolution, 'EPSG:3857',
-
{ 'INFO_FORMAT': 'application/json'});
-
var element = popup.getElement();
-
$(element).popover( 'destroy');
-
-
if (url) {
-
$.ajax({
-
type: "GET",
-
url: url,
-
dataType:'json',
-
//data: {id:1001},//也可以是字符串鏈接"id=1001",建議用對象
-
success: function(data){
-
console.log("返回的數據: " + data.features[0].properties.Layer);
-
var layer=data.features[0].properties.Layer;
-
var hdms = "圖層名::"+layer;
-
-
$(element).popover({
-
'placement': 'top',
-
'animation': false,
-
'html': true,
-
'content': hdms
-
});
-
popup.setPosition(evt.coordinate);
-
$(element).popover( 'show');
-
}
-
});
-
-
}
-
});
首先獲取wms的當前圖層,然后拼接wms服務getfeatureinfo的url拼接,這里使用的函數獲取,也可以直接按照ogc標准自己拼接url。
2、wfs中getfeature
針對沒有顯示到地圖上但是有wfs服務的圖層數據,可以使用getfeature的方法從gis服務器中獲取要素信息,只要服務器提供ogc標准的wfs服務即可,它與wms的區別是wms中getfeatureinfo只是通過點獲取要素信息,方法比較單一,而wfs中getfeature可以使用filter進行復雜的空間查詢和屬性查詢,還可以通過bbox過濾空間信息。
-
/*gis server第二種*/
-
map.on( 'click',mapClick);
-
//點擊地圖查詢
-
function mapClick(evt)
-
{
-
var element = popup.getElement();
-
$(element).popover( 'destroy');
-
-
var coor=evt.coordinate;
-
coor=coor.join( ',');
-
//注意這里直接將點坐標提交,與圖層做intersrct分析,對於面圖層是沒關系的。如果是查詢,點或者線圖形,一定要將coor先設置一個容差,經行buffer之后的圖形,再去與圖層疊加分析。不設置容差幾乎就找不到了
-
//圖層的圖形字段是geom,不同圖層的圖形字段都要自己先看下自己的,有的是the_geom,有的是shape等等,具體分析即可。
-
var filter='filter=<Filter xmlns="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml"><Intersects><PropertyName>the_geom</PropertyName><gml:Point><gml:coordinates>'+coor+'</gml:coordinates></gml:Point></Intersects></Filter>'
-
-
$.ajax({
-
type: "GET",
-
//url: "http://localhost:8080/geoserver/xcy/wfs?service=WFS&request=GetFeature&version=1.1.0&typename=xcy:polygon&outputFormat=json&CQL_FILTER=EntityHand='7E25'",
-
//屬性查詢
-
//url: "http://localhost:8080/geoserver/xcy/wfs?service=WFS&request=GetFeature&version=1.1.0&typename=xcy:polygon&outputFormat=json&PROPERTYNAME=Layer&FEATUREID=polygon.2",
-
//空間查詢
-
url: 'http://localhost:8080/geoserver/xcy/wfs?service=WFS&request=GetFeature&version=1.1.0&typename=xcy:polygon&outputFormat=json&'+filter ,
-
-
dataType:'json',
-
success: function(data){
-
console.log("返回的數據: " + data.features[0].properties.Layer);
-
var layer=data.features[0].properties.Layer;
-
var hdms = "圖層名::"+layer;
-
-
$(element).popover({
-
'placement': 'top',
-
'animation': false,
-
'html': true,
-
'content': hdms
-
});
-
popup.setPosition(evt.coordinate);
-
$(element).popover( 'show');
-
}
-
-
});
-
}
前兩個url是屬性查詢,使用的url是通過filter進行一個點的空間查詢,詳細wfs服務可以查看http://docs.opengeospatial.org/is/04-094r1/04-094r1.html#118
空間查詢還是比較復雜的,filter中的xml還需詳細理解一下。
四、后台方法
最近出了個紅芯瀏覽器,用的谷歌的內核,包裝了下外表就說自主研發的,讓人啼笑皆非,不過在碼農的世界里沒有利益,有現成的可以解決問題還是要善於借鑒的,這里可以使用AE或者geotool。
AE是arcgis的,C#陣營可以使用;geotool是開源的,java陣營比較方便。
首先使用正常的web框架,將點擊坐標參數傳到后台,用geojson或者自定義字符串隨意,只要你能解析出來;
后台集成了AE或者geotool之后可以通過里面的空間分析或者屬性分析工具,查出要查詢的要素;
最后使用json返回,格式你自己定咯;
五、空間數據庫方法
這種方法與后台方法類似,縣將點擊坐標參數傳到后台,只不過沒有使用的AE或者geotool來進行空間分析,而是直接使用空間數據庫中的空間查詢sql語句來查詢數據,然后提交到后台,后台提交到前台顯示。
執行sql如下: select * from t where ST_Intersect(t.geom,ST_GeomfromText('Point(x y)',3857));
六、總結
這幾種方法沒有絕對的好與壞,只是適合不適合的問題。
- 前台:矢量數據,必須加載到地圖,如果沒有加載或者是wms就不可以了。這種方法比較方便,僅學習openlayers就可以,但是換了前端js框架就完戲;
- gis server:數據發布為wms或者wfs,不必須加載到地圖。可以看作提供地圖數據的普通server,只要數據被發布就可以查詢到,而且符合ogc標准,許多外部的數據可以為我所用;
- 后台:提供接口,不必須加載到地圖,相當於使用第三方庫做了一個gis server。不符合ogc發布標准,但是定制化程度高,不過依賴第三方庫,不用gis server發布數據,AE還要收費的;
- 空間數據庫:提供接口,不必須加載到地圖,相當於在空間數據庫基礎上做了gis server。不符合ogc發布標准,定制化程度高,不依賴第三方庫,不用gis server發布數據,需要數據庫空間拓展,相對於后台方法比較適合處理大量數據,一個點擊事件用數據庫有點高射炮打蚊子了==
一個點擊獲取要素搞這么多種方法,有必要搞得這么復雜么?是的,單獨從解決問題的角度我們並沒有必要這么做,但是從這個過程中鍛煉的是一種思想,數據從前台、后台、普通server、gis server、數據庫等獲取的各種手段,這個不僅在點擊事件有這么多種方法,往大里講整個系統架構也無非是這么幾種。
