openlayers with google maps 簡單教程

openlayers with google maps 簡單教程

what is openlayer

openlayers是一個高性能、功能全面的地圖庫。有如下特性:javascript

  1. 支持各類格式的tiled layers數據
  2. 使用canvas的高性能vector layer
  3. 細粒度豐富的交互操做
  4. 支持commanjs風格
  5. 開源免費

why use it

通常來講google map api就知足需求了,可是當須要在地圖上繪製大量節點時,使用svg來顯示部件就會出現很嚴重的性能問題,通常狀況下google maps等的編輯操做也不夠流暢。而openlayers使用canvas做爲矢量層,大量的點線面信息對於canvas的影響是較小的,並且canvas的交互也更加流暢。css

why write this article

  1. 與高德地圖、google maps、百度地圖等國內經常使用地圖沒有很方便的接口
  2. 大版本更新後官方文檔不全面並且不夠清晰,沒有guild
  3. 並且網上簡明詳細的教程不多

針對以上幾點,以爲本身的小經驗會對你們有所幫助,能夠少走些彎路,也是對本身這幾天工做的一個總結。html

a simple example(step by step)

下面經過一個簡單地小例子介紹openlayers的一些基本用法,以及我以爲重要的地方。java

需求

須要使用google map或者高德地圖做爲底圖,在地圖上繪製一個矩形,實現矩形的編輯而且可以獲得矩形被修改以後的回調函數。大概會涉及到這些技術點:jquery

  1. 如何與google map等地圖組合使用
  2. 知道座標數組或者某格式的geo數據,如何在地圖上添加feature
  3. 完成feature的修改
  4. 獲得feature修改後的回調方法

附上簡單截圖ajax

title

初始化地圖

咱們但願openlayer能和google map等組合使用,可是因爲google等地圖廠商不肯意向openlayer「妥協」,所以如今沒法直接使用Tiled Layers,但咱們能夠將openlayer與地圖api組合起來使用。bootstrap

只使用地圖的底圖,在底圖上覆蓋一層 openlayer 的 canvas 層來顯示數據並攔截與底圖之間的交互,經過地圖的 api 來重設狀態。
此方案還有如下優勢:canvas

  1. 解決了頁面節點過多以後的性能問題
  2. 底圖能夠被抽象出去,可以在不影響交互邏輯的基礎上更換底圖。

代碼以下:api

html<!DOCTYPE html>
<html>
<head>
  <title>Snap interaction example</title>
  <script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.6.0/ol.css" type="text/css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.6.0/ol.js"></script>
  <script src="https://maps.googleapis.com/maps/api/js"></script>
  <style type="text/css">
    div.fill {
      width: 100%;
      height: 100%;
    }

    .map {
      width: 800px;
      height: 400px;
    }
  </style>
</head>
<body>


<div class="container-fluid">
  <div class="row-fluid">
    <div class="span12">
      <div id="map" class="map">
        <!-- gmap用於加載google maps, olmap用於加載openlayer canvas。
        目標是加載完畢以後olmap覆蓋與gmap之上而且攔截交互操做。
        開始時放在同一層的好處是都能根據父節點來設置長寬。也能夠在js中動態生成div,渲染後插入 -->
        <div id="gmap" class="fill"></div>
        <div id="olmap" class="fill"></div>
      </div>
    </div>
  </div>
</div>




<script type="application/javascript">
  // 加載google map並禁用地圖的交互操做
  var gmap = new google.maps.Map(document.getElementById('gmap'), {
    disableDefaultUI: true,
    keyboardShortcuts: false,
    draggable: false,
    disableDoubleClickZoom: true,
    scrollwheel: false,
    streetViewControl: false
  });

  // ol.View 是openlayers用於控制地圖的 座標系標準 zoom center rotate等操做的對象,在實例化map時候須要使用
  var view = new ol.View({
    // make sure the view doesn't go beyond the 22 zoom levels of Google Maps
    maxZoom: 21,
    projection: 'EPSG:4326' // 設置爲標準經緯度的座標標準,十分重要! 默認是'EPSG:3857'
  });

  // view 拖動時觸發事件,根據當前的座標轉化爲經緯度,調用谷歌地圖setCenter方法同步地圖位置
  view.on('change:center', function () {
    var center = view.getCenter();
    gmap.setCenter(new google.maps.LatLng(center[1], center[0])); // 注意順序
  });

  // 同上,更改焦距時觸發的時間
  view.on('change:resolution', function () {
    gmap.setZoom(view.getZoom());
  });

  // ol.source.Vector 做爲 ol.layer.Vector的數據集,增刪改feature的方法由source提供
  var vectorSource = new ol.source.Vector();

  var vector = new ol.layer.Vector({
    source: vectorSource
  });

  var olMapDiv = document.getElementById('olmap');
  var map = new ol.Map({
    layers: [vector], // 所使用的圖層
    // 禁用掉默認的拖動、旋轉等交互
    interactions: ol.interaction.defaults({
      altShiftDragRotate: false,
      dragPan: false,
      rotate: false
    }).extend([new ol.interaction.DragPan({kinetic: null})]),
    target: olMapDiv,
    view: view  // 這裏可使用 new ol.View({options}) 可是在這裏須要經過手動設置來觸發google maps調節到正確地zoom與center
  });
  view.setCenter([10.689697265625, -25.0927734375]); // 若是未設置view的座標標準,這裏千萬要注意不要直接寫經緯度
  view.setZoom(6);  // 設置縮放等級
  
  // 將openlayers容器放置到google地圖容器中
  olMapDiv.parentNode.removeChild(olMapDiv);
  gmap.controls[google.maps.ControlPosition.TOP_LEFT].push(olMapDiv);
</script>


</body>
</html>

有了這段代碼應該就有了一個能夠拖動縮放的地圖了。數組

添加feature

固然光有一個地圖是不行的,若是須要往地圖上面添加feature怎麼辦呢?大體有如下兩種場景:

  1. 提供整個地圖的信息描述數據,好比geoJson,WKT或者自定義的數據結構等,須要解析整個數據並批量顯示在地圖上。
  2. 拿到某個feature的座標數據,須要添加到地圖上,並實現特異化的控制。

批量添加數據

先上代碼

javascript/**
   * 將geoJson字符串解析後添加到地圖中
   * @param vectorSource {ol.source.Vector} 須要添加feature的矢量層數據對象
   * @param data {string} geoJson字符串
   */
  function addFeatures(vectorSource, data){
 vectorSource.addFeatures(ol.format.GeoJSON.readFeatures(data, {
      // 數據的座標code
      dataProjection: 'EPSG:3857',
      // 地圖view使用的座標code
      featureProjection: 'EPSG:4326'
    }));
  }

ol.format下有不少種數據類型,選擇匹配的數據格式。
好比WKT使用ol.format.WKT.readFeature

readFeature返回的是ol.Feature的數組,能夠經過遍歷其來得到feature對象,從而按需求修改或者掛載監聽事件。

添加單個feature

若是現有的數據是geoJson等標準格式的數據,能夠經過ol.format中的類進行轉換。若是有需求則使用ol.proj.transform進行座標系轉換。

// 返回單個feature對象
var feature = ol.format.GeoJSON.readFeature(data)

// 添加到source
vectorSource.addFeature(feature);

若是拿到的是經緯度信息,添加一個polygon

// data 是一個coordinates的二維數組 須要注意
var feature = new ol.feature(new ol.geom.Polygon(data));

修改feature

介紹如何修改feature以及掛載監聽事件。

初始化修改添加、修改交互

// 聲明選擇交互
 var select = new ol.interaction.Select({
      // 根據 feature editable 選項來判斷是否能夠選中
      filter: function(feature) {
        if (_this._featureMap[feature.getId()].editable) {
          return true;
        }
      }
    });

// 獲得被選中元件的對象
var selected = select.getFeatures();

// 聲明修改交互,能夠修改被選中的feature
var modify = new ol.interaction.Modify({
  features: selected
});

// 當新元件被選中時觸發
selected.on('add', event => {
  var feature = event.element
})

// 當元件被取消選中時觸發,通常把元件的修改回調放在這
    selected.on('remove', evt => {
      var feature = evt.element;
      var fid = feature.getId();
      // 判斷元件是否被修改仍是須要feature的change事件
      console.log(fid);
    });

// 在interactions中添加
this._map = new ol.Map({
      layers: [vector],
      interactions: ol.interaction.defaults({
        altShiftDragRotate: false,
        dragPan: false,
        rotate: false
      }).extend([new ol.interaction.DragPan({kinetic: null}), select, modify]),
      target: $olMapDiv,
      view: this._view
    });

通常來講若是須要後續對feature進行操做,可使用getId方法拿到featureid,能夠經過setId來設置本身想要的id,不然會自動生成。 將id存在常駐的對象中供之後使用。

假設拿到ol.Feature對象 feature

feature.on('change:geometry', function(e){
  var feature = e.element;
  // do what you want  好比標記元件已被修改
})

須要注意的是這個onChange事件在修改的過程當中會不斷地觸發,若是須要的是修改完成以後的回調,須要使用selectremove事件。

select.getFeatures().on('remove', function(e){})

修改feature對象

設置id

feature.setId(id)

獲得geometry對象

var geometry = feature.getGeometry();
// 經過調用geometry類的方法修改元件座標

feature to string

var format = new ol.format.GeoJSON();
format.writeFeature(feature);

須要注意的地方

  • openlayers默認的座標系是'EPSG:3857',標準經緯度座標系是'EPSG:4326'
  • 看openlayer文檔最重要的技巧是注意類型
  • geometry接受的coordinates實際上是一個三維數組,必定要注意

經常使用操做

座標系轉換

根據當前座標系與目標座標系進行轉換。

ol.proj.transform(coordinate, source, destination)
coordinate 在文檔中得類型是 Coordinate其實就是一個有橫縱座標組成的數組,所以必定要注意官方文檔中得數據類型。
source 當前座標編碼 string類型
destination 目標座標編碼 string類型

從經緯度轉化到指定座標系

ol.proj.fromLonLat(coordinate, opt_projection)
opt_projection 目標座標編碼 string類型

從某座標轉經緯度

ol.proj.toLonLat(coordinate, opt_projection)

數據格式化

ol.format

相關文章
相關標籤/搜索