提到小工具,就不得不提到 OpenLayers 。 OpenLayers (主頁是 http://www.openlayers.org )是由 MetaCarta 最初發起的,用于在網頁界面上展示地圖的一套 Javascript 腳本框架。
MapGuide
的
Fusion
框架最為核心的地圖
Widget
,就是采用了
OpenLayers
框架。
Fusion
框架對
OpenLayers
進行包裝,為其添加了更多的功能,從而使之能夠更符合
Fusion
框架并與其余
Fusion
組件進行交互。
非常有趣的是,由于 OpenLayers 所采用的術語跟 Fusion 采用的并不是十分一致,甚至 Fusion 不同部分采用的術語也不是十分一致,所以同一個名字在不同地方表達的意思卻很可能并不相同。所以,在詳細介紹 Fusion 如何對 OpenLayers 進行包裝之前,有必要對兩者之間的術語進行一下區分,以免當您閱讀到相關材料時感到疑惑。
OpenLayers 認為,用戶看到的由多個圖層 (layer) 組成的一張地圖 (map) 。地圖本身與加載的數據源格式無關,與數據源格式相關的是圖層。因此,地圖類只有一個( OpenLayers.Map ),而圖層類卻有很多,這些類都以 OpenLayers.Layer 作為命名空間,如 OpenLayers.Layer.Google/Yahoo/MapGuide/WMS/Vector 等等。
這樣的結構有一個問題,那就是所有的圖層之間是平行的關系,這是很不利于圖層管理的。我們假設有這樣一張地圖:該地圖包含有十二個圖層,有九個來自于不同數據源的圖層和三個位于頂層的 Vector 層。那么,我如果想用代碼去處理所有 Vector 的層,就必須遍歷所有的層,依次比較是不是 Vector 層,再對 Vector 層進行處理。解決這個問題的方案很簡單,那就是引入層級結構,允許用戶把圖層分組。比如上面的例子中,把三個 Vector 分成一組,比如命名為“標記”組,屆時只需要對標記組中的每一個層進行處理即可。
這也正是 Fusion 對于 OpenLayers 眾多改進中的一個。而問題也正是這里引入的:地圖 Widget 在給這種層級結構命名的時候,出人意料地采用了另外的命名方式:地圖 Widget 把圖層組命名為“地圖組” (map group) ,把組里面的圖層命名為 (map) 。下面代碼是示例數據中 Library://Samples/Sheboygan/FlexibleLayouts/Slate.ApplicationDefinition 布局文件對于地圖定義的那一部分,用戶可以在 MapGuide Studio 中通過點擊位于 Map 面板上的 “Edit Map Group” 按鈕來查看這部分內容。
<?xml version="1.0" encoding="utf-8"?> <MapSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> ? <MapGroupType id="Sheboygan"> ??? <Map> ????? <Type>MapGuide</Type> ????? <SingleTile>true</SingleTile> ????? <Extension> ??????? <ResourceId>Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition</ResourceId> ??????? <SelectionAsOverlay>true</SelectionAsOverlay> ??????? <SelectionColor>0x0000FFA0</SelectionColor> ????? </Extension> ??? </Map> ??? <Extension /> ? </MapGroupType> </MapSet> |
布局文件中地圖定義的部分代碼
其實, MapGuide 這樣做是有原因的。這個問題源于不同產品之間定位的不同: OpenLayers 框架的目的是在同一張地圖上面顯示多個數據源。所以在 OpenLayers 看來,一個來自 MapGuide 的地圖僅僅是一個層而已。然而,在 MapGuide 內部,一張 MapGuide 地圖內是包含多個 Layer ,具體表現就是一個 MapDefinition 里可以包含多個 LayerDefinition 。所以,如果 Fusion 把 MapGuide 叫做一個 Layer 的話,又該如何稱呼里面的 Layer 呢?
鑒于這樣的考慮, Fusion 才做了這種概念上的映射: Fusion 中的地圖 Widget 對應 OpenLayers 里面的地圖; Fusion 里面的地圖組是一個邏輯概念,從而形成一種邏輯上的層級結構以便管理; Fusion 中的地圖實際對應于 OpenLayers 里面的圖層。
但事情到這里還沒有結束,接下來的事情可能會讓您有些意外:在編寫地圖 Widget 實現代碼時,為了能夠便于與 OpenLayers 中的類對應起來, Fusion 將地圖(也就是 OpenLayers 中的圖層)稱為 Layers (注意,不是 Layer ),并要求每一個地圖的代碼都繼承自 Fusion.Layers 。比如, MapGuide 的 Layers 的名稱就叫做 Fusion.Layers.MapGuide 。
下表總結了 Fusion 與 OpenLayers 之間這種概念映射關系
Fusion 概念 |
Fusion 代碼命名 |
OpenLayers 概念 |
OpenLayers 代碼命名 |
地圖 |
Fusion.Layers |
圖層 |
OpenLayers.Layer |
地圖組 |
|
無對應概念 |
|
地圖 Widget |
Fusion.Widget.Map |
地圖 |
OpenLayers.Map |
?Fusion 與 OpenLayers 之間的概念映射關系
在閱讀 Fusion 和 OpenLayers 的源代碼或學習他們的 API 時,一定要注意兩者術語上的區別。
本節中,我們提到了
Fusion
引入了地圖組這一個概念。這只是
Fusion
對于
OpenLayers
眾多改動中的一個。下面我們來看看到底
Fusion
對
OpenLayers
還做了哪些改動。
Fusion 對于 OpenLayers 的改進
為了便于 Fusion 的其他組件能夠與地圖進行交互, Fusion 對于 OpenLayers 進行了較為全面的包裝。一般來說,如果您不是開發 Fusion.Layers 的開發人員,除了使用一些 OpenLayers 的一些工具性的函數之外,您甚至都不需要知道 OpenLayers 的存在。但是,僅僅進行包裝是不夠的,由于 OpenLayers 與 Fusion 定位的不同, Fusion 必須對 OpenLayers 進行擴展才能適應更為復雜的模型。
1.?????? Fusion 中添加了選擇集的概念。 OpenLayers 在同一張地圖里面顯示多種不同數據源的方面確實做的很好,遺憾的是,它缺少選擇集這一至關重要的概念。對于 OpenLayers 來說,選擇集完全是可有可無的,因為它的目的在于將地圖展示出來,而且,很多地圖根本就沒有選擇集這樣的 API ,比如 Google 地圖等等。但對于 Fusion 則不同,我們很難想象沒有選擇集,用戶該如何利用 MapGuide 進行管理。所以, Fusion 加入了選擇集這個概念,并且要求實現 Layers 的地圖(比如 MapGuide )實現選擇集功能。我們可以看到, Fusion.Widget.Map 中不但有諸如 get/set/clear/hasSelection 這樣控制和讀取選擇集的函數,而且有 MAP_SELECTION_ON 和 MAP_SELECTION_OFF 這兩個事件來通知監聽者地圖選擇集的當前狀況。
2.?????? Fusion 開放了更多的事件。借助于 Fusion 自己獨立實現的事件機制, Fusion 允許用戶接收到更多種類的事件,比如 Session 是否已創建、地圖當前忙碌與否、選擇集狀態變更、當前圖層(這個是 Fusion 中的圖層,不是 OpenLayers 的)變化等等。
3.?????? Fusion 允許地圖的實現類返回自身支持哪些比例尺,這就使得用戶可以直觀的知道自己當前縮放地圖到什么程度。
4.?????? 允許用戶隨時設置當前地圖的背景圖片和地圖上的光標形狀。這對于直觀地反應地圖當前狀態是是否有用的。
5.?????? 支持右鍵菜單。雖然在瀏覽器上實現右鍵菜單相對簡單一些,但是通過使用地圖 Widget 的 setContextMenu ,代碼編寫者就可以直接把已經準備好的 div 作為右鍵菜單,再也不需要直接與底層鼠標事件打交道了。
地圖的定義
前面在介紹 Fusion 與 OpenLayers 術語不同的時候,摘錄了應用程序定義中對于地圖部分的定義。通過解析這個定義, Fusion 了解了應該如何加載該地圖。下面,我們就來看看這個定義中到底都定義了哪些東西。
在 Fusion 中,一個地圖組用一個 MapGroup 進行標簽定義, MapGroup 里面的 Map 標簽就是對于一個地圖的定義了。
1.?????? Type: 該標簽標示了地圖的類型。所有 MapGuide 地圖該標簽的值均為 MapGuide 。當 Fusion 讀取到該地圖的 Type 時,就會用對應的 “Fusion.Layers. 標簽值 ” 來初始化該地圖。比如 MapGuide 地圖就會用 Fusion.Layer.MapGuide 來初始化。
2.?????? SingleTile: 如果該項為真,則表示該項不采用分塊服務。
3.?????? Extension: 該于擴展 Map 標簽,來為地圖初始化提供更多的信息。各個 Fusion.Layers 的實現類可以自行決定其需要的內容,以及如何解釋這些內容。對于 MapGuide 而言,有以下常見的擴展:
a)???????? ResourceId: MapDefinition 的資源 Id ,通過該 Id , Fusion 可以知道加載哪一個地圖定義。
b)??????? SelectionAsOverLay: 如果該項是 true ,那么將會使用 GETDYNAMICOVERLAY 來獲取地圖,否則采用 GETMAPIMAGE 來獲取地圖。前者是新版本才支持的,可以把選擇集和地圖本身繪制成兩張地圖。如果您使用的 MapGuide 版本比較舊,您可以把該項設置成為 false
c)???????? SelectionColor: 該項表示用什么顏色來顯示選中的要素。