• 使用Visifire+ArcGIS API for Silverlight实现Graphic信息的动态图表显示


      首先来看一看实现的效果:
     
    PS:原始的程序中更新曲线数据时添加了过渡的效果,具体可查看官网的示例:
    点击其中的一个例子,然后点击Live Updates,就可看到数据更新时的过渡效果。但是蛋疼的博客园,不知道为什么,我插入了我原始的xap文件,过渡效果却没有了,每次更新数据时,曲线直接就出来了(中间没有过渡行为),开始的时候以为是上传后xap文件有可能发生了变化,或者进行压缩什么的,或者浏览器解析什么的,于是我把上传到博客园的xap文件又下载下来,然后嵌入到一个htm页面中,发现还是有过度效果的,但是为什么在博客园的日志中就没有呢?整了好久还是没有整明白,求解释!
     
    下面来看看具体实现的过程吧:
    首先需要添加SLVisifire.Charts,FJ.Core的引用。然后开始我们正式的工作:
    1.定义一个Chart,该Chart即为显示的图表,以及定义一个Timer,用于定时刷新数据。
     Chart chart;                                                Random rand = new Random(DateTime.Now.Millisecond);             System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
    2.定义一个方法:CreateChart实例化Chart,并完成Chart的相关设置(如:高,宽,曲线样式等等)
    0
            ///  /// Function to create a Visifire Chart ///  public void CreateChart()         { try { // Create a new instance of a Chart chart = new Chart(); //添加X,Y坐标的描述 Axis axisX = new Axis()                 {                     Title = "月份",                     FontSize = 18,                 };                 chart.AxesX.Add(axisX);                 Axis axisY = new Axis()                 {                     Title = "实时监测值",                     FontSize = 16,                 };                 chart.AxesY.Add(axisY); // 设置图表的高宽 chart.Width = 640;                 chart.Height = 300; //Line数据更新时的过渡效果 chart.AnimatedUpdate = true; // 定义DatatSeries实例,即一条曲线 DataSeries dataSeries1 = new DataSeries();                 DataSeries dataSeries2 = new DataSeries(); //只有当Series的个数大于等于2个时Lenged才会生效 dataSeries1.LegendText = "CO2";                 dataSeries2.LegendText = "SO2"; // 设置DataSeries样式 dataSeries1.RenderAs = RenderAs.Spline;                 dataSeries2.RenderAs = RenderAs.Spline; // 定义数据点  DataPoint dataPoint1;                 DataPoint dataPoint2; for (int i = 1; i <= 12; i++)                 { // 实例化数据点 dataPoint1= new DataPoint();                     dataPoint2 = new DataPoint(); //设置数据值 dataPoint1.YValue = rand.Next(0, 99);                     dataPoint2.YValue = rand.Next(0, 99); //设置X轴显示名称 dataPoint1.AxisXLabel = string.Format("{0} 月", i);                     dataPoint2.AxisXLabel = string.Format("{0} 月", i); // 添加数据点  dataSeries1.DataPoints.Add(dataPoint1);                     dataSeries2.DataPoints.Add(dataPoint2);                 } // 将DataSeries(曲线)添加到Chart中  chart.Series.Add(dataSeries1);                 chart.Series.Add(dataSeries2); // 注册Chart Loaded事件,在该事件中设置Timer的间断值及注册Timer Tick事件 chart.Loaded += new RoutedEventHandler(chart_Loaded);             } catch (Exception ex)             {                 MessageBox.Show(ex.ToString());             }         }
    0
    3.我们看到在创建Chart中注册了Loaded事件,在该事件的完成函数我们设置Timer的间断值及注册Timer Tick事件
         void chart_Loaded(object sender, RoutedEventArgs e)         {             timer.Tick += new EventHandler(timer_Tick);             timer.Interval = new TimeSpan(0, 0, 0, 0, 2000);         }
    0
            ///  /// Event handler for Tick event of Dispatcher Timer ///  /// System.Windows.Threading.DispatcherTimer /// EventArgs void timer_Tick(object sender, EventArgs e)         { for (Int32 i = 0; i < 12; i++)             { // 更新曲线数据 chart.Series[0].DataPoints[i].YValue = rand.Next(0, 99);                  chart.Series[1].DataPoints[i].YValue = rand.Next(20, 80);              }         }
    0
    4.这里我们再写一个方法:AddChartToMapLayer,该方法用来将Chart添加到地图中
    0
            ///  /// Add Chart to Map ///  /// Chart /// Position public void AddChartToMapLayer(Chart chart, Graphic position)         {             ElementLayer chartlayer = new ElementLayer();             chartlayer.ID = "ChartLayer";             chartlayer.Opacity = 1; if (Map.Layers["ChartLayer"] != null)             {                 Map.Layers.Remove(Map.Layers["ChartLayer"]);             }             chart.Titles.Add(new Title()             {                 Text=string.Format("City: {0}",position.Attributes["CITY_NAME"].ToString ())             }); //获得Graphic的中心坐标 ESRI.ArcGIS.Client.Geometry.Geometry geometry=position.Geometry;             MapPoint mapPoint=new MapPoint ((geometry.Extent.XMax+geometry.Extent.XMin)/2,(geometry.Extent.YMax+geometry.Extent.YMin)/2); //获得图层X,Y方向对应的比例 double cell_X = (Map.Extent.XMax - Map.Extent.XMin) / Map.ActualWidth; double cell_Y = (Map.Extent.YMax - Map.Extent.YMin) / Map.ActualHeight; //Chart的宽度为500所以,Chart的中心则位于宽度等于250的位置,将Chart向右移动,以防Chart覆盖Graphic Envelope extent = new Envelope(mapPoint.X + (320 + 20) * cell_X, mapPoint.Y, mapPoint.X + (320 + 20) * cell_X, mapPoint.Y); //设置ElementLayer的外包范围  ElementLayer.SetEnvelope(chart, extent);             chartlayer.Children.Add(chart);             Map.Layers.Add(chartlayer);         }
    0
    现在准备工作已经完成,下面就调用这些方法来实现上述的功能,我们大体的功能过程是:
    当鼠标移入Graphic是就显示其对应的Chart,移除的移除Chart,这里我们注册一下FeatureLayer的MouseEnter和MouseLeave事件就行,我们再后台的XAML中注册这两个事件。
    0
         <esri:FeatureLayer ID="MyFeatureLayer" Url="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer/0" Where="POP1990 > 500000" MouseEnter="FeatureLayer_MouseEnter" MouseLeave="FeatureLayer_MouseLeave" Renderer="{StaticResource MySimplePointRenderer}"/>
    0
    最后在后台添加如下代码:
    0
       private void FeatureLayer_MouseEnter(object sender, GraphicMouseEventArgs e)         { //绘制Chart  CreateChart(); //将Chart添加到Map  AddChartToMapLayer(chart, e.Graphic); //启动Timer,定时刷新数据  timer.Start();         } private void FeatureLayer_MouseLeave(object sender, GraphicMouseEventArgs e)         { //停止Timer  timer.Stop(); //移除ElementLayer if (Map.Layers["ChartLayer"] != null)             {                 Map.Layers.Remove(Map.Layers["ChartLayer"]);             }         }
    0
    后台的XAML代码:
    <UserControl x:Class="SilverlightChartDemo.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vc="clr-namespace:Visifire.Charts;assembly=SLVisifire.Charts" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" xmlns:esri="http://schemas.esri.com/arcgis/client/2009"> <Grid x:Name="LayoutRoot" Background="White"> <Grid.Resources> <esri:SimpleRenderer x:Key="MySimplePointRenderer"> <esri:SimpleRenderer.Symbol> <esri:SimpleMarkerSymbol Size="15" Style="Circle"> <esri:SimpleMarkerSymbol.ControlTemplate> <ControlTemplate> <Grid x:Name="RootElement" RenderTransformOrigin="0.5,0.5" Width="15" Height="15"> <Grid.RenderTransform> <ScaleTransform x:Name="customEnlargeRotatingMarkerSymbolScale" ScaleX="1" ScaleY="1" /> </Grid.RenderTransform> <Grid.Resources> <DropShadowEffect x:Key="customEnlargeRotatingMarkerSymbolEffect" /> </Grid.Resources> <vsm:VisualStateManager.VisualStateGroups> <vsm:VisualStateGroup x:Name="CommonStates"> <vsm:VisualState x:Name="Normal"> <Storyboard> <DoubleAnimation BeginTime="00:00:00" Storyboard.TargetName="customEnlargeRotatingMarkerSymbolScale" Storyboard.TargetProperty="ScaleX" To="1" Duration="0:0:0.2" /> <DoubleAnimation BeginTime="00:00:00" Storyboard.TargetName="customEnlargeRotatingMarkerSymbolScale" Storyboard.TargetProperty="ScaleY" To="1" Duration="0:0:0.2" /> <DoubleAnimation BeginTime="00:00:00" Storyboard.TargetName="customEnlargeRotatingMarkerSymbolRotate" Storyboard.TargetProperty="Angle" To="360" Duration="0:0:0.2" /> <DoubleAnimation BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.ShadowDepth)" To="2" Duration="0:0:0.2" /> </Storyboard> </vsm:VisualState> <vsm:VisualState x:Name="MouseOver"> <Storyboard> <DoubleAnimation BeginTime="00:00:00" Storyboard.TargetName="customEnlargeRotatingMarkerSymbolScale" Storyboard.TargetProperty="ScaleX" To="2" Duration="0:0:0.2" /> <DoubleAnimation BeginTime="00:00:00" Storyboard.TargetName="customEnlargeRotatingMarkerSymbolScale" Storyboard.TargetProperty="ScaleY" To="2" Duration="0:0:0.2" /> <DoubleAnimation BeginTime="00:00:00" Storyboard.TargetName="customEnlargeRotatingMarkerSymbolRotate" Storyboard.TargetProperty="Angle" To="0" Duration="0:0:0.2" /> <DoubleAnimation BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.ShadowDepth)" To="5" Duration="0:0:0.2" /> </Storyboard> </vsm:VisualState> </vsm:VisualStateGroup> </vsm:VisualStateManager.VisualStateGroups> <Ellipse x:Name="ellipse" Width="15" Height="15" Fill="Green" Stroke="White" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Effect="{StaticResource customEnlargeRotatingMarkerSymbolEffect}"></Ellipse> <Canvas x:Name="RotateCanvas" HorizontalAlignment="Left" VerticalAlignment="Top" Width="15" Height="15" RenderTransformOrigin="0.5,0.5"> <Canvas.Clip> <EllipseGeometry RadiusX="7.5" RadiusY="7.5" Center="7.5,7.5" /> </Canvas.Clip> <Canvas.RenderTransform> <RotateTransform x:Name="customEnlargeRotatingMarkerSymbolRotate" Angle="360" /> </Canvas.RenderTransform> <Line Stroke="White" StrokeThickness="2" X1="0" Y1="0" X2="15" Y2="15" /> <Line Stroke="White" StrokeThickness="2" X1="0" Y1="15" X2="15" Y2="0" /> </Canvas> </Grid> </ControlTemplate> </esri:SimpleMarkerSymbol.ControlTemplate> </esri:SimpleMarkerSymbol> </esri:SimpleRenderer.Symbol> </esri:SimpleRenderer> </Grid.Resources> <esri:Map Background="White" HorizontalAlignment="Stretch" Margin="0" Grid.ColumnSpan="3" Name="Map" VerticalAlignment="Stretch" WrapAround="True" Extent="-15000000,2000000,-7000000,8000000"> <esri:Map.Layers> <esri:LayerCollection> <esri:ArcGISTiledMapServiceLayer Url="http://www.arcgisonline.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer" /> <esri:FeatureLayer ID="MyFeatureLayer" Url="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer/0" Where="POP1990 > 500000" MouseEnter="FeatureLayer_MouseEnter" MouseLeave="FeatureLayer_MouseLeave" Renderer="{StaticResource MySimplePointRenderer}"/> </esri:LayerCollection> </esri:Map.Layers> </esri:Map> </Grid> </UserControl>
     
    这样我们便实现了上述的效果。
     
    需要注意的几点:
    1.Chart控件第一次加载数据的动画效果(一个点一个点添加),只能使用一次,也就是实例化Chart,加载数据时会有这样的效果,之后更新Chart控件的数据不会有类似第一次加载Chart时显示曲线动画效果,而是上面说的过渡效果。
    2.注意设置Chart的AnimatedUpdate属性为True,否则数据更新时绘制曲线没有过渡的效果
    3.将Chart作为ElementLayer添加到地图中,注意设置ElementLayer的显示位置。
     
     总结:
     以上的过程数据都是用Timer组件来定时生成的,当然这里也可以扩展,比如你的数据也可以是通过SQL查询得到。此外,本例没有用到数据绑定,这是因为本文的Chart是动态生成的,每次选择Graphic时都会重新生成Chart.所以没有用数据绑定。当然如果你的Chart是写死的(实例化一次),或者定义在后台的xaml中,那么建议您选择数据绑定的方式,数据绑定的方式也很简单,例如在XAML定义如下的Chart(详见Visifire documentation):
     
    <vc:Chart Name="MyChart" Width="500" Height="300" Theme="Theme1"> <vc:Chart.Series> <vc:DataSeries RenderAs="Column" DataSource="{Binding}"> <vc:DataSeries.DataMappings> <vc:DataMapping MemberName="XValue" Path="Key">vc:DataMapping> <vc:DataMapping MemberName="YValue" Path="Value">vc:DataMapping> vc:DataSeries.DataMappings> vc:DataSeries> vc:Chart.Series> vc:Chart>
     
    在后台添加如下代码:
     
    public partial class Page : UserControl { public Page()     {         InitializeComponent(); for (int i = 0; i < 10; i++)         {             values.Add(new KeyValuePair<double,double>(i, i + 1));         }                      MyChart.DataContext = values;     }     Random rand = new Random();     ObservableCollection<keyvaluepair<double, double>> values = new ObservableCollection<keyvaluepair<< span="">double, double>>(); }
     
    这样便可以实现Chart曲线的数据绑定。
    PS:有那么一段时间没有用Visifire了,很多又忘记了,以上算是自己的一个总结,同时很多人也问个类似的效果怎么做,在此和大家分享一下,鉴于时间和知识的关系,疏漏和错误在所难免,还望各位指正。
     //关于解决地图缩放时Chart偏移的问题。
    1.注册Map的ExtentChanging事件,然后在事件完成函数中重新设定Elmentlayer的Envelop,代码如下:
     
            private void Map_ExtentChanging(object sender, ExtentEventArgs e)         { double cell_X = (Map.Extent.XMax - Map.Extent.XMin) / Map.ActualWidth;             ESRI.ArcGIS.Client.Geometry.Geometry geometry = selectedGraphic.Geometry;             MapPoint mapPoint = new MapPoint((geometry.Extent.XMax + geometry.Extent.XMin) / 2, (geometry.Extent.YMax + geometry.Extent.YMin) / 2);             Envelope extent = new Envelope(mapPoint.X + (320 + 20) * cell_X, mapPoint.Y, mapPoint.X + (320 + 20) * cell_X, mapPoint.Y);             Chart Mychart = chartlayer.Children[0] as Chart;             ElementLayer.SetEnvelope(Mychart, extent);         }
     
  • 相关阅读:
    string
    auto和decltype
    const限定符
    &(引用) 和 *(指针)
    extern关键字
    关于将函数写入头文件问题(分离式编译)
    poj2154(polya定理+欧拉函数)
    bzoj2115(线性基)
    51nod1832(二叉树/高精度模板+dfs)
    51nod1464(trie + dfs)
  • 原文地址:https://www.cnblogs.com/devgis/p/16531129.html
Copyright © 2020-2023  润新知