Flex Viewer解析.docx
- 文档编号:10649905
- 上传时间:2023-02-22
- 格式:DOCX
- 页数:22
- 大小:211.93KB
Flex Viewer解析.docx
《Flex Viewer解析.docx》由会员分享,可在线阅读,更多相关《Flex Viewer解析.docx(22页珍藏版)》请在冰豆网上搜索。
FlexViewer解析
公告:
[意见反馈][官方博客]
FlexViewer解析-----结构
(1)收藏
1、 结构图以及解析
下图是ESRI提供的开发帮助里面对其结构的一个描述图,本人做了一些归类:
A部分:
这一部分是项目中的组件列表,包括一些配置文件、Module(就是Widget)、组件等等。
这些组件在没有经过组织之前是完全孤立的。
它们主要完成一些界面显示和业务逻辑。
B部分:
该部分的主要功能就是将A部分中相互完全孤立的文件列表,不管是业务层还是界面层进行一个组织,将他们之间关联起来,便于程序的统一管理和开发。
其中对于将这些文件或者组件综合起来的一个非常重要的一个内容就是container(在viewer中叫做SiteContainer容器),关于container是如何组织这些组件的,在SiteContainer解析一文中将会详细阐述。
C部分:
我们可以将该部分称作数据层,也就是说这一层是提供数据的,不管是地图数据还是常规数据,都是通过这一层获取的,关于这一层在Viewer中并不明显,其贯穿于整个系统的各个角落。
本人愚见,此处也是Viewer需要改进的地方。
在下面的文章里,我们主要基于这三部分对FlexViewer进行解析。
理解了Viewer的这三部分,那么在Viewer中是如何具体的进行文件或者说组件组织的那?
2、 文件组织
首先我们还是看下Viewer的效果图,同样将其分成几个部分,我们在将这些部分进行一一介绍。
我同样将其分成三个大的组件部分。
A部分:
该部分是地图显示部分,也是系统的主体部分,地图的一些显示配置和基本操作都在该部分中。
对于该部分的定义,我们在Viewer中不难找到,那就是FlexVIew文件夹下面的
com\esri\solutions\flexviewer\MapManager.mxml
该文件中定义个,地图的添加以及一些地图的基本操作。
map=newMap();
map.id="map";
map.zoomSliderVisible=false;
map.addEventListener(MapEvent.LOAD,mapLoadComplete);
this.addChild(map);
这几行代码完成了对map控件的添加,下面的部分就是图层的添加以及一些配置,包括一些工具定义:
navToolbar=newNavigation();
navToolbar.map=map;
drawToolbar=newDraw();
drawToolbar.map=map;
这两行代码,为地图添加了一个浏览工具和一个绘图工具。
B部分:
该部分是一个控制条,用来控制整个系统的用户操作。
其主文件为:
com\esri\solutions\flexviewer\Controller.mxml
打开之后我们发现其显示部分很简洁:
Bannerid="banner"status="{status}"/> HBoxid="menuContainer"horizontalGap="-25" horizontalCenter="0"y="{banner.height-20}"/> 其实其使用了一个定义好的组件Banner,这个组件才是这个控制条信息的主体部分。 而control只是为这个组件提供必须的配置信息。 Banner组件位于components文件夹下,打开它,仔细查看其中的内容,我们就可以明白Viewer里面的B部分是怎么出来的了。 然后我们说说B部分的菜单是如何出来的。 在Controller仅仅的两行设计代码里面我们可以看到有个叫做menuContainer的HBox,他就是负责显示菜单的。 在程序的配置文件加载完成后,这个界面就会执行对菜单的配置,也就是下面的一个函数: privatefunctionconfigureMenus(): void { for(vari: Number=0;i { varmenuId: String=configData.configMenus[i].id; varmenuLabel: String=configData.configMenus[i].label; varmenuIcon: String=configData.configMenus[i].icon; varmenuItems: Array=configData.configMenus[i].items; varcontrollerMenu: ControllerMenu=newControllerMenu(); controllerMenu.id=menuId; controllerMenu.menuLabel=menuLabel; controllerMenu.menuImage=menuIcon; controllerMenu.menuCollection=newArrayCollection(menuItems); menuContainer.addChild(controllerMenu); } varbw: Number=configData.configMenus.length*90; if(bw>banner.minWidth) banner.width=bw; } 这里面使用了另外一个组件ControllerMenu,其定义位于Banner.mxml同目录下的ControllerMenu.mxml中,这个组件就是完成主菜单定义的主要控件。 对于子菜单的定义我们在ControllerMenu中可以看到这句代码: Repeaterid="menuRepeater"dataProvider="{menuCollection}"> ControllerMenuItemitemId="{menuRepeater.currentItem.id}" itemLabel="{menuRepeater.currentItem.label}" itemIcon="{menuRepeater.currentItem.icon}" itemRuleVisible="{menuRuleVisible(menuRepeater.currentIndex)}" itemAction="{menuRepeater.currentItem.action}" itemValue="{menuRepeater.currentItem.value}"/> Repeater> 这个Repeater就是用来完成子菜单信息绑定的。 其中使用了关于子菜单的组件ControllerMenuItem,我们打开这个子菜单的定义,可以清楚地看到关于子菜单的点击事件和一些效果代码。 这就是菜单的实现方式。 以上就是Viewer左上侧控制条的实现流程。 C部分: 这一部分的实现相对比较复杂,主要是在其管理上面,再加上其使用Module的方式加载显示,所以感觉上相对复杂。 公告: [意见反馈][官方博客] FlexViewer解析-----结构 (2)收藏 FlexViewer解析-----结构 (2) C部分: 这一部分的实现相对比较复杂,主要是在其管理上面,再加上其使用Module的方式加载显示,所以感觉上相对复杂。 这些侧边栏控件(Widget)的基本显示是通过一个模板出来的,也就是WidgetTemplate,这个模板里面实现了一个基本的Widget模块,包括最大化、最小化、关闭、界面设计等。 WidgetTemplate实现了一个IWidgetTemplate接口。 该接口是用来连接WidgetTemplete和Widget内容的,这个接口的定义还是比较简单的: publicinterfaceIWidgetTemplate { functionsetTitle(value: String): void; functionsetIcon(value: String): void; functionsetState(value: String): void; } 这一接口主要定义的功能有设置Widget的标题、图标以及显示状态。 使用接口的好处众所周知,我们不需要关心当前操作的那个具体对象,如果该对象实现了这个接口,直接使用接口中的函数,就是对当前对象的操作。 以上就是我们在添加一个新的模块的时候为什么要使用此模板的原因: 如果我们想修改Widget侧边栏的风格(不是样式方便)布局,那么我们就可以对WidgetTemplate.mxml这个文件进行编辑,将之修改成我们想要的风格布局。 在后续的实例中会介绍一些例子。 又者,在添加一个Widget的时候,开发指南说让我们继承一个类BaseWidget,为什么要继承这个类那? 其实这个类是用来实现Widget的具体功能,并且获取一些必要的信息的。 上面介绍了侧边栏模板的显示实现,接下来我们谈谈侧边栏功能的实现方式。 首先为了实现侧边栏的一些功能,其为我们定义个一个类BaseWidget,同样为了方便扩展和管理其功能,该类同样实现了一个接口IBaseWidget。 我们先看看这个IBaseWidget接口都定义了那些功能: publicinterfaceIBaseWidget { functionsetId(value: Number): void; functionsetTitle(value: String): void; functionsetIcon(value: String): void; functionsetConfig(value: String): void; functionsetConfigData(value: ConfigData): void; functionsetPreload(value: String): void; functionsetState(value: String): void; functionsetMap(value: Map): void; } 我们可以望文生义的看一下这些接口,不难明白它们都是实现那些功能,看了这个接口我们就可以明白许多东西,为什么在Widget里面可以直接使用map,可以直接使用ConfigData,因为Widget在加载Module的时候已经使用这些接口方法,获取到了这些信息。 当然我们可以直接用的。 那么这时候就会有人问,这里面设置的标题、图标…….怎么会显示到我们的Widget上面的那? 解答此问题我们就要看看BaseWidget这个类为我们做了什么了。 打开BaseWidget.as,我们可以看到这样一个定义: privatevarwidgetTemplate: IWidgetTemplate; 并且在类的构造函数中: publicfunctionBaseWidget() { super(); this.layout="absolute"; addEventListener("creationComplete",initWidgetTemplate); } 也就是添加了一个在其创建完成的事件监听initWidgetTemplate; privatefunctioninitWidgetTemplate(event: Event): void { varchildren: Array=this.getChildren(); foreach(varchild: Objectinchildren) { if(childisIWidgetTemplate) { widgetTemplate=childasIWidgetTemplate; widgetTemplate.setTitle(widgetTitle); widgetTemplate.setIcon(widgetIcon); if(widgetPreload==STATE_MINIMIZED) widgetTemplate.setState(STATE_MINIMIZED); } } } 我们仔细看下这个函数,不难发现,其为前面定义的widgetTemplate进行了复制,赋的什么值那? 读一下这个代码我们什么都清楚了,widgetTemplate的值就是我们在Widget里面添加的 类中的其他代码就不做解释了,都是对一些操作的定义和对事件的监听或触发,供其他地方调用的。 至此,我们的一个Widget的创建原理就说完了,那么创建完了之后,这些作为Module的组件是如何显示和对其中值初始化的那。 下面我们谈谈对Widget的加载过程,关于这一过程的实现在WidgetManagerDocked.mxml中完成。 打开WidgetManagerDocked.mxml文件,我们可能看起来有点乱,但是有些东西我们可以不用去管他。 下面我们一步一步的来看: 首先,创建完成后调用了init()函数,其中就是对一些事件添加事件监听来完成传值的目的。 以后我们会具体介绍。 privatefunctioninit(): void { SiteContainer.addEventListener(AppEvent.CONFIG_LOADED,config); SiteContainer.addEventListener(AppEvent.MAP_LOADED,onMapLoad); SiteContainer.addEventListener(AppEvent.LAYER_LOADED,onLayerLoad);SiteContainer.addEventListener(AppEvent.WIDGET_MENU_CLICKED,widgetMenuClicked); } 通过这些事件监听,我们可以在监听函数中看到,我们获取到了系统的配置信息、地图控件等信息。 privatefunctionconfig(event: AppEvent): void { configData=event.dataasConfigData; } privatefunctiononMapLoad(event: AppEvent): void { map=event.dataasMap; } 这些信息是为我们的Widget准备的,因为Widget中要初始化这些信息。 然后,我们知道,widget是在我们单击了菜单项后才会出现的,那么一次我们就可以接着看AppEvent.WIDGET_MENU_CLICKED事件(菜单单击事件)的监听函数,就是我们的菜单单击这一事件发生后要执行的代码函数widgetMenuClicked: varid: Number=event.dataasNumber; varpreload: String=configData.configWidgets[id].preload; varlabel: String=configData.configWidgets[id].label; varicon: String=configData.configWidgets[id].icon; varconfig: String=configData.configWidgets[id].config; varurl: String=configData.configWidgets[id].url; 这几行是用来获取当前单击菜单项的配置信息的,如id、标注、图片等。 最后一个URL是其生成的SWF文件的路径,有了这个路径我们就可以找到SWF文件,将它加载到我们的页面中。 接着下面的几层判断使用有判断当前的这个要加载的SWF是不是加载过了,在Flex中已经加载过的SWF是已经下载到本地的,不用再去请求。 其实现方式是使用了HashTable,将已加载过的Module信息存到HashTable里面,我们就可以直接去其中把它取出来。 我们不用关心这是如何实现的,直接用就可以啦。 我们看一看第一次加载是如何完成的,直接跳到多层判断的最后一个loadWidget(id,url,preload);函数。 这个函数定义如下: privatefunctionloadWidget(id: Number,url: String,preload: String): void { info=ModuleManager.getModule(url); info.data= { id: id, preload: preload }; info.addEventListener(ModuleEvent.READY,widgetReadyHandler); info.load(); this.cursorManager.setBusyCursor(); } 首先使用ModuleManager和这个Module的地址获取到这个Module: info=ModuleManager.getModule(url); 然后给它赋上我们的附加信息: info.data= { id: id, preload: preload }; 下面就是开始加载这个module,我们看看module加载完成后的事件监听函数widgetReadyHandler; privatefunctionwidgetReadyHandler(event: ModuleEvent): void { varinfo: IModuleInfo=event.module; moduleTable.add(info.url,info);//加入到module的hashtable中 //获取器相关信息 varid: Number=info.data.id; varpreload: String=info.data.preload; varlabel: String=configData.configWidgets[id].label; varicon: String=configData.configWidgets[id].icon; varconfig: String=configData.configWidgets[id].config; //这句很关键,将Module实例成IBaseWidget,其实就是BaseWidget varwidget: IBaseWidget=info.factory.create()asIBaseWidget; //下面这几句就是为这个Widget初始化信息,看了这几句我们应该就可以明白Widget的那些//map等信息怎么出来的啦 widget.setId(id); widget.setTitle(label); widget.setIcon(icon); widget.setConfig(config); widget.setConfigData(configData); widget.setPreload(preload); widget.setMap(map); widgetTable.add(id,widget); //转成显示对象,加到显示容器里面,这个widget就显示出来了。 varwidgetDO: DisplayObject=widgetasDisplayObject; widgetBox.addChild(widgetDO); this.cursorManager.removeBusyCursor(); } 此函数,我就不多介绍啦,注释写的很明白。 对于如何实现Widget的上下滚动的,可以具体看下这个文件内容,很简单就明白啦。 关于C部分的实现架构原理,就说到这儿了。 其他部分: 该部分主要介绍配置信息、样式信息、事件信息等的组织结构 公告: [意见反馈][官方博客] FlexViewer解析-----结构(3)收藏 FlexViewer解析-----结构(3) 其他部分: 该部分主要介绍配置信息、样式信息、事件信息等的组织结构 这些部分我们在界面中看不到,但是他们起着至关重要的作用,也就我们说的总体架构里面的中间部分。 首先,看看配置信息的组织,ConfigManager.as和ConfigData.as来完成。 ConfigData.as中定义了配置信息的数据结构 publicfunctionConfigData() { configUI=[]; configMenus=[]; configMap=[]; configBasemaps=[]; configExtents=[]; configWidgets=[]; } 我们可以清晰地看到,我们需要的配置信息基本上都包含其中,如果需要进行配置信息的扩展,那么我们就首先要在ConfigData里面加上扩展的数据结构。 ConfigManager.as负责把配置文件中的信息读取初始化到一个ConfigData里面,并执行事件分发。 看一下里面的内容还是比较容易明白的。 就不做介绍了。 然后,样式文件的组织在UIManager.as中实现,打开此文件,我们可以在配置文件加载成功的事件监听函数中找到这一句: StyleManager.loadStyleDeclarations(value); 这一句就是将配置的样式文件载入到我们的系统中。 第三,我们看看自定义事件是如何组织的,事件的组织主要在EventBus.as和AppEvent.as中,前者负责分发事件,后者定义事件。 在此不多介绍,以后专门介绍。 第四,程序总体组织SiteContainer,其将所有的这些组件,配置全部在这个SiteContainer里面进行定义,保证系统中获取的对象都是同一个对象,那就是在SiteContainer中定义的对象。 SiteContainer本身也是静态的,就是在整个系统中只有一个Sitecontainer,这样我们就可以通过它方便的获取各个控件中的信息。 自定义事
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Flex Viewer解析 Viewer 解析