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 < 1)
{
RenderRegularSlice();
}
else
{
RenderSingleSlice();
}
}
}
// 只有一个数据的情况,直接创建一个圆形
private void RenderSingleSlice()
{
EllipseGeometry ellipse = new EllipseGeometry()
{
Center = new Point(0, 0),
RadiusX = _radius,
RadiusY = _radius
};
_sliceVisual.Data = ellipse;
}
// 创建扇形图形
private void RenderRegularSlice()
{
PathGeometry