WPF 玫瑰图绘制
标签:基本 als ini 占用 spro dep XML sharp 数值计算
1.前言:
一直在从事CS应用程序开发工作,随着工作需求,要对部分数据进行可视化展示,UI设计稿其中就有玫瑰图、雷达图的展示。
花了一个下午回溯原来丢掉的数学知识点。。特此将实现方法记录下。
2.效果图:
3.数据对象(RadarObj)
每个图都是由一个数据集合对象组成,从而绘制出对应的效果,对象最基本的属性要有某一维度的数值,用于在图像中展示。
public class RadarObj
{
public string RColor { get; set; }
public string Name { get; set; }
public int DataValue { get; set; }
public double DataRaidus { get; set; }
///
/// Series stroke
///
public Brush Stroke
{
get
{
return new SolidColorBrush((Color)ColorConverter.ConvertFromString(RColor)); ;
}
}
///
/// Series Fill
///
public Brush Fill
{
get
{
return new SolidColorBrush((Color)ColorConverter.ConvertFromString(RColor));
}
}
}
4.绘制玫瑰图
核心逻辑在于,将玫瑰图先理解为一个饼图,然后根据数值计算出在饼图中占用的角度,以及对应的扇面半径,改动每个扇面的半径就成了玫瑰图
其中需要使用到几何的一些基本概念,工作这么多年,忘记了蛮多的,后面各种恶补。直接上代码吧。
"Painter.NightingaleRose"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Painter"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
public partial class NightingaleRose : UserControl
{
public NightingaleRose()
{
InitializeComponent();
}
#region Property
///
/// 数据
///
public List Datas
{
get { return (List)GetValue(DatasProperty); }
set { SetValue(DatasProperty, value); }
}
///
/// 数值的总数
///
public int Count
{
get
{
return Datas.Sum(i => i.DataValue);
}
}
public static readonly DependencyProperty DatasProperty = DependencyProperty.Register("Datas", typeof(List),
typeof(NightingaleRose), new PropertyMetadata(new List()));
///
/// 当前绘制大区域
///
private double MaxSize
{
get
{
var par = this.Parent as FrameworkElement;
return par.ActualHeight > par.ActualWidth ? par.ActualWidth : par.ActualHeight;
}
}
///
/// 停靠间距
///
public int RoseMargin
{
get { return (int)GetValue(RoseMarginProperty); }
set { SetValue(RoseMarginProperty, value); }
}
public static readonly DependencyProperty RoseMarginProperty = DependencyProperty.Register("RoseMargin", typeof(int),
typeof(NightingaleRose), new PropertyMetadata(50));
///
/// 空心内环半径
///
public int RoseInsideMargin
{
get { return (int)GetValue(RoseInsideMarginProperty); }
set { SetValue(RoseInsideMarginProperty, value); }
}
public static readonly DependencyProperty RoseInsideMarginProperty = DependencyProperty.Register("RoseInsideMargin", typeof(int),
typeof(NightingaleRose), new PropertyMetadata(20));
///
/// 显示值标注
///
public bool ShowValuesLabel
{
get { return (bool)GetValue(ShowValuesLabelProperty); }
set { SetValue(ShowValuesLabelProperty, value); }
}
public static readonly DependencyProperty ShowValuesLabelProperty = DependencyProperty.Register("ShowValuesLabel", typeof(bool),
typeof(NightingaleRose), new PropertyMetadata(true));
public static readonly DependencyProperty ShowToolTipProperty = DependencyProperty.Register("ShowToolTip", typeof(bool),
typeof(NightingaleRose), new PropertyMetadata(false));
///
/// 延伸线长
///
public int LabelPathLength
{
get { return (int)GetValue(LabelPathLengthProperty); }
set { SetValue(LabelPathLengthProperty, value); }
}
public static readonly DependencyProperty LabelPathLengthProperty = DependencyProperty.Register("LabelPathLength", typeof(int),
typeof(NightingaleRose), new PropertyMetadata(50));
#endregion Property
#region Method
///
/// 初始化数据
///
private void initData()
{
CanvasPanel.Children.Clear();
if (this.Datas != null && this.Datas.Count > 0)
{
this.CanvasPanel.Width = this.CanvasPanel.Height = 0;
//求角度比例尺 (每个值占多大的角度 可以算到每一块图所占的角度)
var angelScale = 360.00 / Datas.Sum(i => i.DataValue);
//最大半径
var maxRadius = (MaxSize / 2) - RoseMargin - (ShowValuesLabel ? LabelPathLength : 0);
//半径比例尺 (值和比例尺相乘等于每一块图的半径)
var radiusScale = maxRadius / Datas.Max(o => o.DataValue);
//计算半径宽度值
for (int i = 0; i
/// 初始化数据
///
///
public void SetData(object dataobj)
{
this.Datas = (dataobj) as List;
this.initData();
}
private void RadarControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
initData();
}
#endregion Method
#region Compare
///
/// 计算点位
///
///
///
///
private Point GetPoint(double radius, double angel)
{
return new Point(radius * Math.Cos(angel), radius * Math.Sin(angel));
}
private void SetLabel(RadarObj obj, Point location,double duration)
{
//计算偏移量
bool x = true;
bool y = true;
if (location.X -5 && location.X -5 && location.Y
/// 计算百分比
///
/// 总数
/// 当前项的值
/// 保留的小数点几位
///
public static string Getbfb(string zs, string tj, int num)
{
try
{
if (zs.Equals("0"))
{
return "0";
}
double bfb = (double.Parse(tj) / double.Parse(zs)) * 100;
if (bfb >= 100)
{
bfb = 100;
}
return Math.Round(bfb, num).ToString() + "%";
}
catch (Exception ex)
{
return "0%";
}
}
#endregion Compare
}
调用示例
在主窗体grid里面丢个按钮,按钮点击之后执行下列代码
private void RoseClick(object sender, RoutedEventArgs e)
{
NightingaleRose rdc = new NightingaleRose();
this.GrdMain.Children.Clear();
this.GrdMain.Children.Add(rdc);
rdc.SetData(CrData());
}
private List CrData()
{
List list = new List();
list.Add(new RadarObj() { Name="A", DataValue= rdm.Next(20,100) });
list.Add(new RadarObj() { Name = "B", DataValue = rdm.Next(20, 100) });
list.Add(new RadarObj() { Name = "C", DataValue = rdm.Next(20, 100) });
list.Add(new RadarObj() { Name = "D", DataValue = rdm.Next(20, 100) });
list.Add(new RadarObj() { Name = "E", DataValue = rdm.Next(20, 100) });
list.Add(new RadarObj() { Name = "F", DataValue = rdm.Next(20, 100) });
list.Add(new RadarObj() { Name = "F", DataValue = rdm.Next(20, 100) });
return list;
}
WPF 玫瑰图绘制
标签:基本 als ini 占用 spro dep XML sharp 数值计算
原文地址:https://www.cnblogs.com/Funk/p/11405434.html
评论