加入右鍵菜單,首先我們要監聽鼠標右鍵點擊的操作,我們知道鼠標右鍵事件名是 contextmenu。當鼠標在 html 元素之上,點擊鼠標右鍵,便會觸發 contextmenu 事件,在 contextmenu 事件的回調函數中實現對應的顯示菜單功能就可以。
那么在 openlayers 中。在地圖中加入這個事件,我們從哪里下手呢?首先我們得了解 openlayers 的初始化頁面的過程。
openlayers 初始化頁面過程
openlayers 也是一個前端庫,那么它肯定離不開 html 的運用,比方,我們首先須要在頁面放置一個顯示地圖的 html 元素,一個 div 元素(如果其 id 屬性設置為 “map”。后面簡稱為 map div),然后在地圖初始化的時候指定這個元素,openlayers 會首先在這個元素中創建一個 class 為 ol-viewport 的 div 元素,其尺寸保持與 map div 同樣,然后在 ol-viewport div 中創建一個 canvas 元素。在這個 canvas 元素中渲染請求到的地圖。其次。還會加入一個 class 為 ol-overlaycontainer 的 div 元素,用來放置 overlay。最后,加入一個 class 為 ol-overlaycontainer-stopevent 的 div 元素,主要是放置 openlayers 的控件,上一篇加入 自己定義擴展控件 的文章開篇有講過。這里不是重點。我們不詳細介紹了。
最后形成的 html dom 結構例如以下圖:
圖1 形成的DOM結構
我們會想到在這個 map div 元素加入事件。然后右鍵彈出菜單。這個想法非常自然,也確實能夠實現,然而我們要想到后面的事情。至少對事情有一個全局的認識再下手,我們顯示出菜單后。往往是要依據對應的地圖所在位置進行一定的操作,那么我們的 contextmenu 的事件對象包括發生點擊的屏幕坐標,可是怎樣依據屏幕坐標獲得地圖中的對應坐標系下的坐標將會比較困難。
困難在哪里呢?主要有以下的三點:
- 首先,事件對象所含的坐標是相對於整個瀏覽器的視口、頁面或者整個屏幕的。
- 其次。而顯示地圖的元素往往又是任意的大小和位置。
- 最后,屏幕的坐標系和地圖的坐標系又往往全然不同,怎樣將相對與地圖元素的坐標再轉化為地圖坐標系下的坐標?
首先。我們須要獲得事件坐標相對於 map div (包括地圖的元素)的坐標,然后將相對於 map div 的坐標轉化為地圖中的實際坐標。
第一步中,我們能夠通過計算獲得,可是第二步必須通過 openlayers 來完畢,由於僅僅有 openlayers 對地圖的坐標系最清楚。這在 openlayers 中也有相關的功能。慶幸的是。openlayers 中我們能夠一步完畢上述操作。僅僅須要一個函數:map.getEventCoordinate(event),在以下的詳細實現中,我會詳細說到這個函數。
以下我們看看詳細怎樣實現吧。
鼠標右鍵菜單詳細實現
- 為了方便,文章中的代碼使用了 JQuery。
- 文章中的實例完整代碼能夠到我的 GitHub 中查看或者下載。實用的話別忘了點一下 star。
以下我們一步一步地加入右鍵菜單功能,我們分為三步:
- 對 html 元素加入
contextmenu事件; - 獲取地圖對應的點擊坐標;
- 地圖對應位置加入菜單 。
對 html 元素加入 contextmenu 事件
html 元素的鼠標右鍵事件名為 contextmenu,這個事件全部主流瀏覽器都支持,這里不要混淆 html 新增的屬性 contextmenu,這個屬性眼下僅僅有 firefox 支持。我們僅僅是使用 oncontextmenu 這個事件。
對包括地圖的不論什么 html 元素綁定這個事件都能夠,openlayers 會處理坐標轉換這些問題。例如以下,map.getViewport() 會返回 openlayers 初始化頁面時創建的 class 為 ol-viewport 的 div 元素。也就是直接包括地圖的元素。由於瀏覽器都有默認的右鍵菜單。所以我們要取消默認的菜單,僅僅要調用 e.preventDefault(); 就可以:
$(map.getViewport()).on("contextmenu", function(event){
e.preventDefault();
// 書寫事件觸發后的函數
});
獲取地圖對應的點擊坐標
獲取地圖對應的點擊坐標僅僅須要一句就可以。例如以下。
var coordinate = map.getEventCoordinate(event);
函數參數是 oncontextmenu 對應的事件對象。該函數包括對 map.getCoordinateFromPixel() 的調用。map.getCoordinateFromPixel() 參數為 ol.pixel,是一個坐標。數組格式[x, y],事實上現中又調用了 ol.vec.Mat4.multVec2(),該函數完畢處理坐標轉換的實際工作。
地圖對應位置加入菜單
這里我們結合 overlay 加入菜單,之前的文章介紹過 overlay。這里就不再詳細展開了。
首先,我們在 html 頁面加入一個文件夾,詳細的 css 樣式能夠自己設定,想看完整源代碼的能夠到我的 GitHub 中查看或者下載完整的代碼:
<div id="contextmenu_container" class="contextmenu">
<ul>
<li><a href="#">設置中心</a></li>
<li><a href="#">加入地標</a></li>
<li><a href="#">距離丈量</a></li>
</ul>
</div>
使用這個 html 元素初始化一個 overlay,並將 overlay 加入到地圖中:
var menu_overlay = new ol.Overlay({
element: document.getElementById("contextmenu_container"),
positioning: 'center-center'
});
menu_overlay.setMap(map);
接下來,我們就能夠在鼠標右鍵菜單的事件回調函數中,依據獲取的地圖坐標位置,設置 overlay 的顯示位置:
menu_overlay.setPosition(coordinate);
菜單隱藏
當我們鼠標點擊右鍵,菜單出現,可是我們不能讓菜單總是顯示在地圖中,這時我們能夠加入鼠標左鍵單擊,菜單消失功能。或者當選擇某項功能時。菜單消失。這個比較easy實現,僅僅要一句便能夠實現,放在鼠標左鍵事件的回調函數或者菜單功能運行函數中就可以。例如以下:
menu_overlay.setPosition(undefined);
總結
這篇文章中,主要講了 openlayers 初始化頁面地圖元素的過程,並介紹了在地圖上實現“鼠標右鍵菜單功能”。和隱藏菜單的實現。我們並沒有對菜單中的條目綁定事件,由於我們的重點在於實現右鍵菜單,對於菜單的條目要綁定什么功能,和普通的 javascript 事件綁定並無二致,所以沒有展開。
好的,就寫到這里,有什么問題,能夠在文章以下留言或者給我發郵件。
文章中的實例完整代碼能夠到我的 GitHub 中查看或者下載,實用的話別忘了點一下 star。
