前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >WPF 实现带明细的环形图表

WPF 实现带明细的环形图表

作者头像
独立观察员
发布于 2022-12-06 11:16:21
发布于 2022-12-06 11:16:21
49300
代码可运行
举报
运行总次数:0
代码可运行

本文经原作者授权以原创方式二次分享,欢迎转载、分享。 原文作者:普通的地球人 原文地址: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定位到对应圆弧合适的位置去显示(这里取的是圆弧的中间);
  • 比较抱歉的是样式比较丑陋,忽略吧,重点看定位;

圆弧部分

  • Arc有两个重要的属性:StartAngle起始角度和EndAngle终结角度.这两个属性决定了圆弧占所在圆环的比例;
  • 每一个数据项就对应一个圆弧,把所有圆弧都放到一个容器里,首尾相连;
  • 数据项的总和为100,那么所有圆弧也就组成一个完整的圆环;

Popup明细部分

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

椭圆

  • 从图可知,作为背景的椭圆分为两种情况,小于180度,椭圆靠容器的右边对齐,大于180度,靠容器的左边对齐;
  • 也就是代码的这部分;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Ellipse ell = new Ellipse() { Fill = brush }//中间点角度小于180 明细靠右显示 否则靠左显示
Grid detailGrid = new Grid() { Width = _popupHeight, HorizontalAlignment = HorizontalAlignment.Right }if (middleAngle > 180)
{
    detailGrid.HorizontalAlignment = HorizontalAlignment.Left;
}

折线

  • 折线是分为四种,每一个角度区间都对应一种;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 = 0if (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度为例,说明一些基本的东西,见图;
  • 首先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的距离;
  • Y轴 : 1、向上移动二分之一个容器的height; 2、向上移动一个Popupheight; 3、向上移动一个a的距离;

2)90-180

  • X轴 : 1、向右移动二分之一个容器的width; 2、向右移动一个a的距离;
  • Y轴 : 1、上移二分之一个圆弧的Thickness,以保证标记的起点在圆弧的中央; 2、上移一个(r-b)的距离;

3)180-270

  • X轴 : 1、向左移动一个b的距离;
  • Y轴 : 1、上移二分之一个圆弧的Thickness,以保证标记的起点在圆弧的中央; 2、上移一个(r-a)的距离;

4)270-360

  • X轴 : 1、向左移动一个a的距离;
  • Y轴 : 1、向上移动二分之一个容器的height; 2、向上移动一个Popupheight; 3、向上移动一个b的距离;
  • 代码如下;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;
}

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

源码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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 独立观察员博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
opencv实现坐标旋转(教你框住小姐姐)
最近在做一个人脸检测项目,需要接入百度AI的系统进行识别和检测。主要流程就是往指定的URL上post图片上去,之后接收检测结果就好了。
xcywt
2018/08/21
1.2K0
opencv实现坐标旋转(教你框住小姐姐)
点到直线距离 和 线段间最短距离 (OWenT 模板)
点到直线距离 // (x0,y0)到(x1,y1)和(x2,y2)确定的直线的距离 double disBetweenPointAndLine(double x0,double y0,double x1,double y1,double x2,double y2) { //化为ax+by+c=0的形式 double a = y1-y2; double b = x2-x1; double c = x1*y2-x2*y1; double d = (a*x0+b*y0+c
owent
2018/08/01
9390
浙大版《C语言程序设计(第3版)》题目集 习题3-5 三角形判断
给定平面上任意三个点的坐标(x1,y1)、(x2,y2)、(x3,y3),检验它们能否构成三角形。
C you again 的博客
2020/09/15
1K0
试题 基础练习 矩形面积交
资源限制 内存限制:512.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s 问题描述   平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴。对于每个矩形,我们给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积。 输入格式   输入仅包含两行,每行描述一个矩形。   在每行中,给出矩形的一对相对顶点的坐标,每个点的坐标都用两个绝对值不超过10^7的实数表示。 输出格式   输出仅包含一个实数,为交的面积,保留到小数后两位。 样例输入 1 1 3 3 2 2 4 4 样例输出 1.00 提交代码:
GeekLiHua
2025/01/21
440
JAVA-四元数类
public class Quaternion { private final double x0, x1, x2, x3; // 四元数构造函数 public Quaternion(double x0, double x1, double x2, double x3) { this.x0 = x0; this.x1 = x1; this.x2 = x2; this.x3 = x3; } // 转
Pulsar-V
2019/03/12
8820
矩形总面积计算器:计算两个矩形的总面积,包括重叠区域
在平面上,我们经常遇到需要计算矩形面积的情况。本文将介绍一个简单而高效的算法,通过输入两个矩形的坐标,计算它们的总面积(包括重叠区域)。
GeekLiHua
2025/01/21
880
emgucv 画圆弧「建议收藏」
emgucv中没有根据给定点画圆弧的函数,自己写了一个,在此给出该函数。其中DrawPixel函数是将圆弧中的点标记一下,需要根据自己程序里的函数具体给出。
全栈程序员站长
2022/07/22
5940
ECUST 09年 校赛个人赛第八场(最后一场)总结
这次我只AC了一题(在结束的那一刻,另一题在题目来源地网站上AC了,我们的OJ上仍然WA,我们OJ的Special Judge真是—_—!)
owent
2018/08/01
2540
HDUOJ-------Naive and Silly Muggles
Naive and Silly Muggles Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 61    Accepted Submission(s): 39 Problem Description Three wizards are doing a experiment. To avoid from bothering, a special
Gxjun
2018/03/21
6320
WPF 实现扇形统计图
扇形统计图 原文作者:ArcherSong 博客地址:https://www.cnblogs.com/ganbei/ 绘制一个扇形原理也是基于Canvas进行绘制; ArcSegment[1]绘制弧形; 绘制指示线; 绘制文本; 鼠标移入动画; 显示详情Popup; 源码Github[2] Gitee[3] 1)SectorChart.cs代码如下; using System; using System.Collections.Generic; using System.Collections.Obje
独立观察员
2022/12/06
1.4K0
WPF 实现扇形统计图
在两条直线相交处添加圆角,算法该如何实现?
然后基于圆心作两条直线的垂足得到两个点,这两个点就是圆弧起点和终点,然后确定方向就可以了。
前端西瓜哥
2024/06/17
2090
在两条直线相交处添加圆角,算法该如何实现?
2022年新年焰火代码
一、2022年新年焰火代码 本代码的所有者是海拥✘和海瞳✘ 1、2022年新年焰火用html+css+js代码写成的,非常的炫酷,想要源码,往下划。👇麻烦大家给我点个赞吧!有问题的话请私信我哦!!! <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>海拥 | 新年焰火</title> <link rel="shortcut icon" href="http://haiyong.site/wp-c
海曈
2022/11/14
6650
2022年新年焰火代码
Canvas系列(2):曲线图形
我们的代码是加在上一章最后的坐标系中的,如果直接使用arc画弧的话,那么起始点是上一个绘制的结束,也就是绘制坐标系的结束位置,为了让之前的代码的结束不在作为本次绘制的开始,我们使用了新的APIcontext.beginPath();,用来开启一个新的路径,路径相关的知识会在下一章跟大家分享。我们这里绘制了一个圆心是(150,75),半径是60,从0度到90度的弧。由上我们可以看出弧的角度是按照我们高中学的坐标系来的。所以,学习是有用的!!!
kai666666
2020/10/19
1.1K0
Canvas系列(2):曲线图形
MSRA-TD5000数据集使用详解
详情参考MSRA的官方地址:http://www.iapr-tc11.org/mediawiki/index.php/MSRA_Text_Detection_500_Database_(MSRA-TD500)
用户1154259
2018/09/21
2K0
MSRA-TD5000数据集使用详解
根据SVG Arc求出其开始角、摆动角和椭圆圆心
这时候我们通过矩阵运算得到了矩阵x1y1和矩阵cxcy,然后还有以下公式求开始角和摆动角:
ryzenWzd
2022/05/07
5760
根据SVG Arc求出其开始角、摆动角和椭圆圆心
日本yolov8用户案例演示!
这篇文章转载来自SWITCH SCIENCE的SuzukiSumiya,本篇文章转载已获作者授权。
大象机器人
2023/12/18
1900
日本yolov8用户案例演示!
很有趣的Java分形绘制
我们可以看到西兰花一小簇是整个花簇的一个分支,而在不同尺度下它们具有自相似的外形。换句话说,较小的分支通过放大适当的比例后可以得到一个与整体几乎完全一致的花簇。因此我们可以说西兰花簇是一个分形的实例。
全栈程序员站长
2022/07/14
5910
很有趣的Java分形绘制
Python PIL ImageDraw 和ImageFont模块学习
http://blog.csdn.net/dou_co/article/details/17618319
bear_fish
2018/09/19
4.3K0
Python PIL ImageDraw 和ImageFont模块学习
CORDIC算法详解(六)- CORDIC 算法的硬件实现
网上有很多类似的介绍,但是本文会结合实例进行介绍,尽量以最简单的语言进行解析。   CORDIC ( Coordinate Rotation Digital Computer ) 是坐标旋转数字计算机算法的简称, 由 Vloder• 于 1959 年在设计美国航空导航控制系统的过程中首先提出[1], 主要用于解决导航系统中三角函数、 反三角函数和开方等运算的实时计算问题。 1971 年, Walther 将圆周系统、 线性系统和双曲系统统一到一个 CORDIC 迭代方程里 , 从而提出了一种统一的CORDIC 算法形式[2]。   CORDIC 算法应用广泛, 如离散傅里叶变换 、 离散余弦变换、 离散 Hartley 变换、Chirp-Z 变换、 各种滤波以及矩阵的奇异值分解中都可应用 CORDIC 算法。 从广义上讲,CORDIC 算法提供了一种数学计算的逼近方法。 由于它最终可分解为一系列的加减和移位操作, 故非常适合硬件实现。 例如, 在工程领域可采用 CORDIC 算法实现直接数字频率合成器。 本节在阐述 CORDIC 算法三种旋转模式的基础上, 介绍了利用 CORDIC 算法计算三角函数、 反三角函数和复数求模等相关理论。 以此为依据, 阐述了基于 FPGA 的 CORDIC 算法的设计与实现及其工程应用。
碎碎思
2020/06/28
5.1K0
p5.js 光速入门
本文的目标是和各位工友一起有序的快速上手 p5.js ,会讲解 p5.js 的基础用法。
德育处主任
2022/12/07
5.3K0
p5.js 光速入门
相关推荐
opencv实现坐标旋转(教你框住小姐姐)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文