OpenLayers 3 之 使用矢量圖層(Vector)

更新 - 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格式!
發佈了81 篇原創文章 · 獲贊 263 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章