GraphicsLayer與FeatureLayer區別 (轉自 http://xiaobaila.blog.163.com/blog/static/189705129201152711528852/)
本文內容:GraphicsLayer,FeatureLayer,自定義地圖符號。
我們的應用場景是對超市數據進行展示,查詢和分析,因此第一步當然是要將超市顯示在地圖之上。如所有的GIS軟件一樣,要將數據加載到地圖里面,需要圖層的概念,這里我們也需要合適的圖層,將超市數據加載進來。
先看一下ArcGIS API for Windows Phone/Silverlight/WPF中的主要圖層類型。 Layer
|–TiledMapServiceLayer
| |– ArcGISTiledMapServiceLayer
|–DynamicLayer
| |–DynamicMapServiceLayer
| |– ArcGISDynamicMapServiceLayer
| |–ArcGISImageServiceLayer
| |–GPResultImageLayer
|– GraphicsLayer
| |– FeatureLayer
|–ElementLayer Layer最基本的基類,常用的幾種圖層類型我已經用紅色標記出來了。前兩種ArcGISTiledMapServiceLayer和ArcGISDynamicMapServiceLayer分別用於加載ArcGIS Server發布的緩存地圖服務和動態地圖服務,這個在上一節中已經說過。再來看一下中間的GraphicsLayer和FeatureLayer,可以說這是API中最常用的兩種圖層,大部分的程序功能都要基於它們來完成。
GraphicsLayer是保留在內存中的一種圖層(與ArcMap、ArcGIS Engine、ArcGIS Server ADF程序中的相應概念類似),顧名思義是很多Graphic的集合,而所有與用戶交互的內容通常都用Graphic來顯示。比如多邊形查詢中用戶畫出的多邊形,屬性/空間查詢結果中的所有要素等內容,都是Graphic。可以說,除了地圖本身,基本上看到的所有與地理位置有關的東西都可以用Graphic來表示。Graphic對象有3個重要的屬性:Geometry,Symbol和Attributes。Geometry代表了一個Graphic的幾何形狀(可疑是點、線、面任意一種)或地理位置,而Symbol則表示Graphic的呈現樣子,比如顏色、效果,同時有了這兩個屬性(缺一不可),Graphic就可以顯示到地圖上了。而Attributes是鍵值對集合,可在里面存儲任意類型的對象,比如一個要素的屬性信息。
FeatureLayer繼承自GraphicsLayer,它與后者的區別是,GraphicsLayer中的Graphic都是人為創建出來的,而FeatureLayer中的Graphic都是從ArcGIS Server發布的服務中讀取出來的,因此FeatureLayer比GraphicsLayer多了一個URL屬性。這個URL通常指向一個ArcGIS Server發布的,MapService或FeatureService的子圖層(對應一個FeatureClass)。FeatureLayer有了這個URL后,就可以讀取出該服務對應子圖層里的所有要素內容,因此FeatureLayer里Graphic的Geometry屬性會自動被FeatureClass的Shape字段填充,而Graphic的Attributes字段則會根據要求,被FeatureClass中的屬性信息所填充。如果發布服務的服務器是ArcGIS Server 10版本,則Graphic的Symbol屬性會自動被服務的DrawingInfo信息填充。另外,FeatureLayer是客戶端API中對FeatureService的唯一載體,這是它另一個非常重要的作用(也是主要作用),以后的文章中會提到。
ArcGIS API for Windows Phone/Silverlight/WPF/Javascript/Flex/iOS/Android都是基於ArcGIS Server所發布的REST服務,所以,在開始之前,我們需要將超市數據用ArcGIS Server發布成MapService。這個過程不屬於本文要討論的內容,不熟悉的同學可自己查閱相關資料。超市圖層的屬性表如下,前面是每個店面的基本信息,后面是該月每天的營
業
額信息:
超市的ShapeFile在這,
點我下載。在我本機上發布出來的地址是:
http://localhost/ArcGIS/rest/services/supermarket/MapServer/0。
現在打開上一節我們完成的HelloMap程序,來繼續改造之。底圖服務我們依舊使用ArcGIS Online提供的StreetMap數據 http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer,然后我們在Map控件中加入一個FeatureLayer,其URL屬性指向發布在本機的超市地圖服務。由於我們的數據范圍僅限於北京市附近,因此我們可以利用Map的Extent屬性指定地圖的初始范圍,代碼現在看起來是這樣的:
1: <esri:Map x:Name="map1" Extent="12926244,4840437,12982108,4878585">
2: <esri:Map.Layers>
3: <esri:ArcGISTiledMapServiceLayer ID="BaseMap" Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
4: <esri:FeatureLayer ID="BusinessLayer"
5: Url="http://localhost/arcgis/rest/services/supermarket/MapServer/0"
6: OutFields="*" />
7: </esri:Map.Layers>
8: </esri:Map>
其中FeatureLayer的OutFields屬性代表從服務器端返回的屬性字段,這里“*”表示返回所有屬性字段,也就是我們的Graphic對象的Attributes里自動填充了超市的所有屬性值。
需要注意,在xaml代碼中,最靠上的圖層在顯示時會出現在Map控件的最底端,如圖:
Silverlight中,可以將常用的任何資源保存到Resource集合中,以便重復利用。因此我們將兩個服務地址保存到App.xaml文件的ResourceDictionary中(可在所有頁面中直接引用):
1: <Application
2: x:Class="esridemo.App"
3: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5: xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
6: xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
7: xmlns:sys="clr-namespace:System;assembly=mscorlib"
8: xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">
9:
10: <!--Application Resources-->
11: <Application.Resources>
12: <sys:String x:Key="BaseMap">http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer</sys:String>
13: <sys:String x:Key="BusinessLayer">http://localhost/arcgis/rest/services/supermarket/MapServer/0</sys:String>
14: </Application.Resources>
15:
16: <Application.ApplicationLifetimeObjects>
17: <!--Required object that handles lifetime events for the application-->
18: <shell:PhoneApplicationService
19: Launching="Application_Launching" Closing="Application_Closing"
20: Activated="Application_Activated" Deactivated="Application_Deactivated"/>
21: </Application.ApplicationLifetimeObjects>
22:
23: </Application>
將MainPage.xaml中的代碼改寫成:
1: <esri:Map x:Name="map1" Extent="12926244,4840437,12982108,4878585">
2: <esri:Map.Layers>
3: <esri:ArcGISTiledMapServiceLayer ID="BaseMap" Url="{StaticResource BaseMap}" />
4: <esri:FeatureLayer ID="BusinessLayer"
5: Url="{StaticResource BusinessLayer}"
6: OutFields="*" />
7: </esri:Map.Layers>
8: </esri:Map>
運行一下
可以看到,超市已經顯示在地圖上面了。但超市的符號依然是ArcMap配置地圖文檔時的默認值,這里我們來利用FeatureLayer的FeatureSymbol屬性,改變一下超市的地圖符號。
在App.xaml文件的資源中,添加一個MarkerSymbol類型的超市符號:
1: <esriSymbols:MarkerSymbol x:Key="SuperMarket">
2: <esriSymbols:MarkerSymbol.ControlTemplate>
3: <ControlTemplate>
4: <Canvas>
5: <VisualStateManager.VisualStateGroups>
6: <VisualStateGroup x:Name="SelectionStates">
7: <VisualState x:Name="Selected">
8: <Storyboard>
9: <Storyboard.Children>
10: <Storyboard>
11: <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.Visibility)">
12: <DiscreteObjectKeyFrame KeyTime="00:00:00">
13: <DiscreteObjectKeyFrame.Value>
14: <Visibility>Collapsed</Visibility>
15: </DiscreteObjectKeyFrame.Value>
16: </DiscreteObjectKeyFrame>
17: <DiscreteObjectKeyFrame KeyTime="00:00:00.01">
18: <DiscreteObjectKeyFrame.Value>
19: <Visibility>Visible</Visibility>
20: </DiscreteObjectKeyFrame.Value>
21: </DiscreteObjectKeyFrame>
22: </ObjectAnimationUsingKeyFrames>
23: </Storyboard>
24: <Storyboard RepeatBehavior="ForEver">
25: <DoubleAnimation BeginTime="0" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)" From="1" To="10" Duration="00:00:01" />
26: <DoubleAnimation BeginTime="0" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" From="1" To="10" Duration="00:00:01" />
27: <DoubleAnimation BeginTime="0" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.Opacity)" From="1" To="0" Duration="00:00:01" />
28: </Storyboard>
29: </Storyboard.Children>
30: </Storyboard>
31: </VisualState>
32: <VisualState x:Name="Unselected" />
33: </VisualStateGroup>
34: </VisualStateManager.VisualStateGroups>
35: <Ellipse Height="20" Width="20" Canvas.Left="-10" Canvas.Top="-10" RenderTransformOrigin="0.5,0.5" x:Name="ellipse" IsHitTestVisible="False" Visibility="Collapsed">
36: <Ellipse.RenderTransform>
37: <ScaleTransform />
38: </Ellipse.RenderTransform>
39: <Ellipse.Fill>
40: <RadialGradientBrush>
41: <GradientStop Color="#00FF0000" />
42: <GradientStop Color="#FFFF0000" Offset="0.25" />
43: <GradientStop Color="#00FF0000" Offset="0.5" />
44: <GradientStop Color="#FFFF0000" Offset="0.75" />
45: <GradientStop Color="#00FF0000" Offset="1" />
46: </RadialGradientBrush>
47: </Ellipse.Fill>
48: </Ellipse>
49: <Image Height="60" Width="60" Canvas.Left="-30" Canvas.Top="-30" Source="Images/SuperMarket.png" x:Name="ellipse1" />
50: </Canvas>
51: </ControlTemplate>
52: </esriSymbols:MarkerSymbol.ControlTemplate>
53: </esriSymbols:MarkerSymbol>
好了,已經完成了我們的准備工作。下節中,我們來完成點擊查詢(Identity)的功能。
相關鏈接:
超市信息的shapefile下載:
http://blog.newnaw.com/wp-content/uploads/2011/03/supermarket_shp.zip
Map控件中添加圖層:
http://help.arcgis.com/en/webapi/silverlight/help/0166/016600000019000000.htm
GraphicsLayer概述:
http://help.arcgis.com/en/webapi/silverlight/help/0166/01660000001q000000.htm
GraphicsLayer詳述:
http://bbs.esrichina-bj.cn/ESRI/thread-44892-1-1.html
FeatureLayer概述:
http://help.arcgis.com/en/webapi/silverlight/help/0166/016600000015000000.htm
圖層類型小結:
http://bbs.esrichina-bj.cn/ESRI/thread-45537-1-1.html
ArcGIS API for Windows Phone/Silverlight/WPF中自定義符號:
http://help.arcgis.com/en/webapi/silverlight/samples/SymbolGalleryWeb/start.htm
Silverlight中的StaticResource:
http://msdn.microsoft.com/en-us/library/cc189045(v=vs.95).aspx
我們的應用場景是對超市數據進行展示,查詢和分析,因此第一步當然是要將超市顯示在地圖之上。如所有的GIS軟件一樣,要將數據加載到地圖里面,需要圖層的概念,這里我們也需要合適的圖層,將超市數據加載進來。
先看一下ArcGIS API for Windows Phone/Silverlight/WPF中的主要圖層類型。 Layer
|–TiledMapServiceLayer
| |– ArcGISTiledMapServiceLayer
|–DynamicLayer
| |–DynamicMapServiceLayer
| |– ArcGISDynamicMapServiceLayer
| |–ArcGISImageServiceLayer
| |–GPResultImageLayer
|– GraphicsLayer
| |– FeatureLayer
|–ElementLayer Layer最基本的基類,常用的幾種圖層類型我已經用紅色標記出來了。前兩種ArcGISTiledMapServiceLayer和ArcGISDynamicMapServiceLayer分別用於加載ArcGIS Server發布的緩存地圖服務和動態地圖服務,這個在上一節中已經說過。再來看一下中間的GraphicsLayer和FeatureLayer,可以說這是API中最常用的兩種圖層,大部分的程序功能都要基於它們來完成。
GraphicsLayer是保留在內存中的一種圖層(與ArcMap、ArcGIS Engine、ArcGIS Server ADF程序中的相應概念類似),顧名思義是很多Graphic的集合,而所有與用戶交互的內容通常都用Graphic來顯示。比如多邊形查詢中用戶畫出的多邊形,屬性/空間查詢結果中的所有要素等內容,都是Graphic。可以說,除了地圖本身,基本上看到的所有與地理位置有關的東西都可以用Graphic來表示。Graphic對象有3個重要的屬性:Geometry,Symbol和Attributes。Geometry代表了一個Graphic的幾何形狀(可疑是點、線、面任意一種)或地理位置,而Symbol則表示Graphic的呈現樣子,比如顏色、效果,同時有了這兩個屬性(缺一不可),Graphic就可以顯示到地圖上了。而Attributes是鍵值對集合,可在里面存儲任意類型的對象,比如一個要素的屬性信息。
FeatureLayer繼承自GraphicsLayer,它與后者的區別是,GraphicsLayer中的Graphic都是人為創建出來的,而FeatureLayer中的Graphic都是從ArcGIS Server發布的服務中讀取出來的,因此FeatureLayer比GraphicsLayer多了一個URL屬性。這個URL通常指向一個ArcGIS Server發布的,MapService或FeatureService的子圖層(對應一個FeatureClass)。FeatureLayer有了這個URL后,就可以讀取出該服務對應子圖層里的所有要素內容,因此FeatureLayer里Graphic的Geometry屬性會自動被FeatureClass的Shape字段填充,而Graphic的Attributes字段則會根據要求,被FeatureClass中的屬性信息所填充。如果發布服務的服務器是ArcGIS Server 10版本,則Graphic的Symbol屬性會自動被服務的DrawingInfo信息填充。另外,FeatureLayer是客戶端API中對FeatureService的唯一載體,這是它另一個非常重要的作用(也是主要作用),以后的文章中會提到。
ArcGIS API for Windows Phone/Silverlight/WPF/Javascript/Flex/iOS/Android都是基於ArcGIS Server所發布的REST服務,所以,在開始之前,我們需要將超市數據用ArcGIS Server發布成MapService。這個過程不屬於本文要討論的內容,不熟悉的同學可自己查閱相關資料。超市圖層的屬性表如下,前面是每個店面的基本信息,后面是該月每天的營
業
額信息:
現在打開上一節我們完成的HelloMap程序,來繼續改造之。底圖服務我們依舊使用ArcGIS Online提供的StreetMap數據 http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer,然后我們在Map控件中加入一個FeatureLayer,其URL屬性指向發布在本機的超市地圖服務。由於我們的數據范圍僅限於北京市附近,因此我們可以利用Map的Extent屬性指定地圖的初始范圍,代碼現在看起來是這樣的:
1: <esri:Map x:Name="map1" Extent="12926244,4840437,12982108,4878585">
2: <esri:Map.Layers>
3: <esri:ArcGISTiledMapServiceLayer ID="BaseMap" Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
4: <esri:FeatureLayer ID="BusinessLayer"
5: Url="http://localhost/arcgis/rest/services/supermarket/MapServer/0"
6: OutFields="*" />
7: </esri:Map.Layers>
8: </esri:Map>
其中FeatureLayer的OutFields屬性代表從服務器端返回的屬性字段,這里“*”表示返回所有屬性字段,也就是我們的Graphic對象的Attributes里自動填充了超市的所有屬性值。
需要注意,在xaml代碼中,最靠上的圖層在顯示時會出現在Map控件的最底端,如圖:
Silverlight中,可以將常用的任何資源保存到Resource集合中,以便重復利用。因此我們將兩個服務地址保存到App.xaml文件的ResourceDictionary中(可在所有頁面中直接引用):
1: <Application
2: x:Class="esridemo.App"
3: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5: xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
6: xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
7: xmlns:sys="clr-namespace:System;assembly=mscorlib"
8: xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">
9:
10: <!--Application Resources-->
11: <Application.Resources>
12: <sys:String x:Key="BaseMap">http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer</sys:String>
13: <sys:String x:Key="BusinessLayer">http://localhost/arcgis/rest/services/supermarket/MapServer/0</sys:String>
14: </Application.Resources>
15:
16: <Application.ApplicationLifetimeObjects>
17: <!--Required object that handles lifetime events for the application-->
18: <shell:PhoneApplicationService
19: Launching="Application_Launching" Closing="Application_Closing"
20: Activated="Application_Activated" Deactivated="Application_Deactivated"/>
21: </Application.ApplicationLifetimeObjects>
22:
23: </Application>
將MainPage.xaml中的代碼改寫成:
1: <esri:Map x:Name="map1" Extent="12926244,4840437,12982108,4878585">
2: <esri:Map.Layers>
3: <esri:ArcGISTiledMapServiceLayer ID="BaseMap" Url="{StaticResource BaseMap}" />
4: <esri:FeatureLayer ID="BusinessLayer"
5: Url="{StaticResource BusinessLayer}"
6: OutFields="*" />
7: </esri:Map.Layers>
8: </esri:Map>
運行一下
可以看到,超市已經顯示在地圖上面了。但超市的符號依然是ArcMap配置地圖文檔時的默認值,這里我們來利用FeatureLayer的FeatureSymbol屬性,改變一下超市的地圖符號。
在App.xaml文件的資源中,添加一個MarkerSymbol類型的超市符號:
1: <esriSymbols:MarkerSymbol x:Key="SuperMarket">
2: <esriSymbols:MarkerSymbol.ControlTemplate>
3: <ControlTemplate>
4: <Canvas>
5: <VisualStateManager.VisualStateGroups>
6: <VisualStateGroup x:Name="SelectionStates">
7: <VisualState x:Name="Selected">
8: <Storyboard>
9: <Storyboard.Children>
10: <Storyboard>
11: <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.Visibility)">
12: <DiscreteObjectKeyFrame KeyTime="00:00:00">
13: <DiscreteObjectKeyFrame.Value>
14: <Visibility>Collapsed</Visibility>
15: </DiscreteObjectKeyFrame.Value>
16: </DiscreteObjectKeyFrame>
17: <DiscreteObjectKeyFrame KeyTime="00:00:00.01">
18: <DiscreteObjectKeyFrame.Value>
19: <Visibility>Visible</Visibility>
20: </DiscreteObjectKeyFrame.Value>
21: </DiscreteObjectKeyFrame>
22: </ObjectAnimationUsingKeyFrames>
23: </Storyboard>
24: <Storyboard RepeatBehavior="ForEver">
25: <DoubleAnimation BeginTime="0" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)" From="1" To="10" Duration="00:00:01" />
26: <DoubleAnimation BeginTime="0" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" From="1" To="10" Duration="00:00:01" />
27: <DoubleAnimation BeginTime="0" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.Opacity)" From="1" To="0" Duration="00:00:01" />
28: </Storyboard>
29: </Storyboard.Children>
30: </Storyboard>
31: </VisualState>
32: <VisualState x:Name="Unselected" />
33: </VisualStateGroup>
34: </VisualStateManager.VisualStateGroups>
35: <Ellipse Height="20" Width="20" Canvas.Left="-10" Canvas.Top="-10" RenderTransformOrigin="0.5,0.5" x:Name="ellipse" IsHitTestVisible="False" Visibility="Collapsed">
36: <Ellipse.RenderTransform>
37: <ScaleTransform />
38: </Ellipse.RenderTransform>
39: <Ellipse.Fill>
40: <RadialGradientBrush>
41: <GradientStop Color="#00FF0000" />
42: <GradientStop Color="#FFFF0000" Offset="0.25" />
43: <GradientStop Color="#00FF0000" Offset="0.5" />
44: <GradientStop Color="#FFFF0000" Offset="0.75" />
45: <GradientStop Color="#00FF0000" Offset="1" />
46: </RadialGradientBrush>
47: </Ellipse.Fill>
48: </Ellipse>
49: <Image Height="60" Width="60" Canvas.Left="-30" Canvas.Top="-30" Source="Images/SuperMarket.png" x:Name="ellipse1" />
50: </Canvas>
51: </ControlTemplate>
52: </esriSymbols:MarkerSymbol.ControlTemplate>
53: </esriSymbols:MarkerSymbol>
好了,已經完成了我們的准備工作。下節中,我們來完成點擊查詢(Identity)的功能。
相關鏈接:
超市信息的shapefile下載:
http://blog.newnaw.com/wp-content/uploads/2011/03/supermarket_shp.zip
Map控件中添加圖層:
http://help.arcgis.com/en/webapi/silverlight/help/0166/016600000019000000.htm
GraphicsLayer概述:
http://help.arcgis.com/en/webapi/silverlight/help/0166/01660000001q000000.htm
GraphicsLayer詳述:
http://bbs.esrichina-bj.cn/ESRI/thread-44892-1-1.html
FeatureLayer概述:
http://help.arcgis.com/en/webapi/silverlight/help/0166/016600000015000000.htm
圖層類型小結:
http://bbs.esrichina-bj.cn/ESRI/thread-45537-1-1.html
ArcGIS API for Windows Phone/Silverlight/WPF中自定義符號:
http://help.arcgis.com/en/webapi/silverlight/samples/SymbolGalleryWeb/start.htm
Silverlight中的StaticResource:
http://msdn.microsoft.com/en-us/library/cc189045(v=vs.95).aspx
