本博文编写环境:ArcGIS 10.1 for Server /Destop
ArcGIS Runtime SDK for Windows Phone 3.0
VS2010sp1+WP7.1SDK
动态图层是ArcGIS 10.1一个新的功能,地图服务发布到 ArcGIS Server 站点后,可根据需要选择是否允许服务器的客户端(如 ArcGIS web API/移动的Runtime SDK)动态更改地图服务中的图层外观和行为。要确定哪些图层显示在地图中、图层符号系统、图层顺序和位置以及标注等,可通过使用动态图层在服务器端实现。这种方式下,动态图层可有效增加用户与地图的交互。
例如,假设创建了一个包含美国各州图层的地图文档,并根据 2000 年各州的人口应用了颜色分类。然后以服务形式将地图发布到站点,并在ArcGIS 移动端或者Web端应用程序中引用该服务。现在,假设您希望移动应用程序的用户能够使用不同的色带显示各州 2000 年的人口。通过在地图服务中激活动态图层,可以让客户端在 web 应用程序中自由地更改各州的符号。服务器将应用修改后的色带,然后将生成的地图图像返回给客户端应用程序。虽然启用动态图层的过程是通过 ArcGIS for Desktop实现的,但使用动态图层来更改符号系统、添加图层等操作通常都是通过代码完成的。
如果要向地图服务动态添加数据(例如要素图层、shapefile、栅格或要素属性表),则需要设置工作空间来包含想要添加的数据。动态工作空间可以是任何企业级地理数据库、文件地理数据库或服务器可以访问的磁盘上的文件目录。如果动态工作空间是企业级地理数据库,您可以通过锁定数据库版本来限制用户对地理数据库的访问。选择工作空间时,将生成一个 ID,用来在可供地图服务使用的工作空间池中唯一地标识该工作空间。地图服务使用此 ID 连接到在动态图层请求中所指定的数据源。为地图服务配置动态工作空间时,可以修改该 ID。
简单概括一下,动态图层就是我们可以动态地改变服务中图层的渲染方式以及图层的顺序,这些渲染是在服务端完成的,同时呢,我们也可以注册一个工作空间,来动态地加载工作空间中的数据(可以是SDE,栅格数据集,FileGDB,shp文件等)。当然,注册工作空间必须要确保ArcGIS Server是可以访问到的地方。
动态图层有两种:1、对已有服务中的图层启用允许排序和修改符号;2、动态工作空间中的数据。
关于启用动态图层我们只需要在发布服务的时候勾选,允许修改图层的顺序以及是渲染符号。
如果要注册工作空间的话,除了上面的操作之外,还应该点击manage..按钮
然后点击Add
这里可以注册四种类型的工作空间,根据所选择的工作空间类型,确定指定还是输入工作空间的路径:
如果要对已经发布的服务启用动态图层的话,在catalog中我们可以选中相应的服务,然后右键,选择ServiceProperty,下一步选择Mapping即可进行相应的操作了。
下面通过实例来实现服务端的渲染,首先发布一个地图服务,包括两个图层,一个点一个面。接下来发布服务,File->Shareas->Service|选择pubulish Service,命名为ChinaMap
启用动态图层:选择允许修改图层的顺序和符号
注册一个动态工作空间(如果要实现动态添加图层的话,需要进行该操作)。点击Manage,我这里注册的是一个文件夹,里面有一个shp文件。命名为new.shp.
由于我要动态添加的图层为Shp文件,这里在WorkSpaceType里面选择Shapefile,并且输入一个唯一的空间ID(事实上ArcGIS server就是根据这个ID来寻找数据的),以及选择shp文件所在的文件夹。点击OK之后如下
接下来发布服务提示如下错误
提示是我们的动态工作空间没有注册到ArcGIS Server的数据存储目录里了,上一步的注册动态工作空间,主要是针对动态图层的存放地方,也就是说我们已经告诉了ArcGIS Server 要到什么地方去寻找数据,但是呢,ArcGIS Server 可能没有权限来访问这个空间,10.1中为了确保ArcGIS Server能够访问到该空间,应该把改空间注册到ArcGIS Server 的数据存储(Data Store)里面。只需双击这个错误,然后点击OK即可,ArcMap帮助我们来完成了注册
继续发布服务。这一次成功。
服务准备好了。
接下来介绍再客户端重如何使用,在VS 新建一个Windows Phone应用程序名字为DimicLayer。本Demo 主要是描述了三个功能,服务端渲染,服务端排序,添加服务端的shp文件。
XAML
<Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock HorizontalAlignment="Center" x:Name="PageTitle" Text="动态图层" Margin="9,-7,0,0" FontSize="26" /> <StackPanel Orientation="Horizontal" > <Button Click="ServerRender">服务端渲染</Button> <Button Click="LayerOerder">图层排序</Button> <Button Click="AddShp">添加shp</Button> </StackPanel> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <esri:Map Background="White" Name="MyMap" WrapAround="True"> <esri:Map.Layers> <esri:LayerCollection> <esri:ArcGISDynamicMapServiceLayer ID="MyDynamicLayer" Url="http://localhost:6080/arcgis/rest/services/ChinaMap/MapServer"></esri:ArcGISDynamicMapServiceLayer> </esri:LayerCollection> </esri:Map.Layers> </esri:Map> </Grid> </Grid>
C# 代码如下
private void ServerRender(object sender, RoutedEventArgs e) { ClassBreaksRenderer newClassBreaksRenderer = new ClassBreaksRenderer(); newClassBreaksRenderer.Field = "OBJECTID"; newClassBreaksRenderer.Classes.Add(new ClassBreakInfo() { MinimumValue = 0, MaximumValue = 8, Symbol = new SimpleFillSymbol() { Fill = new SolidColorBrush(Color.FromArgb(255, 0, 255, 0)) } }); newClassBreaksRenderer.Classes.Add(new ClassBreakInfo() { MaximumValue = 14, Symbol = new SimpleFillSymbol() { Fill = new SolidColorBrush(Color.FromArgb(255, 100, 255, 100)) } }); newClassBreaksRenderer.Classes.Add(new ClassBreakInfo() { MaximumValue = 20, Symbol = new SimpleFillSymbol() { Fill = new SolidColorBrush(Color.FromArgb(255, 0, 255, 200)) } }); newClassBreaksRenderer.Classes.Add(new ClassBreakInfo() { MaximumValue = 26, Symbol = new SimpleFillSymbol() { Fill = new SolidColorBrush(Color.FromArgb(255, 0, 255, 255)) } }); newClassBreaksRenderer.Classes.Add(new ClassBreakInfo() { MaximumValue = 34, Symbol = new SimpleFillSymbol() { Fill = new SolidColorBrush(Color.FromArgb(255, 0, 0, 255)) } }); LayerDrawingOptions layerDrawOptions = new LayerDrawingOptions(); layerDrawOptions.LayerID = 1; layerDrawOptions.Renderer = newClassBreaksRenderer; ArcGISDynamicMapServiceLayer agslayer = MyMap.Layers["MyDynamicLayer"] as ArcGISDynamicMapServiceLayer; agslayer.LayerDrawingOptions = new LayerDrawingOptionsCollection { layerDrawOptions }; agslayer.Refresh(); } private void LayerOerder(object sender, RoutedEventArgs e) { ArcGISDynamicMapServiceLayer agslayer = MyMap.Layers["MyDynamicLayer"] as ArcGISDynamicMapServiceLayer; DynamicLayerInfoCollection myDynamicLayerInfos = agslayer.DynamicLayerInfos; if (myDynamicLayerInfos == null) myDynamicLayerInfos = agslayer.CreateDynamicLayerInfosFromLayerInfos(); var aDynamicLayerInfo = myDynamicLayerInfos[0]; myDynamicLayerInfos.RemoveAt(0); myDynamicLayerInfos.Add(aDynamicLayerInfo); agslayer.DynamicLayerInfos = myDynamicLayerInfos; agslayer.Refresh(); } private void AddShp(object sender, RoutedEventArgs e) { ArcGISDynamicMapServiceLayer agslayer = MyMap.Layers["MyDynamicLayer"] as ArcGISDynamicMapServiceLayer; agslayer.LayerDrawingOptions = null; DynamicLayerInfoCollection myDynamicLayerInfos = agslayer.DynamicLayerInfos; if (myDynamicLayerInfos == null) myDynamicLayerInfos = agslayer.CreateDynamicLayerInfosFromLayerInfos(); DynamicLayerInfo dli = new DynamicLayerInfo() { ID = 2, Source = new LayerDataSource() { DataSource = new TableDataSource() { WorkspaceID = "MyshpID", DataSourceName = "new" } } }; LayerDrawingOptions layerDrawOptions = new LayerDrawingOptions(); layerDrawOptions.LayerID = 2; layerDrawOptions.Renderer = new SimpleRenderer() { Symbol = new SimpleMarkerSymbol { Color = new SolidColorBrush(Color.FromArgb((int)255, (int)255, (int)0, (int)0)), Size = 10, Style = ESRI.ArcGIS.Client.Symbols.SimpleMarkerSymbol.SimpleMarkerStyle.Square } }; agslayer.LayerDrawingOptions = new LayerDrawingOptionsCollection() { layerDrawOptions }; myDynamicLayerInfos.Insert(0, dli); agslayer.DynamicLayerInfos = myDynamicLayerInfos; agslayer.Refresh(); } }
在ServerRender事件里面主要是通过layerDrawOptions.Renderer 为地图服务中已经存在的动态图层增加一个分级渲染器,我这里的分级指标是ObjiectID ,除此之外还可以设置唯一值渲染器,为每一个要素设置一个符号。在LayerOerder 主要是通过DynamicLayerInfos来维护图层的顺序,DynamicLayerInfos是DynamicLayerInfoCollection类型为DynamicLayerInfo的集合,每个图层对应不同的Dynamicinfo,相应的图层顺序也是与Dynamicinfo在DynamicLayerInfos中的位置一致,在AddShp 实现添加动态工作空间中的空间数据,使用DynamicLayerInfo设置数据源以及ID,通过动态服务图层的LayerDrawOption来改变新增图层的符号。
动态图层本质就是客户端告诉服务器绘制哪些图层,可以是指定工作空间的,也可以是已经发布好的图层,告诉服务器如何绘制这些图层,用什么样的渲染方式,什么样的符号,一切都是客户端告诉服务器端的,服务器端只是按照客户端的要求去生成地图而已。
同时设置新增的shp文件的符号。
运行效果如下初始状态
点击"服务端渲染"按钮
点击排序按钮,面图层已经在最上面
点击添加shp按钮
在之前的版本中,是不能实现服务内部图层的排序以及服务端渲染的,但是通过FeatureLayer可以实现不同的要素图层在前端的展示,依然可以进行分级等方式渲染,然而FeatureLayer是客户端渲染技术,他的的展示效率不高(超过3000Graphic就会有卡的感觉),我们可以通过动态图层的方式,让图层的渲染在服务端来完成,在前端通过图片(动态服务)而非Graphic的形式来实现较高效率的展示。
另外关于动态的在添加服务器端的图层,只要我们知道注册空间中要添加的图层的名字既可以实现添加了,通过GP的方式我们可以获得一个文件夹或者数据里面包括哪些图层。然后在前端获得名字之后既可以实现添加了,即是我们最初不知道注册空间里要放哪些数据。依然可以完成添加。这样我们没必要对服务中的图层修改(增加或者减少)之后重新Publish 服务。
同时呢,query操作也可以跟dynamiclayers参数,也就是说可以对动态图层进行查询。
欢迎关注我的新浪微博 http://weibo.com/u/1821556025