[深入浅出Windows 10]QuickCharts图表控件库解析
13.4 QuickCharts图表控件库解析
QuickCharts图表控件是Amcharts公司提供的一个开源的图表控件库,这个控件库支持WPF、Silverlight、和Windows等平台,源代码可以从Github网站上下载到(https://github.com/ailon/amCharts-Quick-Charts)。目前从Github上下载到的QuickCharts图表控件的源代码并不能直接在Windows 10上使用,但是由于都是基于XAML来创建的,所以很方便进行移植到Windows 10平台,移植的代码请参考本书的配套源代码。QuickCharts图表控件封装了一些常用的图表控件如饼图、柱形图、折线图、区域图等,可以直接在项目中进行其提供的图表控件来创建图表。使用QuickCharts图表控件来创建图表控件是比较简单的,通过设置相关的属性就可以实现一个完整的图表,这一小节主要是根据QuickCharts的源码来讲解QuickCharts项目的结构和图表控件实现的原理,同时这也是一种实现图表的很好的思路,可以给实现其他的图表控件作为一个参考。
13.4.1 QuickCharts项目结构分析
打开QuickCharts的项目可以看到QuickCharts的项目结构如图13.8所示,Themes文件夹下面存放的是图表控件和控件相关模块的XAML样式文件,Generic.xaml文件是控件的样式入口文件,所有的控件都是默认从这里来读取样式的,所以在Generic.xaml里面会通过资源字典(ResourceDictionary)的方式把其他的样式文件都加载进来。在QuickCharts项目中每个样式文件都与一个相关的控件对应起来,如PieChart.xaml样式文件对应了饼图PieChart类。控件的初始化的时候会自动到Themes/Generic.xaml这个路径下去搜素控件关联的样式的 这是一种典型的自定义控件的方式。
QuickCharts控件库里面包含了两类图表,一种是饼图图表PieChart,另外一种是连续图表SerialChart。连续图表包含了线形、柱形、区域图这些图形,因为这些图形有很多共同的特点如坐标轴,网格等,所以QuickCharts控件库把这些图形进行了统一的封装处理。
QuickCharts项目类图如图13.9和图13.10所示,主要的类和接口的说明如下:
ILegendItem接口:定义了图例基本属性。
SerialGraph抽象类:定义了连续图表图形的基本方法和属性,继承Control控件和ILegendItem接口。
AreaGraph类:实现了区域图的逻辑,继承SerialGraph类。
LineGraph类:实现了线性图的逻辑,继承SerialGraph类。
ColumnGraph类:实现了柱形图的逻辑,继承SerialGraph类。
SerialChart类:表示是连续图形图表,可以看作是AreaGraph类、LineGraph类和ColumnGraph类的容器,继承Control类。
LegendItem类:表示单条的图例记录,继承DependencyObject类和ILegendItem接口。
Legend类:表示图表的图例,继承ItemsControl类,是一个列表控件,LegendItem为其列表项的类型。
Indicator类:表示连续图表图形的标示,继承Control类。
Balloon类:表示图表弹出的数据指示框提示,继承Control类。
CategoryAxis类:表示连续图形图表的分类轴,通常为X轴,继承Control类。
ValueAxis类:表示连续图形图表的数值轴,通常为Y轴,继承Control类。
ValueGrid类:表示连续图形图表的网格,继承Control类。
Slice类:表示一块片形饼图,继承Control控件和ILegendItem接口。
PieChart类:表示饼图图表,继承Control类。
13.4.2 饼图图表PieChart的实现逻辑
在QuickCharts控件库里面饼图PieChart是由多个饼图切片Slice控件,一个图例Legend控件和一个标注Balloon控件组成。下面来看一下PieChart是怎么把这些模块组合起来实现一个饼图图表的。
(1)Slice控件的实现
文件Slice.xaml里面定义了Slice控件的样式,使用Path图形来绘图,Slice控件的形状如图所示。在Slice类里面封装了初始化的方法RenderSlice()方法,RenderSlice方法里面会根据当前的Slice图形所占的比例来实现Slice图形,如果小于1则是饼图里面的一个切片,否则则是一个完整的圆。代码如下所示:
代码清单5-4:QuickCharts控件(源代码:第5章\Examples_5_4)
- Slice.cs文件主要代码
- ------------------------------------------------------------------------------------------------------------------
- // 初始化图形
- private void RenderSlice()
- {
- if (_sliceVisual != null)
- {
- _sliceVisual.Fill = Brush;
- if (_percentage < )
- {
- RenderRegularSlice();
- }
- else
- {
- RenderSingleSlice();
- }
- }
- }
- // 只有一个数据的情况,直接创建一个圆形
- private void RenderSingleSlice()
- {
- EllipseGeometry ellipse = new EllipseGeometry()
- {
- Center = new Point(, ),
- RadiusX = _radius,
- RadiusY = _radius
- };
- _sliceVisual.Data = ellipse;
- }
- // 创建扇形图形
- private void RenderRegularSlice()
- {
- PathGeometry geometry = new PathGeometry();
- PathFigure figure = new PathFigure();
- geometry.Figures.Add(figure);
- _sliceVisual.Data = geometry;
- // 根据比例计算角度
- double endAngleRad = _percentage * * Math.PI / ;
- Point endPoint = new Point(_radius * Math.Cos(endAngleRad), _radius * Math.Sin(endAngleRad));
- // 添加直线
- figure.Segments.Add(new LineSegment() { Point = new Point(_radius, ) });
- // 添加弧线
- figure.Segments.Add(new ArcSegment()
- {
- Size = new Size(_radius, _radius),
- Point = endPoint,
- SweepDirection = SweepDirection.Clockwise,
- IsLargeArc = _percentage > 0.5
- });
- // 添加直线
- figure.Segments.Add(new LineSegment() { Point = new Point(, ) });
- }
(2)图例Legend控件的实现
图例Legend控件是通过继承ItemsControl类实现了一个列表控件,列表项是由LegendItem类组成的,在样式文件Legend.xaml上可以找到这个列表控件所实现的绑定的逻辑。LegendItem类有两个属性一个是Brush表示图形的颜色画刷,一个是Title表示图形的标题,它们跟Legend控件绑定的ItemTemplate的XAML代码如下所示:
- Legend.xaml文件主要代码
- ------------------------------------------------------------------------------------------------------------------
- <DataTemplate>
- <StackPanel Orientation="Horizontal">
- <Rectangle Fill="{Binding Brush}" Height="10" Width="10" Margin="5" />
- <TextBlock Text="{Binding Title}" VerticalAlignment="Center" />
- </StackPanel>
- </DataTemplate>
(3)标注Balloon控件的实现
Balloon控件是由Border控件和TextBlock控件组成的,用来显示图形的标注,Balloon类的Text属性则是表示标示的文本内容,XAML的语法如下:
- Balloon.xaml文件主要代码
- ------------------------------------------------------------------------------------------------------------------
- <ControlTemplate TargetType="amq:Balloon">
- <Border Background="#20000000"
- BorderBrush="{TemplateBinding BorderBrush}"
- BorderThickness="{TemplateBinding BorderThickness}"
- CornerRadius="5"
- Padding="5">
- <TextBlock Text="{TemplateBinding Text}" />
- </Border>
- </ControlTemplate>
(4)PieChart控件把Slice控件、Legend控件和Balloon控件组成饼图图表
在上面已经讲解了Slice控件、Legend控件和Balloon控件的实现方式,可以把这三个控件看作是饼图图表的三大模块,接下来PieChart控件要做的事情就是把这三者结合起来形成一个完整的饼图图表。先来看一下PieChart控件的XAML样式,分析它的UI布局。打开PieChart.xaml样式文件,可以看到如下的代码:
- PieChart.xaml文件主要代码
- ------------------------------------------------------------------------------------------------------------------
- <ControlTemplate TargetType="amq:PieChart">
- <Border Background="{TemplateBinding Background}"
- BorderBrush="{TemplateBinding BorderBrush}"
- BorderThickness="{TemplateBinding BorderThickness}"
- Padding="{TemplateBinding Padding}">
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <Border x:Name="PART_SliceCanvasDecorator" Background="Transparent">
- <Canvas x:Name="PART_SliceCanvas" />
- </Border>
- <amq:Legend x:Name="PART_Legend" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="10,0,0,0" Visibility="{TemplateBinding LegendVisibility}"/>
- <Canvas>
- <amq:Balloon x:Name="PART_Balloon"
- BorderBrush="{TemplateBinding Foreground}"
- BorderThickness="2" Visibility="Collapsed"/>
- </Canvas>
- </Grid>
- </Border>
- </ControlTemplate>
命名为PART_SliceCanvas的Canvas对象是饼图的图形面板,在该面板上会添加多个饼图切片Slice控件形成一个完成的圆形,组成一个饼图,当然如果只有一个数据的时候就只有一个Slice控件,这时候Slice控件是一个完整的圆。PieChart类里面定义的Legend对象对应样式里面的命名为PART_Legend的Legend控件,表示饼图的图例,显示在饼图图表的右上角上。PieChart类里面定义的Balloon对象对应样式里面的命名为PART_Balloon的Balloon控件,表示饼图的标示,这个Balloon控件是在一个Canvas面板的里面的,它的位置会根据用户点击的Slice控件的位置而进行改变,改变的原理是通过设置Balloon控件的Canvas.LeftProperty和Canvas.TopProperty属性来实现。
在PieChart控件里面最核心的逻辑就是对Slice控件初始化的过程了,这个过程是通过调用ProcessData()方法来初始化饼图里面所有的Slice控件,在ProcessData()方法里面先后调用了三个封装好的方法,SetData()方法、ReallocateSlices()方法和RenderSlices()方法。SetData()方法设置饼图数据属性的绑定,饼图的数据包含了标题和数值两个属性,标题是用于表示Slice控件的含义,数值是用来计算Slice控件的大小。ReallocateSlices()方法创建和初始化饼图图表里面所有的Slice控件,把Slice控件添加到PART_SliceCanvas面板上。RenderSlices()方法用于设置Slice控件在PART_SliceCanvas面板上的位置和隐藏Balloon控件,因为Balloon控件要点击了Slice控件才显示出来。
(5)使用PieChart控件
PieChart控件把相关的图形创建初始化等逻辑都封装好了,使用PieChart控件创建饼图图表只需要设置好TitleMemberPath属性和ValueMemberPath属性和数据源数据属性的对应关系,就可以把饼图图表显示出来。
XAML代码如下所示:
- PieChart.xaml文件主要代码
- ------------------------------------------------------------------------------------------------------------------
- <amq:PieChart x:Name="pie1" TitleMemberPath="title" ValueMemberPath="value"></amq:PieChart>
后台CS代码如下所示:
- PieChart.xaml.cs文件主要代码
- ------------------------------------------------------------------------------------------------------------------
- public ObservableCollection<PData> Data = new ObservableCollection<PData>()
- {
- new PData() { title = "slice #1", value = },
- new PData() { title = "slice #2", value = },
- new PData() { title = "slice #3", value = },
- new PData() { title = "slice #4", value = },
- };
- private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
- {
- // 通过DataSource属性把数据集合传递给饼图图表
- pie1.DataSource = Data;
- }
- ……省略若干代码
- // 饼图绑定的数据集合的数据类型表示饼图的一块
- public class PData
- {
- public string title { get; set; }
- public double value { get; set; }
- }
13.4.3 连续图形图表SerialChart的实现逻辑
在QuickCharts控件库里面连续图形图表SerialChart实现了三种图形,线性图LineGraph、柱形图ColumnGraph和区域图AreaGraph。可以在SerialChart图表里面显示其中一种或多种图形,因为这三种图形实现的原理是类似,都是在坐标轴上连续性地展示相关的数据,只是图形的形状不一样,所以在QuickCharts控件库里面这三种图形统一使用SerialChart控件来封装起来。先打开SerialChart控件的样式文件分析SerialChart控件的样式结构,SerialChart控件的样式文件SerialChart.xaml的主要代码如下所示:
- SerialChart.xaml文件主要代码
- ------------------------------------------------------------------------------------------------------------------
- <ControlTemplate TargetType="amq:SerialChart">
- <Border Background="{TemplateBinding Background}"
- BorderBrush="{TemplateBinding BorderBrush}"
- BorderThickness="{TemplateBinding BorderThickness}"
- Padding="{TemplateBinding Padding}">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition />
- <RowDefinition Height="Auto" />
- </Grid.RowDefinitions>
- <!--轴线 X轴 Y轴-->
- <amq:ValueAxis x:Name="PART_ValueAxis" Grid.Row="0" Margin="0,0,0,-2"
- Canvas.ZIndex="100"
- Foreground="{TemplateBinding AxisForeground}"
- HorizontalAlignment="Right"
- />
- <!--轴线上的类别-->
- <amq:CategoryAxis x:Name="PART_CategoryAxis" Grid.Row="1"
- Foreground="{TemplateBinding AxisForeground}"
- />
- <!--图表网格-->
- <Border Grid.Row="0" Background="{TemplateBinding PlotAreaBackground}">
- <amq:ValueGrid x:Name="PART_ValueGrid" Foreground="{TemplateBinding GridStroke}" />
- </Border>
- <!--图形面板-->
- <Border x:Name="PART_GraphCanvasDecorator" Grid.Row="0">
- <Canvas x:Name="PART_GraphCanvas" Background="Transparent" />
- </Border>
- <!--图例-->
- <amq:Legend x:Name="PART_Legend" Grid.Row="0"
- Margin="10,0,0,0"
- Visibility="{TemplateBinding LegendVisibility}"
- VerticalAlignment="Top" HorizontalAlignment="Left"
- />
- <!--标注-->
- <Canvas Grid.Row="0">
- <amq:Balloon x:Name="PART_Balloon"
- BorderBrush="{TemplateBinding AxisForeground}"
- BorderThickness="2"
- Visibility="Collapsed"
- />
- </Canvas>
- </Grid>
- </Border>
- </ControlTemplate>
从SerialChart控件的样式里面可以看到SerialChart控件是由数值轴控件/Y轴控件(ValueAxis)、类别轴控件/X轴控件(CategoryAxis)、图表网格控件(ValueGrid)、图形面板(Canvas面板上添加LineGraph、ColumnGraph和AreaGraph控件)、图例控件(Legend)和标注控件(Balloon)组成的。其中图例和标注控件在上一小节已经讲解了,下面看一下其他的控件的实现原理以及如何使用SerialChart控件。
(1)数值轴控件/Y轴控件(ValueAxis)和类别轴控件/X轴控件(CategoryAxis)
ValueAxis和CategoryAxis控件的实现原理是基本一样的,打开它们的样式文件可以看到,轴控件是由两个Canvas面板和一个Rectangle控件组成,命名为PART_ValuesPanel的Canvas面板是用于显示轴上的数字,命名为PART_TickPanel的Canvas面板是用于显示轴上的刻度(数值和轴之间的小线段),Rectangle控件则是用于表示轴线。Y轴(ValueAxis)采用Grid面板的ColumnDefinitions来排列,X轴(CategoryAxis)则是采用RowDefinition。
(2)图表网格控件(ValueGrid)
ValueGrid控件是由一个Canvas面板组成,在使用ValueGrid控件的时候需要通过SetLocations方法来把图表的坐标数值传递进来,然后ValueGrid控件再根据坐标的数值在Canvas面板上来创建Line线段绘制成网格。
(3)LineGraph、ColumnGraph和AreaGraph控件
LineGraph、ColumnGraph和AreaGraph控件是SerialChart图表里面最核心的图形,这三个控件的XAML样式文件都是只有一个Canvas面板,三个控件类都继承SerialGraph抽象类,SerialGraph类封装了三个控件共性的一些属性,如Locations(图表数据的点集合)、XStep(X轴的两个值的间距)等。LineGraph控件表示线性图,实现的原理是通过图表的数据点集合来创建一个Polyline图形添加到Canvas面板上。ColumnGraph控件则是使用Path来绘制柱形的形状。AreaGraph控件使用Polygon图形来绘制区域图。
(4)SerialChart控件
SerialChart控件把各大模块组成连续图形图表的原理和PieChart控件是一样的流程,只是在PieChart控件里面初始化的是Slice控件,而在SerialChart控件里面初始化的是LineGraph、ColumnGraph和AreaGraph控件。
(5)使用SerialChart控件
因为SerialChart控件是可以加载LineGraph、ColumnGraph和AreaGraph三种控件的,所以提供了一个Graphs属性,可以通过Graphs属性来添加多个图形。代码如下所示:
- SerialChart.xaml文件主要代码
- ------------------------------------------------------------------------------------------------------------------
- <amq:SerialChart x:Name="chart1" DataSource="{Binding Data}" CategoryValueMemberPath="cat1" AxisForeground="White" PlotAreaBackground="Black" GridStroke="DarkGray">
- <amq:SerialChart.Graphs>
- <amq:LineGraph ValueMemberPath="val1" Title="Line #1" Brush="Blue" />
- <amq:ColumnGraph ValueMemberPath="val2" Title="Column #2" Brush="#8000FF00" ColumnWidthAllocation="0.4" />
- <amq:AreaGraph ValueMemberPath="val3" Title="Area #1" Brush="#80FF0000" />
- </amq:SerialChart.Graphs>
- </amq:SerialChart>
- SerialChart.xaml.cs文件主要代码
- ------------------------------------------------------------------------------------------------------------------
- // 图表数据实体类
- public class TestDataItem
- {
- // cat1表示X轴的分类
- public string cat1 { get; set; }
- // 用来作为LineGraph图形的展示数据
- public double val1 { get; set; }
- // 用来作为ColumnGraph图形的展示数据
- public double val2 { get; set; }
- // 用来作为AreaGraph图形的展示数据
- public decimal val3 { get; set; }
- }
- private ObservableCollection<TestDataItem> _data = new ObservableCollection<TestDataItem>()
- {
- new TestDataItem() { cat1 = "cat1", val1=, val2=, val3=},
- new TestDataItem() { cat1 = "cat2", val1=13.2, val2=1.5, val3=2.1M},
- new TestDataItem() { cat1 = "cat3", val1=, val2=, val3=},
- new TestDataItem() { cat1 = "cat4", val1=8.1, val2=, val3=},
- new TestDataItem() { cat1 = "cat5", val1=8.1, val2=, val3=},
- new TestDataItem() { cat1 = "cat6", val1=8.1, val2=, val3=},
- };
- // 绑定的数据集合属性
- public ObservableCollection<TestDataItem> Data { get { return _data; } }
- private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
- {
- this.DataContext = this;
- }
源代码下载:http://vdisk.weibo.com/u/2186322691
目录:http://www.cnblogs.com/linzheng/p/5021428.html
欢迎关注我的微博@WP林政 微信公众号:wp开发(号:wpkaifa)
Windows10/WP技术交流群:284783431
[深入浅出Windows 10]QuickCharts图表控件库解析的更多相关文章
- [深入浅出Windows 10]分屏控件(SplitView)
4.18 分屏控件(SplitView) 分屏控件(SplitView)是Windows 10新增的控件类型,也是Windows 10通用应用程序主推的交互控件,通常和一个汉堡按钮搭配作为一种抽屉式菜 ...
- [深入浅出Windows 10]实现饼图控件
13.2 实现饼图控件 上一小节讲解了动态生成折线图和区域图,对于简单的图形这样通过C#代码来生成的方式是很方便的,但是当我们的图表要实现更加复杂的逻辑的时候,这种动态生成的方式就显得力不从心了,那就 ...
- 《深入浅出Windows 10通用应用开发》
<深入浅出Windows 10通用应用开发>采用Windows 10的SDK进行重新改版,整合了<深入浅出Windows Phone 8.1应用开发>和<深入解析 ...
- .net chart(图表)控件的使用-System.Windows.Forms.DataVisualization.dll
这个案例指在介绍微软这套免费又功能强大的图表控件Microsoft Chart Controls for Microsoft .NET Framework 3.5,通过它,可让您的项目及报表,轻松套用 ...
- Windows高DPI系列控件(二) - 柱状图
目录 一.QCP 二.效果展示 三.高DPI适配 1.自定义柱状图 2.新的柱状图 3.测试代码 四.相关文章 原文链接:Windows高DPI系列控件(二) - 柱状图 一.QCP QCP全称QCu ...
- 基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts
在我们做各种应用的时候,我们可能都会使用到图表统计,以前接触过一些不同的图表控件,在无意中发现了图表控件Highcharts,其强大的功能和丰富的互动效果,令人难以忘怀.本篇主要介绍在Web开发中使用 ...
- [深入浅出Windows 10]布局原理
5.2 布局原理 很多时候在编写程序界面的时候都会忽略了应用布局的重要性,仅仅只是把布局看作是对UI元素的排列,只要能实现布局的效果就可以了,但是在实际的产品开发中这是远远不够的,你可能面临要实现的布 ...
- [深入浅出Windows 10]不同平台设备的适配
2.3 不同平台设备的适配 Windows 10通用应用程序针对特定的平台还会有一个子API的集合,当我们要使用到某个平台的特定API的时候(比如手机相机硬件按钮触发事件),这时候就需要调用特定平台的 ...
- [深入浅出Windows 10]应用实战:Bing在线壁纸
本章介绍一个使用Bing搜索引擎背景图接口实现的一个应用——Bing在线壁纸,讲解如何使用网络的接口来实现一个壁纸下载,壁纸列表展示和网络请求封装的内容.通过该例子我们可以学习到如何使用网络编程的知识 ...
随机推荐
- ListView优化中ViewHolder要不要定义为static静态内部类?
给学生讲课的时候,发现存在这个问题,下来百度了下,发现很纠结,涉及到了内部类对外部类的引用,静态类的生命周期等java知识,现总结如下: static class ViewHolder { //定义l ...
- Delphi之DLL知识学习4---创建DLL
下面是在Delphi中创建一个DLL的全过程,你将看到怎样创建一个接口单元,使之可以被其他的应用程序访问.并且将学会怎么把Delphi的窗体加入DLL中. 一.数美分:一个简单的DLL 下面是包含一个 ...
- 攻城狮在路上(叁)Linux(二十六)--- linux文件系统的特殊查看与操作
一.boot sector 与 super block的关系: 1.boot sector用于存放引导装载程序,占用1024个字节. 2.super block的大小也为1024字节. 3.若bloc ...
- PHP不同域名cookie共享(单点登录实现原理)
PHP使用P3P完成COOKIE跨域操作实际实用中,类似的需求有,比如说我们有两个域名,我们想实现在一个域名登录后,能自动完成另一个域名的登录,也就是单点登录(SSO)功能.为了测试的方便,先编辑ho ...
- NBU官方Doc網址https://www.veritas.com/support/en_US/article.DOC5332
NBU(NetBackup) 7.0之後的版本官方文檔鏈接地址: https://www.veritas.com/support/en_US/article.DOC5332
- android 入门-android Studio 解决方案
一.当提示 解决方案: 1. 2. 二.从这步到这步 的时候,可能遇见下面的问题. 解决方案: 更新一下build-tools 19.1.0版本 放到你的sdk里并重启as. 三. 当遇见这样的情况 ...
- Sizeof与Strlen的区别与联系
转自:http://www.cnblogs.com/carekee/articles/1630789.html 一.sizeof sizeof(...)是运算符,在头文件中typedef为uns ...
- 解释一下SQLSERVER事务日志记录
解释一下SQLSERVER事务日志记录 大家知道在完整恢复模式下,SQLSERVER会记录每个事务所做的操作,这些记录会存储在事务日志里,有些软件会利用事务日志来读取 操作记录恢复数据,例如:log ...
- 用Feature的方式删除SharePoint2010的Page中重复的WebPart
用Feature的方式删除SharePoint2010的Page中重复的WebPart. 代码如下所示: public class SupportCenterDuplicatedWebpartRemo ...
- wpf textblock 会覆盖 button里面字体样式的解决方法 还有button的style覆盖。。datepicker里面的按钮的style
.(button使用contont写的时候) 当.button使用 <button.content><textBlock/></button.content>依然会 ...