openLayers 3知識回顧

熱愛前端的17號誒發表於2018-12-25

openlayers 知識


前段時間幫助同事重構一個地圖類的專案,然後就學習了openLayer3這個框架,但是官網上沒有中文版,也沒有詳細的例子解釋,我只能遇到看不懂的就翻譯成中文來用,為了方便以後再用這個ol,能夠更快的上手,就花了幾天的時間總結了ol的知識,ol功能很豐富,API也很多,沒有寫太多,只是寫了怎麼用的,只要學會了根本,就可以很快的使用API去操作map。

另外,在總結知識的同時,還寫了demo,加深自己的理解,大家覺得不錯的話,給個star~ GitHub

那麼開始吧!

目錄

var map = new ol.Map({
    target:`map`,
    layers:[],
    view:views,
    interactions:interactions,
    controls:controls,
})

map是openlayers的核心元件,所有的操作方法以及渲染都是掛載到map上面。建立的map物件需要傳一個物件進去,最常見的就有以下幾個屬性,

* target --> 地圖的掛載元素,就是在html元素裡宣告的id
* layers --> 層,是個陣列,可以放很多層,如果未定義,則將呈現沒有圖層的地圖,圖層是按照提供的順序渲染的,因此,如果您希望(例如)向量圖層顯示在圖塊圖層的頂部,則它必須位於圖塊圖層之後。
* view  --> map的檢視,
* interactions --> 互動,比如滑鼠事件導致放大,縮小,旋轉之類的,預設都是true
* controls --> 控制元件,類似與按鈕,有放大,縮小,全屏等的按鈕 

最簡單的顯示地圖:

document.body.innerHTML = `<div id="map" style="height:400px;width:100%"></div>`;

var map = new ol.Map({
    target:`map`,
    layers:[new ol.layers.Tile({
        source: new ol.source.OSM()
    })],
    view: new ol.View({
        center:[0,0],
        projection: `EPSG:4326`,
        zoom:10,
    }),
    interactions: ol.interaction.defaults({
        doubleClickZoom:false,
        altShiftDragRotate:false
    }),
    controls: ol.control.defaults({
        attribution: false,
    })
})

map

這個map不是裡面的Map,而是初始化後的map,map = new ol.Map();在openlayers3 的API中,有很多方法,可以通過方法去操作layers,view,interactions,controls。
列印map,可以發現map裡面有很多屬性,可以簡單知道map上有多少個層,target是誰,size是多少等等,也可以通過API方法去獲取

var target = map.getTarget();    // 獲取 target的值  -- map
var size = map.getSize();  // 獲取可視區域的寬高。

同樣的,也可以在map上設定

map.addControl(new ol.control.FullScreen()); // 新增全屏控制元件
map.addLayers( new ol.layer.Vector({
    source:new ol.Source.Vector()
}))  // 新增一個向量圖層

*map裡有一個函式方法,可以通過點選某個圖層或某個點而獲取到當前的層和資訊。
forEachFeatureAtPixel(pixel, callback, opt_options)
params: pixel:座標
callback:回撥函式,將使用兩個引數呼叫回撥,第一個是feature,第二個是layers
opt_options:可選

map.on(`click`,function(e){
    var feature = map.forEachFeatureAtPixel(e.pixel,function(f){
        return f;
    })
    console.log(feature);   // ol.Feature
})

view

檢視.View物件表示地圖的簡單2D檢視。這是用於更改地圖的中心,解析度和旋轉的物件。
一個檢視是由三種狀態確定:center,resolution,zoom和rotation。每個狀態具有相應的獲取和設定。

  • center:初始座標,比如:成都的位置 [104.06, 30.67],這樣地圖初始化會以成都為中心展開(projection:`EPSG:4326`)。
  • projection:一個檢視有一個projection。投影確定中心的座標系,其單位確定解析度的單位(每畫素的投影單位)。
    projection有兩種值,預設投影是球形墨卡託(EPSG:3857),是地圖的xy座標,另一種就是經緯度座標,(EPSG:4326)是WGS84的一種。
    通過一個方法可以進行EPSG:3857與EPSG:4326轉化。
    經緯度轉至xy(EPSG:4326->EPSG:3857)
    ol.proj.transform(coordinates,`EPSG:4326`,`EPSG:3857`)
    xy轉至經緯度(EPSG:3857->EPSG:4326)
    ol.proj.transform(coordinates,`EPSF:3857`,`EPSG:4326`)
  • zoom:計算檢視初始解析度的縮放級別。至於resolution初始解析度,在其未宣告時,zoom起作用。對應的它也有maxZoom,minZoom。
  • rotation:初始旋轉度,預設是0,(順時針正向旋轉,0表示北向),弧度制
var view = new ol.View({
    center:[104.06,30.67],
    projection:`EPSG:4326`,
    // center: ol.proj.transform([104.06,30,67],`EPSG:4326`,`EPSG:3857`);    // 這個和上面的結合體。
    zoom:10,
    rotation:Math.PI/10,
})

檢視對應的也有get和set系列的方法,用於獲取和設定zoom,center,rotation等等,除此之外,還有約束方法,constrainRotation(),約束旋轉度,API上有詳細解釋。

map.getView()   // 就是當前檢視,view
view.getZoom()  // 獲取縮放級別;
view.getCenter() // 獲取初始中心座標
view.setCenter([20,30])  // 設定初始中心[20,30],也可以用ol.proj.transform
view.constrainRotation(2,5) // 獲取此檢視的約束旋轉

layers

層,是一個物件陣列,將那些與資料顯示方式相關的屬性組合在一起,形成一個層,openlayer就是由一個一個的層形成的,包括地圖,瓦片地圖,圖片,圖形都是由layer形成而呈現在map上的
簡單的來說,layer可以是一個地圖,也可以是一個圖形,也可以是個圖片,因為是個陣列,可以互相疊加的,[map,image,shape],在相同位置的情況下,後者會覆蓋前者。

layer

根據這個圖片可知,layers有三種形式

  • ol.layer.Tile 瓦片,瓦片地圖源於一種大地圖解決方案,針對一整塊非常大的地圖進行切片,分成很多相同大小的小塊地圖,在使用者訪問的時候,再一塊一塊小地圖載入,拼接在一起,從而還原成一整塊大的地圖。這樣做的優點在於,使用者在同一時間,同一個可見檢視內,只能看到地圖的一部分,而不是全部。提高使用者體驗。通常用這個作為底圖。
  • ol.layer.Image 對應的是一整張圖,而不像瓦片那樣很多張圖,從而無需切片,也可以載入一些地圖,適用於一些小場景地圖
  • ol.layer.Vector 向量,使用直線和曲線來描述圖形,這些圖形的元素是一些點、線、矩形、多邊形、圓和弧線等等,它們都是通過數學公式計算獲得的。由於向量圖形可通過公式計算獲得,所以向量圖形檔案體積一般較小。向量圖形最大的優點是無論放大、縮小或旋轉等不會失真。

每個形式都需要一個source,資料來源,所以每一個形式都對應一個資料來源,Source和Layer是一對一的關係,有一個Source,必然需要一個Layer,然後把這個Layer新增到Map上,就可以顯示出來了。

ol.layer.Tile

對於瓦片資料來源,也有很多屬性,

  • opacity,改變透明度,預設是1
  • visible,可視,預設是true
  • zIndex,圖層渲染的z-index。在渲染時,將按照Z-index然後按位置對圖層進行排序
  • source 有很多形式,
  • 線上服務的Source
    • ol.source.OSM
    • ol.source.BingMaps
    • ol.source.TileImage
  • 支援協議標準的Source,包括ol.source.TileArcGISRest,ol.source.TileWMS,ol.source.WMTS,ol.source.UTFGrid,ol.source.TileJSON。如果要使用它們,首先你得先學習對應的協議,之後必須找到支援這些協議的伺服器來提供資料來源,這些伺服器可以是地圖服務提供商提供的,也可以是自己搭建的伺服器,關鍵是得支援這些協議。
  • ol.source.XYZ,而且現在很多地圖服務(線上的,或者自己搭建的伺服器)都支援xyz方式的請求。國內線上的地圖服務,高德,天地圖等,都可以通過這種方式載入的
var OSMtile = new ol.layer.Tile({ 
    source:new ol.source.OSM()  
})
var qqTile = new ol.layer.Tile({
    source: new ol.source.XYZ({
        url: `http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}`
    }),
})
map.addLayer(OSMtile);  // 新增open street Map作為底圖
map.addLayer(qqTile)  // 新增騰訊地圖

map.addLayer()這個方法就相當於初始化中的layers的陣列中新增一樣,如下程式碼,這倆是等價的,只不過後者更靈活些。

var map = new ol.Map({
    layers:[OSMtile,qqTile]
})  // 等價於下面
map.addLayer(OSMtile); 
map.addLayer(qqTile)

ps!當新增地圖作為底圖時,會發現騰訊底圖覆蓋率OSM地圖,是因為layer是一個陣列,遵遁先來先渲染,後來居上的原則。
layer也有get/set方法,用來設定或獲取屬性,其實通過API就可以知道響應方法去操作。

ol.layer.Image

關於靜態圖片層,運用的不多,一般作為寫死的,不經常換的例項中。
同樣,ol.layer.Image也有資料來源,一般就是ol.source.ImageStatic,ol.source.ImageCanvas等等。

var center = ol.proj.transform([104.06667, 30.66667], `EPSG:4326`, `EPSG:3857`);
// 計算靜態圖對映到地圖上的範圍,圖片畫素為 550*344,保持比例的情況下,把解析度放大一些
var extent = [center[0]- 550*1000/2, center[1]-344*1000/2, center[0]+550*1000/2, center[1]+344*1000/2];
var imageStatic = new ol.layer.Image({
    source: new ol.source.ImageStatic({
        url: `../pandaBase.jpg`, // 靜態圖
        imageExtent: extent     // 對映到地圖的範圍
    })
})
map.addLayer(imageStatic);
ol.layer.Vector
向量圖層,是用來渲染向量資料的圖層型別,在OpenLayers裡,它是可以定製的,可以控制它的透明度,顏色,以及載入在上面的要素形狀等。常用於從資料庫中請求資料,接受資料,並將接收的資料解析成圖層上的資訊。比如將滑鼠移動到中國,相應的區域會以紅色高亮顯示出來,高亮便是向量圖層的行為

既然是個向量圖,可以改變大小,顏色,以及形狀。包含source資料來源類,style類設定樣式,以及其他的zIndex,opacity等等。
Feature類是Vector類用來在地圖上展示幾何物件,是Vector圖層類一個屬性。這個屬性是個*要素陣列*。

source

對應的資料來源ol.source.Vector也是個物件。最常見屬性的是featuresformat以及url。通常url和format一塊,url按理傳來的是geojson格式的向量圖,需要format格式化一下。最常用還是features。
ol.Feature

  • feature 具有幾何和其他屬性屬性的地理要素的向量物件,類似於GeoJSON等向量檔案格式中的要素。
  • Geometry類是feature物件的基本組成部分,Vector類採用Geometry類來儲存一個要素的幾何資訊.通過feature名.getGeometry()獲取
  • feature類有兩個部分,Geometry物件和attributes屬性,attributes包含要素相關的資料。比如:{type:`circle`},通過getProperties().attributes去獲取。
    geometry
  • new ol.geom.Point([x1,y1]) 點
  • new ol.geom.LineString([[x1,y1],[x2,y2]]) 線
  • new ol.geom.LinearRing()
  • new ol.geom.MultiLineString([[[x1,y1],[x2,y2]],[[x3,y3],[x4,y4]],[…]]) 多條線
  • new ol.geom.MultiPoint([[x1,y1],[x2,y2],[…]]) 多個點
  • new ol.geom.Polygon([[[x1,y1],[x2,y2],[x3,y3],[x4,y4],[…],[x1,y1]]]) 幾何
    如果這些座標是經緯度座標的話,都需要座標轉換applyTransform(ol.proj.getTransform(`EPSG:4326`, `EPSG:3857`)),(部分圖形展示請看demo)
var polygon = new ol.geom.Polygon([[[110, 39], [116, 39], [116, 33], [110, 33], [110, 39]]]);
polygon.applyTransform(ol.proj.getTransform(`EPSG:4326`, `EPSG:3857`)); // 座標轉換
var square = new ol.Feature({
    geometry:polygon
})
layer.getSource().addFeature(square)
style
一個style物件,包含Style類,有7個屬性:
  • geometry 返回要為此樣式渲染的幾何的要素屬性或幾何或函式
  • fill 填充樣式。
  • image 影像樣式
    • icon : new ol.style.Icon()
      • anchor :[0.5,0.5]錨點,
      • color
      • src :圖示源
    • circle: new ol.style.Circle()
      • fill :new ol.style.Fill()
      • radius : 半徑
      • stroke :new ol.style.Stroke()
    • regularShape :new ol.style.RegularShape()
      • fill :new ol.style.Fill()
      • points : 點數,幾個點
      • radius : 半徑
      • radius1 : 外半徑
      • radius2 : 內半徑
      • angle 0 形狀的角度以弧度表示。值為0將使其中一個形狀的點朝上。
      • stroke :new ol.style.Stroke()
      • rotation : 0 旋轉度
  • renderer 自定義渲染器。配置時fill,stroke和image將被忽略,並且將為每個幾何體的每個渲染幀呼叫提供的函式。
  • stroke 邊線樣式
    • color 顏色
    • lineCap :butt, round, square 線帽
    • lineJoin :bevel, round, miter. 線條連線形狀
    • width 寬度
  • text 文字樣式
    • font :`10px sans-serif`
    • text
    • textAlign left`,`right`,`center`,`end` start`
    • fill :new ol.style.Fill()
    • stroke :new ol.style.Stroke()
    • backgroundFill
    • padding
  • zIndex 層級
    // set*()在重新呈現使用該樣式的要素或圖層之前,通過方法對樣式或其子項所做的任何更改都不會生效
// 最簡單的呈現方式,複雜的請參考demo
var layer = new ol.layer.Vector({
    source: new ol.source.Vector({
        features:[new ol.Feature({
            geometry: new ol.geom.Point(ol.proj.transform([104, 30], `EPSG:4326`, `EPSG:3857`)),
        })]
    }),
    style: new ol.style.Style({
        image: new ol.style.Circle({
            radius: 30,
            fill: new ol.style.Fill({
                color: `red`
            })
        })
    }),
    opacity:0.5
})
map.addLayer(layer)

一個層layer有一個featrue,也可以有多個feature,因為Feature類是Vector類用來在地圖上展示幾何物件,是Vector圖層類一個屬性。這個屬性是個*要素陣列*。
對於style樣式問題,feature的style的層級比layer.Vector的層級要高,所以feature的style會覆蓋layer的style。
ps:feature中的樣式不能以屬性名的形式寫,因為feature類中沒有style屬性名,只有geometry,所以要以方法的形式去新增,setStyle()。

其實關於layer,vector,API上都有其方法,包括set/get,雖然類有很多子類,子類又有很多子子類,也無妨,只要抓住想要操作的是哪一個部分就行,是feature,還是layer,還是geometry等等。

styleFunction
feature中可以使用styleFunction來設定自己隨心所欲的樣式,通過官網API文件可以看到,其型別為ol.FeatureStyleFunction,函式僅帶有一個引數resolution,在函式體內this指的是當前的feature,根據文件說明,這個函式要返回一個style陣列。
除了feature可以設定樣式之外,layer也是可以設定樣式的,同樣地也支援styleFunction,但是需要注意的是,其定義和feature的不一樣,型別為ol.style.StyleFunction,該函式具有兩個引數,第一個引數為feature,第二個引數為resolution,同樣地,該函式需要返回style陣列。

var layer = new ol.layer.Vector({
    source: new ol.source.Vector()
})
var map = new ol.Map({
    layers: [
        new ol.layer.Tile({
        source: new ol.source.OSM()
        }), 
        layer
    ],
    target: `map`,
    view: new ol.View({
        projection: `EPSG:4326`,
        center: [104, 30],
        zoom: 10
    })
});

var anchor = new ol.Feature({
    geometry: new ol.geom.Point([104, 30])
});
// 應用style function,動態的獲取樣式
anchor.setStyle(function(resolution){
    return [new ol.style.Style({
        image: new ol.style.Icon({
        src: `../img/anchor.png`,
        scale: map.getView().getZoom() / 10
        })
    })];
});

layer.getSource().addFeature(anchor);

controls

地圖控制元件,包括縮放按鈕,標尺,版權說明,指北針等等,不會隨著地圖的放大而放大,縮小而縮小,就相當於position:fixed一樣,固定在某個地方。 在實現上,並不是在畫布上繪製的,而是使用傳統的HTML元素來實現的,便於同地圖分離,也便於介面實現。
在openlayers 3 中,預設情況下,在地圖上是不會顯示這麼多地圖控制元件的,只會應用ol.control.defaults()這個函式返回的地圖控制元件,預設包含了ol.control.Zoom,ol.control.Rotate和ol.control.Attribution這個控制元件。
OpenLayers 3目前內建的地圖控制元件類都在包ol.control下面:

  • ol.control.Attribution: 右下角的地圖資訊控制元件
  • ol.control.FullScreen: 全屏控制元件
  • ol.control.MousePosition: 滑鼠位置控制元件
  • ol.control.OverviewMap: 鳥瞰圖控制元件
  • ol.control.Rotate: 指北針控制元件
  • ol.control.ScaleLine: 比例尺控制元件
  • ol.control.Zoom: 縮放按鈕控制元件
  • ol.control.ZoomSlider: 縮放滾動條控制元件
  • ol.control.ZoomToExtent: 放大到設定區域控制元件
var map = new ol.Map({
    target:`map`,
    layers:[new ol.layers.Tile({
        source: new ol.source.OSM()
    })],
    view: new ol.View({
        center:[0,0],
        projection: `EPSG:4326`,
        zoom:10,
    })
    controls: ol.control.defaults({
        attribution: false, // 資訊false
        rotate: false,    // 旋轉false
        zoom: false      //   縮放false
    })
})

map.getControls()是獲取控制元件的資訊,
如果想要新增其他的控制元件,可以使用map中的一個方法,map.addControl()

map.addControl(ol.control.OverviewMap)  // 新增鳥瞰圖控制元件

控制元件不是在畫布上繪製的,而是用html實現的,所以樣式問題可以按照css+html的形式去修改。

interactions

互動,就是人與機之間的互動模式,比如用滑鼠左鍵雙擊地圖可以放大地圖,按住滑鼠左鍵拖動地圖可以移動瀏覽地圖,用滾動滑鼠中間的滑輪可以放大縮小地圖等等。這些都是openLayers內建的,其實也可以自己去interact。

內建的互動

內建的互動在map中都是預設的。

var map = new ol.Map({
    interactions: ol.interaction.defaults().extends()
    // .... 其餘程式碼
})

ol.interaction.defaults()預設包含以下互動:

  • 滑鼠
    • 按住alt+shift鍵,用滑鼠左鍵拖動地圖,就能讓地圖旋轉,對應的互動類為ol.interaction.DragRotate。
    • 用滑鼠左鍵雙擊地圖,就可以放大地圖,對應的互動類為ol.interaction.DoubleClickZoom。
    • 用滑鼠左鍵,拖拽地圖,就可以平移地圖,對應的互動類為ol.interaction.DragPan。
    • 滾動滑鼠中間的滑輪,就可以縮放地圖,對應的互動類為ol.interaction.MouseWheelZoom。
    • 按住shift鍵,同時用滑鼠左鍵在地圖上拖動,就可以放大地圖,對應的互動類為ol.interaction.DragZoom。
  • 觸控式螢幕
    • 在觸控式螢幕上,用兩個手指在觸控式螢幕上旋轉,就可以旋轉地圖,對應的互動類為ol.interaction.PinchRotate。
    • 在觸控式螢幕上,用兩個手指在觸控式螢幕上縮放,就可以縮放地圖,對應的互動類為ol.interaction.PinchZoom。
  • 鍵盤(注意:需要設定tabindex,才能使div獲得鍵盤事件,就是在宣告id的那個div中新增:tabindex=”0″)
    • 用鍵盤上的上下左右鍵,就可以平移地圖,對應的互動類為ol.interaction.KeyboardPan。
    • 用鍵盤上的+/-鍵,就可以縮放地圖,對應的互動類為ol.interaction.KeyboardZoom。

如果想要取消某個互動事件

var map = new ol.Map({
    interactions: ol.interaction.defaults({
        mouseWheelZoom: false, // 取消滾動滑鼠中間的滑輪互動
        shiftDragZoom: false, // 取消shift+wheel左鍵拖動互動
    })
    // .... 其餘程式碼
})

extend()為擴充套件

var map = new ol.Map({
    interactions: ol.interaction.defaults().extend()
    // .... 其餘程式碼
})

map.getInteraction()是獲取控制元件的資訊,
如果想要新增其他的互動,可以使用map中的一個方法,map.addInteraction()

map.addInteraction(new ol.interaction.MouseWheelZoom); 

關於new Interaction(),總共有7個子類,可以用在extend([])中,也可以用addInteraction()

  • DoubleClickZoom interaction,雙擊放大互動功能;
  • DragAndDrop interaction,以“拖檔案到地圖中”的互動新增圖層;
  • DragBox interaction,拉框,用於劃定一個矩形範圍,例子常用於放大地圖;
  • DragPan interaction,拖拽平移地圖;
  • DragRotateAndZoom interaction,拖拽方式進行縮放和旋轉地圖;
  • DragRotate interaction,拖拽方式旋轉地圖;
  • DragZoom interaction,拖拽方式縮放地圖;
  • Draw interaction,繪製地理要素功能;
  • KeyboardPan interaction,鍵盤方式平移地圖;
  • KeyboardZoom interaction,鍵盤方式縮放地圖;
  • Select interaction,選擇要素功能;
  • Modify interaction,更改要素;
  • MouseWheelZoom interaction,滑鼠滾輪縮放功能;
  • PinchRotate interaction,手指旋轉地圖,針對觸控式螢幕;
  • PinchRoom interaction,手指進行縮放,針對觸控式螢幕;
  • Pointer interaction,滑鼠的使用者自定義事件基類;
  • Snap interaction,滑鼠捕捉,當滑鼠距離某個要素一定距離之內,自動吸附到要素。

這些子類都可以查API,有詳細解釋。這些子類中,有個常用的屬性condition或方法handleEvent(mapBrowserEvent)

condition

代表的是事件名稱,比如:click,doubleClick,主要是依據ol.events。主要有以下幾種,預設是singleClick

  • altKeyOnly 僅按下alt鍵則返回true
  • shiftKeyOnly 僅按下shift鍵則返回true
  • altShiftKeysOnly 僅按下alt鍵+shift則返回true
  • always
  • never
  • click,只要是點選,包括singleClick,doubleClick都返回true
  • doubleClick
  • singleClick
  • focus 如果地圖具有焦點,則返回true。此條件需要具有tabindex屬性的地圖目標元素,例如
  • mouseOnly 從滑鼠裝置發起為true
  • noModifierKeys 沒有組合鍵則返回true
  • pointerMove 指標移動時返回true
  • targetNotEditable 如果目標元素不可編輯,則返回true,即不是input,select或textarea元素false。
  • platformModifierKeyOnly
  • primaryAction 從一個主指標在與表面接觸或起源如果按下滑鼠左鍵

handleEvent(mapBrowserEvent)

function (mapBrowserEvent){
    return ol.events.condition.click(mapBrowserEvent) && ol.events.condition.shiftKeyOnly(mapBrowserEvent);
}
Select

是個選擇圖形的類,用於互動.
new ol.interaction.Select(options)
options是個物件引數,包括:

  • style
  • layers 應從中選擇要素的圖層列表。或者,可以提供過濾功能。將為地圖中的每個圖層呼叫該函式,並應返回true您想要選擇的圖層。如果該選項不存在,則所有可見圖層都將被視為可選擇。
  • condition 型別為 ol.events.ConditionType,規定了什麼情況下觸發 select 操作,預設不需要特殊條件進行觸發。
  • addCondition
  • removeCondition
  • toggleCondition 獲取module:ol/MapBrowserEvent-MapBrowserEvent和返回布林值的函式,以指示是否應該處理該事件。這是condition事件的補充。預設情況下, module:ol/events/condition-shiftKeyOnly即按下shift以及condition事件,如果當前未選中,則將該功能新增到當前選擇,如果是,則將其刪除。見add而remove 如果你想使用的,而不是一個觸發不同的事件。
  • multi 用於確定預設行為是否應僅在單擊的地圖位置選擇單個feature或所有(重疊)feature。預設值false表示單選。
  • features
  • filter 過濾 見demo
  • wrapX 當地圖水平顯示多個相同位置時,是否顯示多個勾繪任務,預設為 false
    select點選事件
selectSingleClick.on(`select`, function (event) {
    console.log(event)
})

該select也有set/get方法,用來獲取或者設定屬性,比如獲取選中的features,獲取所有屬性名稱和值的物件getProperties。

Draw

是個繪製圖形的類,預設支援繪製的圖形型別包含 Point(點)、LineString(線)、Polygon(面)和Circle(圓)。觸發的事件包含 drawstart和drawend,分別在勾繪開始時候(單擊滑鼠)和結束時候觸發(雙擊滑鼠)。
new ol.interaction.Draw(options)
options是個物件引數,包括:

  • type: 幾何型別(加粗為預設)
    • Point
    • LineString
    • LinearRing
    • Polygon
    • MultiPoint
    • MultiLineString
    • MultiPolygon
    • GeometryCollection
    • Circle
  • source 資料來源,如果想要儲存繪製的圖形,需要有一個載體來儲存繪製的圖形,比如新建一個layer,這個layer的source就是該繪製的source。
    •   var drawLayer = new ol.layer.Vector({
            source:new ol.source.Vector()
        }) // 新建一個層
        map.addLayer(drawLayer)
        var draw = new ol.interaction.Draw({
            source: drawLayer.getSource(), // 資料來源就是新建層的資料來源
            type: `Point`,
        })
        map.addInteraction(draw);
  • style
  • stopClick
  • condition 型別為 ol.events.ConditionType,規定了什麼情況下觸發 draw 操作,預設不需要特殊條件進行觸發。
  • clickTolerance: 數值型別,單位是畫素,判斷使用者滑鼠(PC)或者手指(移動裝置)的行為是新增點,還是按住滑鼠或者手指不鬆開進行拖拽地圖,預設值是 6 畫素,也就是說當按下滑鼠和抬起滑鼠左鍵之間的這段時間段內,如果地圖被拖動沒有超過 6 畫素,那麼預設為新增一個點,相反如果超過了 6 畫素,那麼不會新增點,只是平移一下地圖。
  • snapTolerance 數值,畫素為單位,預設值是 12 畫素,當一定位置內最後一個點吸附到第一個點,對多邊形時有用
  • features
  • maxPoints 表示繪製單個要素(面和線)最多的點數限制,預設沒有限制
  • minPoints 表示繪製單個要素(面和線)需要的最少點數,面預設為 3,線預設為 2
  • geometryName 字串型別,繪製的 geometry 的名稱。
  • geometryFunction 因為預設type只有四種:Point(點)、LineString(線)、Polygon(面)和Circle(圓),此方法就是可以用來繪製規則或者自己想要繪製的圖形的方法,該函式有兩個引數,一個是座標集合、一個是勾繪的 geometry 型別,返回構造好的 geometry 物件,用來初始化要素。
    •   var draw = new ol.interaction.Draw({ // 繪製矩形
            type: `LineString`,
            maxPoints: 2,
            geometryFunction: function(coordinates, geometry){
                if(!geometry){
                    geometry = new ol.geom.Polygon(null);
                }
                var start = coordinates[0];
                var end = coordinates[1];
                geometry.setCoordinates([
                    [start, [start[0], end[1]], end, [end[0], start[1]], start]
                ]);
                return geometry;
            }
            // 其餘程式碼塊
        })
    • 上面的例子用LineString的形式去繪製矩形,這裡的原理就是捕捉滑鼠點選的點,然後獲取限制的兩個點的座標,用來初始化一個矩形框。
  • wrapX 當地圖水平顯示多個相同位置時,是否顯示多個勾繪任務,預設為 false
  • freehand 預設是false,是否以曲線的形式,不是規範化的,看demo-freehandDraw.html
  • freehandCondition 型別同condition,也是 ol.events.ConditionType,這個選項規定了什麼情況下觸發不用重複點選繪製模式,即拖拽滑鼠就可以繪製圖形的模式,預設情況下是按下 shift 按鍵,這種模式對於不容易繪製的曲線比較方便,而且釋放 shift 情況下,如果沒有完成繪製,可以繼續使用點選繪製。(就是需要輔助鍵,例如shift,ctrl時,會以曲線形式繪畫)–demo-secondDraw.html,按shift繪畫可以發現。
    drawstart/drawend
// 繪製結束時進行回撥
draw.addEventListener(`drawend`, function (evt) {
    // 獲取繪製圖形的所有座標點(終止點是起始點)
    var feature = evt.feature
    var geometry = feature.getGeometry()
    var coordinate = geometry.getCoordinates()
    // console.log(coordinate)
    var lent = coordinate[0].length // 座標點個數
})
Modify

用於修改要素幾何的互動。要修改已新增到現有源的功能,請使用該source選項構建修改互動,如果要修改集合中的要素(例如,選擇互動使用的集合),請使用該features選項構建互動。必須使用source或features構建互動
預設情況下,互動將允許在alt 按下鍵時刪除頂點。要配置具有不同刪除條件的互動,請使用該deleteCondition選項。
new ol.interaction.Modify(options)
options是一個引數物件,如下:

  • condition
  • style
  • source
  • features
  • wrapX
  • insertVertexCondition 一個函式,它接受module:ol/MapBrowserEventMapBrowserEvent並返回一個布林值,以指示是否可以將新頂點新增到草圖要素中。預設是module:ol/events/condition-always。 同deletCondition
  • deleteCondition 獲取module:ol/MapBrowserEventMapBrowserEvent和返回布林值的函式,以指示是否應該處理該事件。預設情況下, module:ol/events/condition-singleClick與 module:ol/events/conditionaltKeyOnly在頂點缺失的結果。看demo-modifyDifficult.html(先選中後操作)
Snap

在修改或繪製向量要素時處理向量要素的捕捉。這些功能可以來自一個module:ol/source/Vector或module:ol/Collection-Collection 任何互動物件,允許使用者使用滑鼠與功能進行互動可以從捕捉中受益,只要它之前新增。

快照互動會修改地圖瀏覽器事件coordinate和pixel 屬性,以強制對其進行的任何互動進行快照。
new ol.interaction.Snap(options) 看API
options:

  • features 應提供此選項或來源。
  • edge 抓住邊緣。預設值時true
  • vertex 捕捉到頂點。預設值是true
  • source 捕捉此來源的功能。應提供此選項或功能

官方例子Snap Interaction

事件
簡單例子
var map = new ol.Map({
    layers: [
        new ol.layer.Tile({
        source: new ol.source.OSM()
        })
    ],
    target: `map`,
    view: new ol.View({
        center: ol.proj.transform(
            [104, 30], `EPSG:4326`, `EPSG:3857`),
        zoom: 10
    })
});

// 監聽singleclick事件
map.on(`singleclick`, function(event){
    // 通過getEventCoordinate方法獲取地理位置,再轉換為wgs84座標,並彈出對話方塊顯示
    alert(ol.proj.transform(map.getEventCoordinate(event), `EPSG:3857`, `EPSG:4326`));
})

任意的事件應用,必然會有三個步驟:

  • 找準事件傳送者,比如上面這個例子,map就是事件傳送者。 如何找到它呢? 一般都是要互動的物件。
  • 找準事件名稱,比如上面例子中的singleclick,切忌不要隨便想象,或者按照慣例來寫名稱-condition,
  • 編寫事件響應函式,在OpenLayers中,事件傳送者都會有一個名字為on的函式,呼叫這個函式,就能監聽指定的事件,響應函式listener具有一個引數event,這個event類就對應於API文件中事件名稱後邊括號裡的類。
    forEachFeatureAtPixel(pixel, callback, opt_options)

    登出事件
  •   // 建立事件監聽器
      var singleclickListener = function(event){
          alert(`...`);
          // 在響應一次後,登出掉該監聽器
          map.un(`singleclick`, singleclickListener);
      };
      map.on(`singleclick`, singleclickListener);
  •   // 使用once函式,只會響應一次事件,之後自動登出事件監聽
      map.once(`singleclick`, function(event){
          alert(`...`);
      })
    自定義事件

    要新增自定義事件,需要知道這樣一個事實:ol.Feature繼承於ol.Object,而ol.Object具有派發事件(dispatchEvent)和監聽事件(on)的功能。

  • dispatchEvent(event) 分發一個事件,並呼叫偵聽此類事件的所有監聽器,event引數可以是字串,也可以是具有type屬性的Object
  • on(type, listener) 觸發type型別的監聽器。

// 為地圖註冊滑鼠移動事件的監聽
map.on(`pointermove`, function (event) {
    map.forEachFeatureAtPixel(event.pixel, function (feature) {
        // 為移動到的feature傳送自定義的mousemove訊息
        feature.dispatchEvent({ type: `mousemove`, event: event });
        // feature.dispatchEvent(`mousemove`);
    });
});

// 為feature1(之前建立的一個feature)註冊自定義事件mousemove的監聽
feature1.on(`mousemove`, function (event) {
    // 修改feature的樣式為半徑100畫素的園,用藍色填充
    this.setStyle(new ol.style.Style({
        image: new ol.style.Circle({
            radius: 100,
            fill: new ol.style.Fill({
                color: `blue`
            })
        })
    }));
});
dispatchEvent的引數具有type和event屬性,必須這樣構造嗎?在回答這個問題之前,需要先看一下API文件,發現引數型別為goog.events.EventLike,說明它其實用的是google的closure庫來實現的,通過closure庫的原始碼我們知道,派發的事件如果是一個物件,那麼必須包含type屬性,用於表示事件型別。其他的屬性可以自由定義,比如此處定義了event屬性,並設定對應的值,為的是讓滑鼠事件傳遞給feature1的監聽函式。dispatchEvent的引數會被原封不動的傳遞給事件響應函式,對應程式碼`feature1.on(`mousemove`, function(event){}`裡引數event,可以通過除錯視窗看到此處的event和dispatchEvent的引數是一樣的。注意事件名稱是可以自定義的,只要派發和監聽使用的事件名稱是一致的就可以。

除了可以通過dispatchEvent({type: `mousemove`, event: event})這種形式派發一個事件之外,還可以通過dispatchEvent(`mousemove`)這中形式直接傳送mousemove事件。

總結

openlayers功能很多,有的地方自己因時間有限還沒有深入瞭解,但是大部分是夠用了,有大部分都是參考資料的,因為講的很通透,所以就拿過來了。,對於openylayers3,一定多看看官方例子,例子有很多吸收的知識點,特別有用。有時間後會自己補上這一環節,大家如果有疑問或者我不對的地方請下方評論或私信。大家一起進步加油!

參考資料

openlayer3
OpenLayers 3 Primer

相關文章