zoukankan      html  css  js  c++  java
  • 通过svg/canvas path绘制饼图(代码为c#,逻辑平台无关)

    path参数

    1. M x,y 将起点移动到指定位置
    2. L x,y 从起点绘制直线到目标位置
    3. A 20,20 0 1 0 0,1 起点 起点x,起点y 画椭圆 长轴,短轴 旋转角度 是否是优弧 正角方向绘制 终点x,终点y
    4. z 绘制闭合路径
      TIP:对应的参数均有对应的小写表示,如m,l,a
      使用小写字母的参数坐标对应起点位置的相对坐标,
      大小字母表示绝对坐标

    绘图思路

    1. 每一次移动起点到圆心
    2. 绘制对应的扇形的从圆心到圆上的某条边(长度为圆的半径)
    3. 绘制对应的圆弧
    4. 闭合路径

    需要解决的问题

    1. 计算对应的圆弧的终点(扇形的半径为圆的半径,起点为直线的终点)
    2. 将终点对应绘图的实际坐标(空间转换)

    解决思路

    1. 使用三角函数根据弧度(根据半分比通过2PI计算)、半径(已知)计算对应的x、y长度
    2. 空间转换根据实际绘图空间坐标转换
      (例左上角为0,0,水平向右和水平向下对应x,y轴正方向,此时转换需要将x加上一半的宽度(将x移动到圆心),将y轴翻转再加上一半高度)

    绘图逻辑代码

    namespace Aixueshi.ExamManagement.UserControls.CommonControl
    {
        public class PieChartViewModel
        {
            /// <summary>
            /// 绘制颜色
            /// </summary>
            //public Brush Brushes { get; set; }
    
            /// <summary>
            /// 百分比,范围[0-1]
            /// </summary>
            public double Percent { get; set; }
    
            /// <summary>
            /// 颜色
            /// </summary>
            public string Color { get; set; }
        }
        /// <summary>
        /// 饼图
        /// 设置上下文为List<PieChartViewModel>
        /// 可通过设置所有percent之和小于1来绘制纯扇形
        /// !!! 注意:需同时设置PieChart组件的容器Width、Height,否则会导致对应的宽度计算为NULL !!!
        /// </summary>
        public partial class PieChart : UserControl
        {
            double ChartWidth { get { return this.Width; } }
            double ChartHeight { get { return this.Height; } }
            double MidWidth
            {
                get
                {
                    return ChartWidth / 2;
                }
            }
            double MidHeight
            {
                get
                {
                    return ChartHeight / 2;
                }
            }
    
            //记录上一次绘图结束位置x
            double lastX;
            //记录上一次绘图结束位置y
            double lastY;
    
            double lastPercent = 0;
    
            //List<PieChartViewModel> model { get; set; }
            public PieChart()
            {
                InitializeComponent();
    
                //DataContext = model;
            }
    
            private void Clear()
            {
                canvas.Children.Clear();
                lastX = ChartWidth;
                lastY = MidHeight;
                lastPercent = 0;
            }
    
            private StringBuilder MoveMid(StringBuilder str)
            {
                return str.Append($"M {MidWidth} {MidHeight} ");
            }
            private StringBuilder AddLine(StringBuilder str)
            {
                return str.Append($"L {lastX} {lastY} ");
            }
    
    
            private void AddArc(StringBuilder str, double percent)
            {
    
    
                double x = MidWidth, y = MidHeight;
                if (lastPercent >= 0 && lastPercent < 1)
                {
                    //绘制整圆
                    if (lastPercent == 0 && lastPercent + percent >= 1)
                    {
                        str.Append($"A {MidWidth},{MidHeight} 0 0 0 {0}, {y} z ");
                        MoveMid(str);
                        str.Append($"L {0} {y} ");
                        str.Append($"A {MidWidth},{MidHeight} 0 0 0 {ChartWidth}, {y} z ");
                        return;
                    }
                    lastPercent += percent;
                    if (lastPercent > 1)
                    {
                        lastPercent = 1;
                    }
                    var arc = lastPercent * (2 * Math.PI);
                    var reletiveX = Math.Round(Math.Cos(arc) * MidWidth);
                    var reletiveY = -Math.Round(Math.Sin(arc) * MidWidth);
    
                    x += reletiveX;
                    y += reletiveY;
                    str.Append($"A {MidWidth},{MidHeight} 0 0 0 {x}, {y} z ");
    
                    //更新坐标
                    lastX = x;
                    lastY = y;
                }
                else
                {
                    if (lastPercent < 0)
                    {
    
                    }
                    else
                    {
    
                    }
                }
            }
    
            public void Add(double percent, string color)
            {
                var data = new StringBuilder();
    
                MoveMid(data);
                AddLine(data);
                AddArc(data, percent);
    
                var path = new Path();
                path.Fill = new SolidColorBrush((Color)ColorConverter.ConvertFromString(color));
                path.Data = Geometry.Parse(data.ToString());
                canvas.Children.Add(path);
            }
            int index = 0;
            SolidColorBrush randomBrush()
            {
                if (index > 3)
                {
                    index = 0;
                }
                index++;
                switch (index)
                {
                    case 1:
                        return new SolidColorBrush((Color)ColorConverter.ConvertFromString("#34E1B6"));
                    case 2:
                        return new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FB7468"));
                    case 3:
                        return Brushes.Gray;
                    default:
                        break;
                }
                return Brushes.Black;
            }
    
            private void pieChart_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
            {
                Clear();
                if (this.DataContext is List<PieChartViewModel> data)
                {
                    foreach (var item in data)
                    {
                        Add(item.Percent, item.Color);
                    }
                }
            }
        }
    }
    
    留待后查,同时方便他人
    联系我:renhanlinbsl@163.com
  • 相关阅读:
    Github 代码在线在vscode中打开
    TP5如何查询字段为空
    浏览器总是报 'https://static.hae123.cn/gc/gc3.js 错误
    Sublime 复制到word 如何保留样式?
    pdf 在浏览器中是下载,而不是打开如何实现?
    Shell脚本中的set指令,比如set -x 和 set -e【转】
    Python面向对象进阶【转】
    Redis为什么变慢了?常见延迟问题定位与分析【转】
    史上最全的 Linux Shell 文本处理工具集锦【转】
    Linux运维常用命令总结【转】
  • 原文地址:https://www.cnblogs.com/ives/p/piechart.html
Copyright © 2011-2022 走看看