ArcGIS FlexViewer入門教程

1、ArcGIS API for Flex-Widget開發部署流程

開發Widget開發工具:Flex Builder
開發語言:ActionScript & mxml

1)開發環境配置:

a)首先確保FlexBuilder(Flex SDK 4.6)安裝成功,並下載Flex viewer(libs目錄中包含ArcGIS API for Flexv1.0)。
b)解壓下載下來的Flex viewer壓縮包。
c)打開Flex Builder,將剛解壓出來的源代碼導入到flex workspace中。在導入嚮導中選擇源代碼的目錄,點擊finish。
d)編譯Flex Viewer。選中當前工程,在Project 菜單下選擇Build Project。
2)自定義widget開發
a)新建一個mxml組件(右鍵單擊flex Viewer ,選擇New->MXML Component)。選擇組件目錄,輸入組件名稱,並確保該組件繼承BasWidget類。
b)將創建好的widget添加Flex Builder ProjectModule list。右鍵單擊Flex Viewer 工程,選擇屬性(properties),打開屬性配置框,然後在左邊列表擇FlexModules。單擊Add按鈕,選擇MyFirstWidget.mxml。這一步的目的是確保MyFirstWidget能夠被編譯成單獨的swf文件。
c)編譯widget。重新編譯整個Flex Viewer 工程即可。編譯完成之後在bin-debug目錄下就會有MyFirstWidget.swf。
3)使用WidgetTemplate,打開MyFirstWidget.mxml文件,內置的WidgetTemplate提供了豐富的界面元素。下面介紹如何部署Widget。
a)把Widget加入到config.xml文件中。
打開config.xml文件並在<widgets>標籤中添加代碼:
b)保存config.xml文件並重新編譯Flex Viewer。
c)運行Flex Viewer。
d)從Tool菜單中選擇My First Widget。

至此,通過代碼就完成了個基本的Widget UI 設計,已經有了最大化,最小化,關閉等功能。下一步,就是實現業務邏輯。

4) 訪問地圖 (Accessing a Map)
Flex Viewer是一個以地圖爲中心的應用程序,所有的操作都是圍繞地圖來進行。FlexViewer初始化之後,Widget就可以訪問地圖了(來自ArcGISServer 的地圖服務)。map是BaseWidget類中定義的一個public 屬性,只要是繼承BaseWidget的類都可以訪問改屬性,該屬性是com.esri.ags.Map(ArcGIS API for Flex)類型,因此可以使用map對象訪問任何在ArcGIS API for Flex中的對象。當widget 被加載之後,widget manager會動態的把當前活動的地圖對象關聯到widget。

5) 在地圖上顯示業務數據
a)添加GraphicsLayer
建議爲每個Widget都創建一個Graphics Layer。
b)Widget打開/最小化的時候打開/關閉Graphics Layer,WidgetTemplate提供了2個窗口狀態的事件:widgetOpened 和 widgetClosed,可以使用這兩個事件來同步WidgetTemplate窗口狀態的變化和Graphics Layer顯示。當widget打開的時候顯示Graphics Layer,當widget關閉的時候隱藏Graphics Layer。例子如下:首先偵聽widgetOpened 和 widgetClosed事件。在widgetOpened 和 widgetClosed事件的響應函數中控制Graphics Layer的顯示。
6)Widget中使用繪製功能
在 Flex Viewer 中通過調用setMapAction方法,可以方便的進行地圖上的繪製。setMapAction是在BaseWidget類中定義的public方法,因此只要繼承於BaseWidget類的Widget都可以使用該方法。
setMapAction方法的定義如下:
參數:
action: String 類型,定義爲當前繪製操作的要素類型。對應ArcGIS Flex API 中繪製工具的繪製要素類型。對應列表如表3-2:
表 3-2:flexViewrer與ArcGIS API for Flex繪製消息對應表

Flex Viewer

ArcGIS API for Flex

extent

Draw.EXTENT

point

Draw.MAPPOINT

line

Draw.LINE

polyline

Draw.POLYLINE

polygon

Draw.POLYGON

multipoint

Draw.MULTIPOINT

freehandpolyline

Draw.FREEHAND_POLYLINE

freehandpolygon

Draw.FREEHAND_POLYGON

status: String 類型,在控制欄上顯示的狀態文本。
callback: Function類型,繪製結束後調用的回調函數。回調函數的定義可以參考下面代碼:

2、FlexViewer源碼包結構

Flex Viewer源代碼是Flash Builder中標準的Flex工程,可直接導入到Flash Builder。下面分別介紹一下源代碼包結構中的各個部分,包結構如下圖所示。

1) src根目錄:包含index.mxml、defaults.css和config.xml。index.mxml是系統入口點,也就是創建Flex Application實例的地方;defaults.css是Flex Viewer中用來定義組件樣式的文件,所有對組件樣式進行定義的css腳本都可以放到這個文件中,defaults.css在index.mxml中被引用;config.xml是缺省配置文件。

2) apps:Flex Viewer的良好設計使其具有很高的可配置性,包括底圖、業務圖層、各種服務器端資源、甚至是用戶體驗都是可配置的。apps包中的內容是不同應用系統的配置文件及各種所需資源。Flex Viewer可以在url參數中設置所需加載的配置文件,比如:在Flex Viewer的url後加上配置文件的信息“?config=apps/zh_CN/config.xml”,Flex Viewer就會加載apps/zh_CN下的config.xml文件,根據該配置文件中的信息來配置整個Flex Viewer系統。也就是說,Flex Viewer根據不同的配置文件可以展現完全不同的應用系統。

3) assets.images:Flex Viewer使用的各種圖片、flash資源所在的目錄。

4) com.esri.viewer:該包及其子包的內容是Flex Viewer的主體程序,這裏所說的“主體程序”是相對於Widget而言的。主體程序中實現了Widget的基礎、對Widget的管理、以及除自定義Widget之外的所有功能,這部分內容將在後邊的小節介紹。

5) widgets:Flex Viewer中所有的Widget都在此包中。Widget基於Module開發,Module是Adobe爲解決Flex系統體積過大而提出的一種解決方案,較大的Flex系統可以通過Module將系統進行分割,從而減小系統初始化所需加載的體積。Flex Viewer通過Widget將業務功能進行劃分,每個Widget都是一個功能相對完善和獨立的組件,每個Widget可以獨立完成一個或者一組相關操作。

6) libs:這是Flash Builder中Flex工程存放庫文件的目錄,agslib-2.3-2011-03-01.swc是AGS Flex API 2.3的庫文件。根據不同的業務需求,可能會用到更多的庫文件,那麼這些庫文件都將放到這個目錄下。

7) locale:Flex Viewer支持國際化,國際化所需的屬性文件全部放在該目錄下。在Flash Builder中,可通過指定編譯參數來決定使用哪種語言,如下圖所示:

3、FlexViewer架構分析

在com.esri.viewer.managers包中,彙集了Flex Viewer中所有的Manager。這些Manager各個肩負重任,他們雖隱身幕後,卻是Flex Viewer良好運轉的關鍵,我們不妨稱之爲主席團成員。

1) ConfigManager

Flex Viewer通過配置文件來組織數據、功能和UI。ConfigManager的責任是適時讀取配置文件,對配置文件進行解析,然後將解析結果分發出去,由其他需要使用配置文件數據的模塊接收。

2) DataManager

Flex Viewer各個部分之間需要共享數據,比如說Widget與Widget之間數據共享。DataManager提供了一種數據共享的方案,任何模塊都可以通過DataManager把數據貢獻出來,供其它模塊使用。 DataManager的關鍵職責是把共享數據保存在內存中,任何時候都可以從DataManager獲取需要的共享數據。

3) MapManager

Map是GIS應用的基礎。MapManager解決了Map的問題。MapManager不是對Map的簡單封裝,而是提供了所有與Map相關的操作,比如根據配置文件加載地圖,放大、縮小這些基本操作,畫圖,在地圖上顯示信息框,圖層控制等等。如果在某個自定義Widget中,想要畫一個多邊形,不必new一個DrawTool,發個消息告訴MapManager你想畫個多邊形即可;如果你想在地圖上某個點上顯示一些信息,同樣發個消息告訴MapManager就行了。MapManager會很友好地幫我們完很多工作,我們只需發個消息知會一聲。

4) ScriptingManager

預留,尚未使用。

5) SecurityManager

預留,尚未使用。

6) UIManager

Flex Viewer用戶體驗之所以風格統一,是因爲UIManager做了大量的工作。在配置文件中,有如下腳本,UIManager會根據這一信息對UI的樣式進行配置。

<style>

<colors>

0xFFFFFF,0x333333,0x101010,0x000000,0xFFD700

</colors>

<alpha>0.8</alpha>

</style>

7) WidgetManager

顧名思義,WidgetManager是對Widget進行管理的組件。WidgetManager對Widget的管理包括根據配置文件創建Widget信息列表、加載Widget、佈局Widget、關閉Widget等。WidgetManager提供四種Widget佈局方式:自由佈局(float)、水平佈局(horizontal)、垂直佈局(vertical)和固定佈局(fix)。自由佈局Widget可以拖動,水平佈局、垂直佈局和固定佈局Widget完全有WidgetManager管理,不可拖動;四種佈局方式中,固定佈局Widget不可改變窗口大小。

3.2Flex Viewer鬆耦合的關鍵

系統耦合度是決定系統靈活性與可維護性的關鍵。Flex Viewer的鬆耦合設計是其健壯的關鍵因素之一。那麼,是什麼保證了FlexViewer的鬆耦合呢?

“事件!事件!還是事件!”

事件是Flex Viewer鬆耦合的關鍵。在3.1中多次提到了“消息”,物化到Flex Viewer中就是事件。不同的模塊通過事件彼此交互、傳遞數據,保證了各模塊之間的鬆耦合,彼此不必相知,卻能緊密合作。ViewerContainer、EventBus、AppEvent組成了Flex Viewer事件機制的基礎。當然,Flex Viewer事件機制的基礎是Flex的事件機制。

1) EventBus

繼承自EventDispatcher,使用了單例模式。EventBus是全局的事件派發器,爲Flex Viewer中的不同模塊之間的交互提供便利。有了EventBus,不同模塊之間的交互無需彼此調用對方的方法,只需派發/監聽消息即可。

2) AppEvent

繼承自Event,在Flex Viewer中被用來當做消息和數據的載體,在不同的模塊之間傳遞數據。AppEvent定義了Flex Viewer中需要的所有事件類型,也就是那些公共的字符串常量。通常,系統層面需要添加的事件也都定義在AppEvent中。

3) ViewerContainer

繼承自Group,使用了單例模式,是Flex Viewer中各個模塊的容器。Flex Viewer中調用ViewerContainer最多的三個方法是:addEventListener()、dispatchEvent()、showError()。我們可以在任何需要對某類AppEvent事件進行監聽的地方通過addEventListener()方法添加監聽,可以在任何需要派發某類AppEvent事件的地方通過dispatchEvent()方法派發事件,可以在任何需要顯示Error信息的地方通過showError()方法顯示Error信息。如果通讀Flex Viewer代碼,會發現,AppEvent的監聽與派發隨處可見。

Flex Viewer鬆耦合的關鍵因素還有Widget的設計和實現,這部分內容將在後面的小節涉及,在此按下不表。

至此,我們的討論涉及到了Flex Viewer中的絕大部分模塊,先來看一下Flex Viewer的整體結構,如圖3.1所示。圖中最下方的Control Widgets和Business Widgets尚未提及,我們將在3.4中涉及這部分內容。

圖 3.1 Flex Viewer整體結構

3.3初始化那些事兒

在瀏覽器地址欄輸入Flex Viewer的地址,經過短暫等待,當她華麗麗地展現在我們眼前,你是否想過在這短暫的等待中,Flex Viewer都做了哪些事情呢?本小節我們來探討Flex Viewer初始化那些事兒。注意,我們這裏所說的Flex Viewer初始化,不是Flex概念中組件生命週期的初始化部分,而是指Flex Viewer在可以與用戶交互之前,所做的準備工作。

圖 3.2 Flex Viewer初始化過程

3.2小節中,我們強調通過使用事件,Flex Viewer將各模塊之間充分解耦。實際上,事件也伴隨着Flex Viewer初始化的整個過程。Flex Viewer的初始化過程如圖3.2所示。

1) 首先觀察一下ConfigManager的構造方法,其中有這樣一句代碼:

ViewerContainer.addEventListener(ViewerContainer.CONTAINER_INITIALIZED,init);

也就是說,ConfigManager實例在構造期間就通過ViewerContainer在EventBus的單例添加了對CONTAINER_INITIALIZED事件的監聽,一旦ViewerContainer在別的地方派發了CONTAINER_INITIALIZED事件,ConfigManager將響應該事件,開始讀取配置文件、解析配置文件,構造ConfigData數據,最後將ConfigData連同CONFIG_LOADED事件派發出去,見下面代碼:

ViewerContainer.dispatchEvent(newAppEvent(AppEvent.CONFIG_LOADED, configData));

2) 我們再觀察一下UIManager、WidgetManager和MapManager的代碼,在各自的初始化代碼中,都可以找到下面一句代碼,此處不再解釋:

ViewerContainer.addEventListener(AppEvent.CONFIG_LOADED,config);

3) 最後,問題的關鍵在於CONTAINER_INITIALIZED事件何時何地被派發?我們觀察一下ViewerContainer的init()方法,其中有下面這句代碼:

ViewerContainer.dispatch(ViewerContainer.CONTAINER_INITIALIZED);

而init()方法是ViewerContainer的creationComplete事件的響應方法。也就是說ViewerContainer初始化結束纔是Flex Viewer初始化的開始。

Flex Viewer初始化的脈絡已經相當清晰,ConfigManager、UIManager、WidgetManager、MapManager在各自的初始化過程中對相應的事件進行監聽,一旦ViewerContainer初始化完成,派發出CONTAINER_INITIALIZED事件,其它的準備工作將順其自然,水到渠成。

我們注意到,初始化過程所涉及的各個模塊都是相互透明的,彼此並不知道有對方的存在,而這些模塊之所以能夠親密協作,關鍵就在於它們都只關心事件,事件機制使得這些模塊之間實現鬆耦合。實際上,事件充斥着Flex Viewer的各個角落,隨着對Flex Viewer理解的逐漸深入,對這一點的體會將更加明顯。

3.4Widget設計及實現

一個Widget是對一組相關操作的封裝,這些相關操作完成某項特定業務功能。Widget不僅可以調用地圖資源,也可以訪問服務器端資源。Widget基於Flex Module,編譯後是獨立的swf文件,這樣一來,將具體的業務邏輯封裝在Widget中,減小了系統主體的體積,在業務功能較多時,可顯著縮短系統加載時間。加之面向接口編程和依賴注入思想的應用,Flex Viewer中的Widget可以獨立開發,通過配置文件決定提供哪些Widget,從而決定系統提供哪些業務功能。可以把Widget理解爲“插件”。這種靈活的“插件”機制是如何實現的呢?下面我們瞭解一下Widget編程模型,如圖3.3所示。

圖 3.3 Widget編程模型

Widget分爲兩種,Control Widget和Business Widget。Control Widget是指控制組件,比如NavigationWidget、HeaderControllerWidget、OverviewMapWidget等,這些Widget提供系統級別的功能,不針對具體業務功能;Business Widget是指業務組件,比如SearchWidget、BookmarWidget、GeoRSSWidget等,這些Widget提供具體業務功能。兩種Widget都繼承自BaseWidget,都由WidgetManager來管理,不同的是,在WidgetManager中有一個WidgetContainer來專門管理Business Widget。

兩種Widget有共同的父類BaseWidget,BaseWidget實現了接口IBaseWidget,兩者也就有了共同的接口。WidgetManager通過IBaseWidget來管理Widget,與具體的Widget解耦。FlexViewer此處使用面向接口編程和依賴注入,實現了主體系統與Widget的鬆耦合。

u IBaseWidget

該接口定義了WidgetManager與Widget進行交互的方法,BaseWidget實現了這個接口。

u BaseWidget

該類是所有Widget的基類。只要某一組件繼承自BaseWidget,WidgetManager即可對其進行管理。由於BaseWidget繼承自Module,每一個Widget都將編譯成獨立的swf文件。

但兩種Widget在具體實現上有所不同。Flex Viewer爲Business Widget提供了統一的UI基類和接口,也就是WidgetTemplate和IWidgetTemplate。通常情況下,Control Widget都會使用自定義UI,但是這不是必須的。

u IWidgetTemplate

該接口定義了BaseWidget與WidgetTemplate交互的方法。WidgetTemplate實現了這一接口。

u WidgetTemplate

該類是IWidgetTemplate的一種默認實現,在具體的Widget實現中,同樣可以使用自定義的WidgetTemplate,只要實現IWidgetTemplate接口即可。WidgetTemplate爲Widget提供基本UI控件,包括窗口面板、帶有圖片按鈕的標題欄等。使用Flex Viewer實現的WidgetTemplate,開發人員可以將更多的精力和時間放在實現業務邏輯上。

需要說明的是,Widget的設計在Flex Viewer 1.x版本和2.x版本中有所區別。在1.x中不存在ControlWidget,比如菜單組件,菜單項是可配置的,但是菜單組件本身是不可配置的。2.x版本以後,Widget的概念擴大了,Flex Viewer中,凡是能看到的組件都是Widget,這樣一來,控制組件可以像業務組件一樣可配置,比如HeaderControllerWidget,靈活性大大提高。

4、FlexViewer2.3自定義Widget

1) 安裝Flash Builder,下載Flex Viewer源碼,我們使用最新的2.3;

2) 打開Flash Builder,導入Flex Viewer 2.3的源代碼;

3) 鼠標放在widgets包上,單擊右鍵,在彈出的菜單中選擇New,然後單擊MXML Component;

4) 在New MXML Component對話框中,輸入包名“widgets.HelloWorld”,填寫Widget名稱“HelloWorldWidget”,並選擇基類BaseWidget,單擊Finish;

5) 此時,HelloWorldWidget已經創建完畢,按照Flex Viewer提倡的做法,在其包下新建一個同名xml配置文件,即“HelloWorldWidget.xml”;

6) 此時,HelloWorldWidget不會被編譯,因爲還未把它加入到Module列表。打開工程的屬性窗口,點擊Flex Modules,點擊Add鍵,將HelloWorldWidget加入到Module列表中。點擊OK,會發現HelloWorldWidget的圖標已經和其他的Widget一樣;

7) 啓動編譯,編譯後會發現在bin-debug目錄下,HelloWorldWidget已經被編譯成swf文件;

8) 下面開始實現HelloWorldWidget的業務邏輯,在Widget面板中顯示出配置文件中的“Hello,Flex Viewer!”字符串。配置文件內容:

<?xml version="1.0" ?>

<configuration>

<hellocontent>Hello, Flex Viewer!</hellocontent>

</configuration>

HelloWorldWidget代碼:

<?xml version="1.0" encoding="utf-8"?>

<viewer:BaseWidgetxmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark"

xmlns:mx="library://ns.adobe.com/flex/mx"

xmlns:viewer="com.esri.viewer.*"

layout="absolute"

width="400"

height="300"

widgetConfigLoaded="init()">

<fx:Script>

<![CDATA[

[Bindable]

private varhelloContent:String;

privatefunction init():void{

if(configXML){

helloContent=String(configXML.hellocontent);

}

}

]]>

</fx:Script>

<viewer:WidgetTemplate>

<s:HGroupwidth="100%"

height="100%"

horizontalAlign="center"

verticalAlign="middle">

<s:Labeltext="{helloContent}"/>

</s:HGroup>

</viewer:WidgetTemplate>

</viewer:BaseWidget>

9) 在config.xml對HelloWorldWidget進行配置,如下:

<widgetcontainer>

<widget label="HelloWorld"icon="assets/images/i_solar.png"

config="widgets/HelloWorld/HelloWorldWidget.xml"

url="widgets/HelloWorld/HelloWorldWidget.swf"/>

</widgetcontainer>

10)編譯,運行!Hello,Flex Viewer!

5、FlexViewer2.3Widget之間的通信

雖然每個Widget都是封裝良好的一個組件,提供一組針對特定業務功能的操作,但是有時候需要Widget之間的彼此協作來完成一個粒度更大的業務邏輯。此時就需要Widget之間的交互,或者說通信。經常看到這樣的問題“一個Widget如何調用另外一個Widget的方法?”。Widget之間彼此相互獨立,互不知曉,“一個Widget調用另一個Widget的方法”意味着兩個Widget緊密地耦合在了一起,這不符合“鬆耦合”的要求。那麼Widget之間該如何交互呢?答案還是事件!還記得ViewerContainer的addEventListener()和dispatchEvent()方法麼?ViewerContainer通過EventBus添加監聽和派發事件,使各模塊默契協作。

5.1 直接通信

直接通信是指Widget A監聽某一事件E,Widget B在任何時間派發了事件E,WidgetA都能夠捕捉到這個事件,並進行響應。當然,這裏對事件的監聽和捕捉都是通過ViewerContainer代理的EventBus實現的,參見圖5.1。我們注意到,Widget A與Widget B除了通過全局的EventBus監聽、派發、捕捉事件外,沒有發生任何直接的聯繫。

圖 5.1 Widget之間直接通信

① Widget A通過EventBus監聽事件E

② Widget B通過EventBus派發事件E

③ Widget A通過EventBus捕捉事件E,並進行響應。

5.2 間接通信

直接通信有一個前提條件,那就是必須交互的兩個Widget都已經被加載。Widget採用lazy-load的加載方式,也就是隻有第一次打開的時候纔會加載。如果Widget B已經加載並派發了事件E,而此時Widget A還並未加載,Widget A是無法捕捉並響應事件E的,因爲Widget A在內存中還不存在。

此時的解決方法是通過DataManager間接通信。DataManager響應Widget B派發的事件,並數據存儲起來,Widget A在第一次加載時通過DataManager獲取Widget B共享的數據,以此可以達到通信的目的,參見圖5.2。同樣的,Widget A與WidgetB,以及兩者與DataManager之間並未直接交互,所有的協作都通過事件來完成。

① DataManager通過EventBus監聽共享數據事件獲取數據事件

② Widget B派發共享數據事件

③ DataManager響應共享數據事件,將數據以key-value的形式保存;

④ Widget A監聽分發數據事件,並且派發獲取數據事件

⑤ DataManager響應獲取數據事件,查詢Widget A所需數據,派發分發數據事件

⑥ Widget A響應分發數據事件,並做相應的響應動作。

DataManager是Flex Viewer爲模塊之間共享數據和保存共享數據設計的一種解決方案。DataManager將各個模塊需要共享出來的數據存儲在內存中,一旦某個模塊需要獲取共享數據,派發一個消息即可,DataManager會響應這個消息,並共享數據作爲消息的載體派發出去。

DataManager響應的事件

u DATA_FETCH_ALL:獲取數據事件(全部數據)

u DATA_PUBLISH:共享數據事件

u DATA_FETCH:獲取數據事件(根據key獲取數據)

DataManager派發的事件

u DATA_SENT:分發數據事件

u DATA_NEW_PUBLISHED:當有新的數據被共享時,將新數據分發出去

6、FlexViewer2.3中拉簾Widget下載

由於最新的ArcGIS API for flex2.x使用了Flex SDK4,因此造成了對之前ArcGIS API for flex1.x制 作的拉簾Widget無法使用,因此重新制作了拉簾工具供大家使用。

下載地址:

Swipe

使用方法:將下載後的swipe.zip解壓,將swipe目錄拷貝到flexViewer工程的src\widgets目錄下,並 將Widget加入到flexViewer工程的模塊(Flex Module)中,編譯。最後在congfig.xml中增加爲 swipeWidget的引用。

(文章轉自)http://www.kubihai.com/c/548535.html
發佈了3 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章