更新 - 2018-05-25
由於openlayers的版本升級迭代,本文程序已經不可運行,最新代碼可到這裏查看: https://github.com/QingyaFan/openlayers-examples/blob/master/vector.html 。
摘要
矢量圖層:矢量圖層是用來渲染矢量數據的圖層類型,在OpenLayers裏,它是可以定製的,可以控制它的透明度,顏色,以及加載在上面的要素形狀等。
常用於從數據庫中請求數據,接受數據,並將接收的數據解析成圖層上的信息。如將鼠標移動到中國,相應的區域會以紅色高亮顯示出來,高亮便是矢量圖層的行爲。
主要內容
1、 HTML文件的進化
這次添加矢量圖層,如果再獨自寫一個JS文件,就得在引用一個外部JS文件,如果後續再加一個功能,那麼就會越來越多的JS文件,不免造成JS文件之間造成干擾,比如說命名衝突等,所以就直接將功能寫在以前的JS文件中(popup.js),並將其更名爲“map_utils.js”,意爲地圖工具集!
首先我們在HTML中原來存留的JavaScript移動到map_utils.js文件中,因爲做到表觀層和邏輯層分離,是一個很重要的事情,便於後期的管理。之所以之前沒有一步就那麼做,是爲了讓大家意識到 -- 過早優化沒有必要,怎麼實現方便,就先做,避免過度考慮。有一句話說的好:“一個思想過度的人,行動非常軟弱!”。
同時,我們將CSS也分離到一個單獨的文件中 – map_style.css,這樣,現階段,就比較容易維護了,別忘了添加引用CSS的語句哦。
我們並不用對HTML頁做其它的修改了,因爲矢量圖層是一個圖層,是從屬於Map對象的(注:一個map可以包含很多layer,layer包含底圖和一般圖層)。
修改後的HTML頁面如下:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="http://openlayers.org/en/v3.3.0/css/ol.css" type="text/css">
<link rel="stylesheet" href="map_style.css" type="text/css">
<title>OpenLayers 3</title>
</head>
<body>
<h2>My Map</h2>
<div id="map" class="map">
<div id="popup" class="ol-popup">
<a href="#" id="popup-closer" class="ol-popup-closer"></a>
<div id="popup-content" style="width:300px; height:120px;"></div>
</div>
</div>
<script src="http://openlayers.org/en/v3.3.0/build/ol.js" type="text/javascript"></script>
<script src="map_utils.js" type="text/javascript"></script>
</body>
</html>
2、 JavaScript文件的修改
接下來,我們就給我們的“map_utils.js”做點手術。
首先我們定義需要全局都能訪問到的變量:map ,vectorLayer等等:
/**
* 定義一些全局變量
*/
var map, vectorLayer;
var highlightStyleCache = {}, highlight;
//彈出框需要的部件
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');
我們原來定義的map,還是可以拿來直接用,但是需要添加一個vector圖層,所以這個圖層要提前定義,首先我們定義矢量圖層的樣式,實例化一個style對象:
/**
* 定義矢量圖層
* 其中style是矢量圖層的顯示樣式
*/
var style = new ol.style.Style({
fill: new ol.style.Fill({ //矢量圖層填充顏色,以及透明度
color: 'rgba(255, 255, 255, 0.6)'
}),
stroke: new ol.style.Stroke({ //邊界樣式
color: '#319FD3',
width: 1
}),
text: new ol.style.Text({ //文本樣式
font: '12px Calibri,sans-serif',
fill: new ol.style.Fill({
color: '#000'
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 3
})
})
});
然後將style用於初始化矢量圖層:
vectorLayer = new ol.layer.Vector({ //初始化矢量圖層
source: new ol.source.GeoJSON({
projection: 'EPSG:3857',
url: 'data/geojson/countries.geojson' //從文件加載邊界等地理信息
}),
style: function(feature, resolution) {
style.getText().setText(resolution < 5000 ? feature.get('name') : ''); //當放大到1:5000分辨率時,顯示國家名字
return [style];
}
});
接下來就是實例化map,還是原來的樣子,出了layers加了一個適量圖層vectorLayer:
map = new ol.Map({ //初始化map
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'sat'})
}),
vectorLayer
],
view: new ol.View({
center: ol.proj.transform([37.41, 8.82], 'EPSG:4326', 'EPSG:3857'),
zoom: 4
})
});
接下來,當鼠標在地圖上移動時,我們要讓矢量圖層做出點反應,對,我們就讓它高亮吧。
/**
* 當鼠標移動時,高亮相應的區域的函數
*/
var featureOverlay = new ol.FeatureOverlay({
map: map,
style: function(feature, resolution) {
var text = resolution < 5000 ? feature.get('name') : '';
if (!highlightStyleCache[text]) {
highlightStyleCache[text] = [new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#f00',
width: 1
}),
fill: new ol.style.Fill({
color: 'rgba(255,0,0,0.1)'
}),
text: new ol.style.Text({
font: '12px Calibri,sans-serif',
text: text,
fill: new ol.style.Fill({
color: '#000'
}),
stroke: new ol.style.Stroke({
color: '#f00',
width: 3
})
})
})];
}
return highlightStyleCache[text];
}
});
var displayFeatureInfo = function(pixel) {
var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
return feature;
});
if (feature !== highlight) {
if (highlight) {
featureOverlay.removeFeature(highlight);
}
if (feature) {
featureOverlay.addFeature(feature);
}
highlight = feature;
}
};
以上是當鼠標移動時的反應,我們要將它綁定到地圖的鼠標移動事件中:
/**
* 鼠標移動的事件
*/
map.on('pointermove', function(evt) {
if (evt.dragging) { //如果是拖動地圖造成的鼠標移動,則不作處理
return;
}
var pixel = map.getEventPixel(evt.originalEvent);
displayFeatureInfo(pixel);
});
就是這樣的效果:
當點擊鼠標的時候,你並不想沒有反應吧!?所以我們再添加一個鼠標點擊事件,效果是彈出我們上一節引入的彈出框框。
/**
* 鼠標點擊的事件
*/
map.on('click', function(evt) {
var pixel = map.getEventPixel(evt.originalEvent);
var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
return feature;
});
var coordinate = evt.coordinate;
var hdms = ol.coordinate.toStringHDMS(ol.proj.transform(
coordinate, 'EPSG:3857', 'EPSG:4326'));
if(feature!==undefined){
content.innerHTML = '<p>你點擊的座標是:</p><code>' + hdms + '</code><p>這裏屬於:'+ feature.get('name') + '</p>';
}
else{
content.innerHTML = '<p>你點擊的座標是:</p><code>' + hdms + '</code><p>這裏是大海!</p>';
}
overlay.setPosition(coordinate);
map.addOverlay(overlay);
});
/**
* 隱藏彈出框的函數
*/
closer.onclick = function() {
overlay.setPosition(undefined);
closer.blur();
return false;
};
這樣,就搞定了。我們看一下運行效果:
總結
這次,我們不僅添加了新功能 -- 矢量圖層,而且整理了HTML、JavaScript和CSS的結構,不過矢量圖層的數據是來自本地文件的,這種情況在真正的應用中很少見,一般都是直接來自後端數據庫的,而且對於網絡地圖這種需要傳輸大量數據的應用來說,減少重新加載的機會和選用一種輕量的傳輸格式至關重要!
這是下一次我們將要涉及的內容,服務器與客戶端的通信手段:AJAX通信,以及傳輸數據格式:GeoJSON格式!