1. 程式人生 > >OpenLayers 3 之 彈出框(popup)

OpenLayers 3 之 彈出框(popup)

摘要

         上回說到,載入完地圖後,我們想更多一點互動,而不僅僅是縮放和平移,賦予地圖多一點的生命 ~-~!點選地圖,它至少應該知道我是在哪裡點選了,並且彈出一個氣球類似的框框告訴我!這次,我們就來嘗試給我們的地圖加上這個能力!

         PS:這次的例子是基於上一篇的載入地圖的程式碼的哦!在上一篇的基礎上增刪修改,所以讀讀前一篇是很有必要的哦!

正文

        在OpenLayers2.x的那個年代 ~-~|,我們知道OpenLayers有一個類(Popup)是專門負責這項“彈出氣球”功能的。現在,到了3.x的時代,不同於OpenLayers 2.x,OpenLayers 3.x去除了Popup類,新增加了Overlay類,用於實現與Popup相同的彈出效果。在OpenLayers3.x的Overlay類定義中(定義

這裡找),Overlay的初始化屬性如下:

/**
* @enum {string}
*/
ol.OverlayProperty = {
  ELEMENT: 'element',
  MAP: 'map',
  OFFSET: 'offset',
  POSITION: 'position',
  POSITIONING: 'positioning'
};

其中,ELEMENT代表要轉換成overlay的HTML元素,可能是一個DIV標籤,MAP是要繫結的地圖物件,POSITION是點選時Popup放置的位置。

所以說為了產生彈出框的效果,那麼HTML檔案中要有相應的元素,那麼我們就定義一些元素:

<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>

這些元素的CSS樣式類,在下面的程式碼中,會貼出來,主要就是一些對popup的美化作用,可以不用太在意哈。

然後取得該元素container,並將獲得的元素傳入overlay物件:

var container = document.getElementById('popup');
var overlay = new ol.Overlay(/** @type {olx.OverlayOptions} */ ({
  element: container,
  autoPan: true,
  autoPanAnimation: {
    duration: 250   //當Popup超出地圖邊界時,為了Popup全部可見,地圖移動的速度. 
  }
}));

這樣,彈出的框框我們就準備好了。下一步需要為Map繫結點選事件,這樣,當我們點選地圖上的相應位置時,才會觸發彈出框框嘛!
/**
 * Add a click handler to the map to render the popup.
 */
map.addEventListener('click', function(evt) {
  var coordinate = evt.coordinate;
  var hdms = ol.coordinate.toStringHDMS(ol.proj.transform(
      coordinate, 'EPSG:3857', 'EPSG:4326'));
  content.innerHTML = '<p>你點選的座標是:</p><code>' + hdms + '</code>';
  overlay.setPosition(coordinate);
  map.addOverlay(overlay);
});

這裡為了最大程度相容各個瀏覽器,我們使用了DOM0級繫結事件的方式,event物件(evt)儲存著點選的點座標,在相應的位置顯示框框即可(overlay.setPosition()),最後,將popup加到地圖上。

OK!至此,我們可以測試一下了: DUANG! 是不是有“加特效”的感覺?~-~|

最後,附上完整程式碼

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">
    <style>
      .map {
        height: 400px;
        width: 100%;
      }
      .ol-popup {
        position: absolute;
        background-color: white;
        -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
        filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
        padding: 15px;
        border-radius: 10px;
        border: 1px solid #cccccc;
        bottom: 12px;
        left: -50px;
      }
      .ol-popup:after, .ol-popup:before {
        top: 100%;
        border: solid transparent;
        content: " ";
        height: 0;
        width: 0;
        position: absolute;
        pointer-events: none;
      }
      .ol-popup:after {
        border-top-color: white;
        border-width: 10px;
        left: 48px;
        margin-left: -10px;
      }
      .ol-popup:before {
        border-top-color: #cccccc;
        border-width: 11px;
        left: 48px;
        margin-left: -11px;
      }
      .ol-popup-closer {
        text-decoration: none;
        position: absolute;
        top: 2px;
        right: 8px;
      }
      .ol-popup-closer:after {
        content: "✖";
      }
    </style>
    <title>OpenLayers 3 example</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 type="text/javascript">
      map = new ol.Map({
        target: 'map',
        layers: [
          new ol.layer.Tile({
            source: new ol.source.MapQuest({layer: 'sat'})
          })
        ],
        view: new ol.View({
          center: ol.proj.transform([37.41, 8.82], 'EPSG:4326', 'EPSG:3857'),
          zoom: 4
        })
      });
    </script>
    <script src="popup.js" type="text/javascript"></script>
  </body>
</html>


JS檔案(popup.js)
/**
 * Elements that make up the popup.
 */
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');


/**
 * Add a click handler to hide the popup.
 * @return {boolean} Don't follow the href.
 */
closer.onclick = function() {
  overlay.setPosition(undefined);
  closer.blur();
  return false;
};


/**
 * Create an overlay to anchor the popup to the map.
 */
var overlay = new ol.Overlay(/** @type {olx.OverlayOptions} */ ({
  element: container,
  autoPan: true,
  autoPanAnimation: {
    duration: 250   //當Popup超出地圖邊界時,為了Popup全部可見,地圖移動的速度. 單位為毫秒(ms)
  }
}));


/**
 * Add a click handler to the map to render the popup.
 */
map.addEventListener('click', function(evt) {
  var coordinate = evt.coordinate;
  var hdms = ol.coordinate.toStringHDMS(ol.proj.transform(
      coordinate, 'EPSG:3857', 'EPSG:4326'));
  content.innerHTML = '<p>你點選的座標是:</p><code>' + hdms + '</code>';
  overlay.setPosition(coordinate);
  map.addOverlay(overlay);
});

        其中HTML頁中的那些CSS樣式“.ol-popup:before”是啥意思呢?.ol-popup我們知道,這是定義一個CSS的樣式類,在相應的元素中加上class=“ol-popup”就可以使用定義的樣式,後面的“:before”表示在相應的元素前面插入相應的樣式,“:after”與之同理,只不過是在元素後面插入相應的樣式。沒有看懂的可以在這裡找到說明。

還有還有,為什麼要把JS檔案引用那幾句放<body>元素的最後面呢?

<script src="http://openlayers.org/en/v3.3.0/build/ol.js" type="text/javascript"></script>
<script src="popup.js" type="text/javascript"></script>

        原因是這樣的:在文件的<head>元素中包含JavaScript檔案,意味著必須等到全部JavaScript都被下載、解析和執行完成以後,才能開始呈現頁面的內容(瀏覽器遇到<body>標籤,才開始呈現內容)。所以,對於需要很多JavaScript程式碼的頁面來說,肯定會導致瀏覽器呈現頁面時出現延遲,而延遲的時候,瀏覽器視窗將是一篇空白!

        當然,對於JavaScript檔案需要比較少的頁面可以寫在<head>中,影響並不大。但畢竟,養成好習慣還是好的哦!~-~

總結

        這次我們能夠知道我們點選的是哪裡了!通過簡單的座標比較,我們就知道我們點選的是哪個省,哪個市了。。。

        但是我們總不能就是為了在地圖上一通亂點,讓地圖告訴我座標吧!- -| 那也太LOW了!我們肯定是看到地圖上有什麼東西了,比較好奇,所以才去點哦。或者說,你搜索了什麼,地圖上加載出結果來,你去點,然後才彈出Popup效果。

        這便是我下一篇要說的:向量圖層,使用向量圖層載入來自資料庫的內容,並配合popup,呈現出更強的能力!