WPF 玫瑰图绘制

2021-02-06 22:17

阅读:509

标签:基本   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">
    "CanvasPanel" HorizontalAlignment="Center" VerticalAlignment="Center" Background="Gray" >
        
 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


评论


亲,登录后才可以留言!