上次[http://blog.csdn.net/sinat_25295611/article/details/79110368] 遇到一個神奇的BUG,懷疑是openlayers這個版本中自動繪製 Text 的一個Bug,其他要素的Text背景樣式失效了,一直沒有解決。
於是換了另外一種方式來實現,也就是 使用 ol.Overlay 來添加標籤。
當加載完Source要素的時候,獲取每個要素的’name’屬性,將其作爲標籤,這裏需要注意一點的是,經常有人問怎麼監聽要素已經加載完畢,由於使用 ol.source.Vector 加載要素(wfs服務/geojson文件等等)是異步加載,所以,在代碼中要給要素綁定事件的時候可能還沒有該要素,比如下面這樣:
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: [-72.980624870461128, 48.161307640513321],
zoom: 8,
projection: 'EPSG:4326'
}),
target: 'map'
});
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: '../data/geojson/line.geojson',
format: new ol.format.GeoJSON()
})
});
map.addLayer(vectorLayer);
// 如果在此處調用vectorLayer.getSource().getFeatures()是完全有可能獲取不到任何Feature的
去查Openlayers的 API文檔會看到 ol.source.Vector
有一個loader
的屬性,並在後面有一段示例代碼:
var vectorSource = new ol.source.Vector({
format: new ol.format.GeoJSON(),
loader: function(extent, resolution, projection) {
var proj = projection.getCode();
var url = 'https://ahocevar.com/geoserver/wfs?service=WFS&' +
'version=1.1.0&request=GetFeature&typename=osm:water_areas&' +
'outputFormat=application/json&srsname=' + proj + '&' +
'bbox=' + extent.join(',') + ',' + proj;
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
var onError = function() {
vectorSource.removeLoadedExtent(extent);
}
xhr.onerror = onError;
xhr.onload = function() {
if (xhr.status == 200) {
vectorSource.addFeatures(
vectorSource.getFormat().readFeatures(xhr.responseText));
} else {
onError();
}
}
xhr.send();
},
strategy: ol.loadingstrategy.bbox
});
後面一段說明:The loader function used to load features, from a remote source for example. If this is not set and url is set, the source will create and use an XHR feature loader.
也就是說,loader是一個函數用於加載數據源,但如果未設置,並且設置了url,就會用XHR異步請求來加載數據源。也就是說,我們完全可以用 loader
這個函數來代替 url
,在其中我們可以自定義的發送請求,然後在回調函數中,對獲取的要素源進行處理。
於是用loader來給每個要素手工添加標籤,當加載完Source要素的時候,獲取每個要素的’name’屬性,將其作爲標籤。就像這樣:
var beijingSource=new ol.source.Vector({
format: new ol.format.GeoJSON(),
loader:function (extent,resolution,projection) {
var url='http://'+host+'/geoserver/wfs?' +
'service=wfs&version=1.1.0&request=GetFeature&typeNames=ztbr:beijing_pq&outputFormat=application/json&srsname=EPSG:3857';
$.ajax({
url:url,
type:'GET',
success:function (res) {
beijingSource.addFeatures(beijingSource.getFormat().readFeatures(res));
var features=beijingSource.getFeatures();
features.forEach(x =>{
//創建標籤的函數,由於我採用的vue組件開發的,vm是我的Vue的this對象
vm.creatLabelForFeature(x,"beijing_pq");
});
},
error:function () {
alert("error")
}
})
}
});
//然後是創建標籤的函數`creatLabelForFeature`
/** 1.根據傳入的要素,添加對應的Lable。並在lable上綁定點擊事件,點擊lable可以進行縮放,請求下一級的矢量地圖,同時隱藏lable */
creatLabelForFeature: function(feature,layerId) {
var vm=this;
var map=vm.map;
var beijingLayer = vm.layers.beijing_pq;
var jiedaoLayer = vm.layers.beijing_jd;
var shequLayer = vm.layers.beijing_sq;
var extent=feature.getGeometry().getExtent();
var geom = feature.getGeometry();
var pos=ol.extent.getCenter(extent);
var content = feature.get('name');
var ele=$("<div class='nameLabel'></div>");
ele.attr("layerId", layerId);
ele.html(content);
ele.css({
'font-size':'12px',
'color': '#ffffff',
'background-color':'#4D98DD' ,
'cursor': 'pointer',
'padding':'1px 4px',
'border-radius': '4px'
});
//給ele 綁點點擊事件,點擊獲取指定下一級的 wfs
ele.click(function (evt) {
map.getView().fit(geom,map.getSize());
var lid = ele.attr("layerId");
var featureName = ele.html();
// console.log(featureName);
if(lid == 'beijing_pq'){
//點擊北京區域圖層,到指定區,加載街道
beijingLayer.setVisible(false);
jiedaoLayer.setSource(new ol.source.Vector()); //每次點擊要把之前的 Source清空 fixme
vm.getWFS('beijing_jd', ol.format.filter.equalTo('district', featureName), jiedaoLayer);
}else if(lid == 'beijing_jd'){
//點擊街道圖層,到指定街道,加載社區
jiedaoLayer.setVisible(false);
shequLayer.setSource(new ol.source.Vector());
vm.getWFS('beijing_sq', ol.format.filter.equalTo('street', featureName),shequLayer);
}else if(lid == 'beijing_sq'){
//TODO 顯示一個社區
shequLayer.setSource(new ol.source.Vector());
vm.getWFS('beijing_sq', ol.format.filter.equalTo('name', featureName),shequLayer);
}
//隱藏上一級的 Overlayers
vm.clearOverlayers(lid);
});
var label = new ol.Overlay({
position: pos,
positioning: 'center-center',
element: ele[0],
stopEvent: false
});
map.addOverlay(label);
//標籤的緩存數組,下次加載時直接取用
vm.overlays[layerId].push(label);
}
於是就實現了下面的效果:(這是鼠標移入移出時就沒有了上篇文章中的Bug了。。。)