WPF 实现带明细的环形图表

本文经原作者授权以原创方式二次分享,欢迎转载、分享。

原文作者:普通的地球人

原文地址:https://www.cnblogs.com/tsliwei/p/7155616.html

Github地址:https://github.com/WPFDevelopersOrg/WPFDevelopers.Charts

大体思路

  • 图表使用Arc+Popup实现;

  • 图表分为两部分,一是环形部分,一是标注的明细部分;

  • 环形部分使用Arc图形表示.需要注意这个ArcBlend里的图形.用Blend建项- 目的话可以直接用,使用VS建项目需要添加引用 Microsoft.Expression.Drawing 在引用管理器=>程序集=>扩展 下(前提是已经安装了Blend);

  • 明细部分使用Popup控件,IsOpen属性绑定到ArcIsMouseOver,也就是鼠标进入圆弧的时候,Popup就打开显示;

  • Popup内部一个椭圆控件当作背景,一个文字显示,一个折线虚线化当作指针;

  • 然后就是把Popup定位到对应圆弧合适的位置去显示(这里取的是圆弧的中间);

  • 比较抱歉的是样式比较丑陋,忽略吧,重点看定位;

f14728989b704f5003085b1c62bae3e8.png

圆弧部分

  • Arc有两个重要的属性:StartAngle起始角度和EndAngle终结角度.这两个属性决定了圆弧占所在圆环的比例;

  • 每一个数据项就对应一个圆弧,把所有圆弧都放到一个容器里,首尾相连;

  • 数据项的总和为100,那么所有圆弧也就组成一个完整的圆环;

Popup明细部分

明细部分分为四种,见图;

1aa8b21f1afcf62f680bd7acddc81985.png

椭圆

  • 从图可知,作为背景的椭圆分为两种情况,小于180度,椭圆靠容器的右边对齐,大于180度,靠容器的左边对齐;

  • 也就是代码的这部分;

Ellipse ell = new Ellipse() { Fill = brush };
//中间点角度小于180 明细靠右显示 否则靠左显示
Grid detailGrid = new Grid() { Width = _popupHeight, HorizontalAlignment = HorizontalAlignment.Right };
if (middleAngle > 180)
{
    detailGrid.HorizontalAlignment = HorizontalAlignment.Left;
}

折线

  • 折线是分为四种,每一个角度区间都对应一种;

private Polyline GetPopupPolyline(double middleAngle)
{
    Polyline pLine = new Polyline() { Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0)), StrokeDashArray = new DoubleCollection(new double[] { 5, 2 }) };
    double x1 = 0, y1 = 0;
    double x2 = 0, y2 = 0;
    double x3 = 0, y3 = 0;
    if (middleAngle > 0 && middleAngle <= 90)
    {
        x1 = 0;y1 = _popupHeight;
        x2 = _popupWidth / 2;y2 = _popupHeight;
        x3 = _popupWidth * 3 / 4;y3 = _popupHeight / 2;
    }
    if (middleAngle > 90 && middleAngle <= 180)
    {
        x1 = 0;y1 = 0;
        x2 = _popupWidth / 2;y2 = 0;
        x3 = _popupWidth * 3 / 4;y3 = _popupHeight / 2;
    }
    if (middleAngle > 180 && middleAngle <= 270)
    {
        x1 = _popupWidth;y1 = 0;
        x2 = _popupWidth / 2;y2 = 0;
        x3 = _popupWidth / 4;y3 = _popupHeight / 2;
    }
    if (middleAngle > 270 && middleAngle <= 360)
    {
        x1 = _popupWidth;y1 = _popupHeight;
        x2 = _popupWidth / 2;y2 = _popupHeight;
        x3 = _popupWidth / 4;y3 = _popupHeight / 2;
    }
    pLine.Points.Add(new Point(x1, y1));
    pLine.Points.Add(new Point(x2, y2));
    pLine.Points.Add(new Point(x3, y3));
    return pLine;
}

Popup的定位

  • 首先以0-90度为例,说明一些基本的东西,见图;

2a0ad0e205b7628ae95551c4deba9a3f.png
  • 首先Popup默认的位置,都是在它容器的左下方的,Popup的左上角和容器的左下角重合;

  • 现在要做的是Popup标记为红点的位置,和圆环上标记为红点的位置重合;

  • 先来回顾一下小时候学过的公式;

1.直角三角形 a=r*sinA

2.勾股定理 c^2=a^2+b^2 b=Sqrt(c^2-a^2)

  • 上图的直角三角形,角A的对边为a,临边为b,斜边为c.显然c边于圆的半径r相等;注意:因为圆弧是有厚度的,所以取r的时候要减去二分之一的圆弧厚度

  • A是可以通过90度减去圆弧的对应的角度求出来的,也就是sinA的值已知了,那么就可以求出ab的长度,然后就可以去移动Popup了;

1)0-90

  • X轴
    1、向右移动二分之一个容器的width
    2、向右移动一个b的距离;

34135a4462613075eaa5b31bebd73c94.png
  • Y轴
    1、向上移动二分之一个容器的height
    2、向上移动一个Popupheight
    3、向上移动一个a的距离;

5c048ef4cfe5eafd2457d7d398c17044.png

2)90-180

  • X轴
    1、向右移动二分之一个容器的width
    2、向右移动一个a的距离;

179da58e0e286c79d545becbd3b5fea8.png
  • Y轴
    1、上移二分之一个圆弧的Thickness,以保证标记的起点在圆弧的中央;
    2、上移一个(r-b)的距离;

0a9d5cc0a5977adb15b499cde8d83b41.png

3)180-270

  • X轴
    1、向左移动一个b的距离;

52015ecce1b4945a4f5eb92c4feeedec.png
  • Y轴
    1、上移二分之一个圆弧的Thickness,以保证标记的起点在圆弧的中央;
    2、上移一个(r-a)的距离;

41b28bb5f901d011af184e5b93103c29.png

4)270-360

  • X轴
    1、向左移动一个a的距离;

b05d721c2ec6d90c023535e17acd3987.png
  • Y轴
    1、向上移动二分之一个容器的height
    2、向上移动一个Popupheight
    3、向上移动一个b的距离;

b2cbf23cd0606edd8234391c20935017.png
  • 代码如下;

private Popup GetPopup(double middleAngle)
{
    /*
     * 生成popup
     * 设置popup的offset 让标记线的起点 对应到圆弧的中间点
     */
    Popup popup = new Popup() { Width = _popupWidth, Height = _popupHeight, AllowsTransparency = true, IsHitTestVisible = false };
    //直角三角形 a=r*sinA 勾股定理 c^2=a^2+b^2 b=Sqrt(c^2-a^2)
    double r = _chartSize / 2 - _arcThickness / 2;
    double offsetX = 0, offsetY = 0;
    if (middleAngle > 0 && middleAngle <= 90)
    {
        double sinA = Math.Sin(Math.PI * (90 - middleAngle) / 180);
        double a = r * sinA;
        double c = r;
        double b = Math.Sqrt(c * c - a * a);
        offsetX = _chartSize / 2 + b;
        offsetY = -(_chartSize / 2 + _popupHeight + a);
    }
    if (middleAngle > 90 && middleAngle <= 180)
    {
        double sinA = Math.Sin(Math.PI * (180 - middleAngle) / 180);
        double a = r * sinA;
        double c = r;
        double b = Math.Sqrt(c * c - a * a);
        offsetX = _chartSize / 2 + a;
        offsetY = -(_arcThickness / 2 + (r - b));
    }
    if (middleAngle > 180 && middleAngle <= 270)
    {
        double sinA = Math.Sin(Math.PI * (270 - middleAngle) / 180);
        double a = r * sinA;
        double c = r;
        double b = Math.Sqrt(c * c - a * a);
        offsetX = -_popupWidth + (r - b) + _arcThickness / 2;
        offsetY = -(_arcThickness / 2 + (r - a));
    }
    if (middleAngle > 270 && middleAngle <= 360)
    {
        double sinA = Math.Sin(Math.PI * (360 - middleAngle) / 180);
        double a = r * sinA;
        double c = r;
        double b = Math.Sqrt(c * c - a * a);
        offsetX = -_popupWidth + (r - a) + _arcThickness / 2;
        offsetY = -(_chartSize / 2 + _popupHeight + b);
    }
    popup.HorizontalOffset = offsetX;
    popup.VerticalOffset = offsetY;

    return popup;
}

差不多主要的就是这些了;
到这;
画图有点累;

e85968af144e76fc5ffad3a1231ffef8.gif

源码1[1]Gtihub[2]Gitee[3]

参考资料

[1]

源码: https://files.cnblogs.com/files/tsliwei/ArcChart.zip

[2]

Gtihub: https://github.com/WPFDevelopersOrg/WPFDevelopers.Charts

[3]

gitee: https://gitee.com/WPFDevelopersOrg/WPFDevelopers.Charts

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF(Windows Presentation Foundation)可以通过使用动画和转换效果来实现环形旋转轮动效果。首先,我们可以使用WPF中的Ellipse控件来创建一个圆形容器,然后在这个容器中放置片控件。接下来,我们可以使用WPF中的动画功能来实现片的环形旋转效果。 首先,我们可以使用DoubleAnimation来定义片旋转的动画效果。通过改变片控件的RenderTransform属性(例如RotateTransform),我们可以让片围绕圆形容器的中心点进行旋转。我们可以使用Storyboard来组织动画,并通过使用AnimateProperty属性来让片按照一定的速度和方向进行环形旋转。 另外,我们还可以使用Path类来定义片的旋转路径,通过使用PathAnimationUsingPath属性来让片沿着指定的路径进行环形旋转。在这个过程中,我们可以通过设置RepeatBehavior属性来让片循环环形旋转一定的次数或者无限循环。 此外,我们还可以通过使用触发器和事件来控制环形旋转的起始和停止。例如,我们可以通过鼠标悬停事件(MouseEnter)来触发环形旋转效果的开始,而通过鼠标离开事件(MouseLeave)来触发环形旋转效果的停止。 总体来说,利用WPF中丰富的动画和转换功能,我们可以很容易地实现片的环形旋转轮动效果。相比较于传统的WinForms等框架,WPF提供了更加灵活和强大的界面设计和动画效果实现方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值