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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/286386.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL Server 2008 R2 安装时提示“Reporting Services目录数据库文件存在”

打开MSSQL数据库管理系统的安装目录&#xff0c;例如&#xff1a; X:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA。 其中 X:\是你安装MS SQL数据库管理系统实例所在的盘符. 删除 X:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DA…

C语言试题九之s=(ln(1)+ln(2)+ln(3)+…+ln(m))^0.5,s作为函数值返回

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、 题目 计算:s=…

几行代码搞定树形文本转XML和JSON

由于需要将百度脑图的内容导出为xml或者json格式&#xff0c;发现百度脑图只能导出为树形文本&#xff0c;所以就写了个小应用给编辑用。/// <summary>/// 树形文本转xml/// </summary>/// <param name"txt"></param>/// <returns><…

2019年ESRI技术公开课(19集视频全)

1. 视频合集简介 本视频合集为2019版ESRI技术公开视频课&#xff0c;共19集全&#xff0c;主要内容包括ArcGIS、ENVI、大数据、Python应用、大数据、点云场景、三维模型、地理建模、椭球面积、深度学习技术等。 2. 视频合集目录 2019年Esri技术公开课&#xff08;1&#xff09;…

VSAN见证虚拟设备

VSAN 6.1发布了也有两三个月了&#xff0c;其中有2个比较显著的新特性&#xff0c;一个就是支持Stretched Cluster, 也就是说你的VSAN集群现在可以不在一个物理位置了&#xff0c;可以跨数据中心部署了&#xff1b;另外一个就是2节点VSAN。我们知道&#xff0c;原来的VSAN至少需…

《iVX 高仿美团APP制作移动端完整项目》01 标题需求分析思路及制作流程

点击整个专栏查看其它系列文章 &#xff08;系列文章更新中…&#xff09;&#xff1a;《iVX 高仿美团APP制作移动端完整项目》 项目界面预览&#xff1a; 一、创建项目 首先打开在线编辑器地址&#xff1a;https://editor.ivx.cn/ 随后登录帐号后创建一个相对应用项目&…

zepto源码研究 - ajax.js($.ajaxJSONP 的分析)

简要&#xff1a;jsonp是一种服务器和客户端信息传递方式&#xff0c;一般是利用script元素赋值src来发起请求。一般凡是带有src属性的元素发起的请求都是可以跨域的。 那么jsonp是如何获取服务器的数据的呢&#xff1f; jsonp先将指定的一个函数名作为url后面的参数传递到服务…

C语言试题十之将两个两位数的正整数a b合并形成一个整数放在c中。合并的方式是:将a数的十位和个位数依次放在c的十位和千位上,b数的十位和个位数依次放在c数的个位和百位上。

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、 题目 请编写函…

Blazor University (27)路由 —— 检测导航事件

原文链接&#xff1a;https://blazor-university.com/routing/detecting-navigation-events/检测导航事件源代码[1]从 Blazor 访问浏览器导航是通过 NavigationManager 服务提供的。这可以使用 razor 文件中的 inject 或 CS 文件中的 [Inject] 属性注入到 Blazor 组件中。Locat…

创建 overlay 网络 - 每天5分钟玩转 Docker 容器技术(50)

上一节我们搭建好实验环境&#xff0c;配置并运行了consul&#xff0c;今天开始创建 overlay 网络。 在 host1 中创建 overlay 网络 ov_net1&#xff1a; -d overlay 指定 driver 为 overaly。 docker network ls 查看当前网络&#xff1a; 注意到 ov_net1 的 SCOPE 为 global&…

Js+Css 控制iframe内容自动缩放

竖屏横屏效果<div class"h5box"> <iframe src"http://player.youku.com/embed/XMTI4MjU5OTA3Mg" frameborder"0" width"1280px" height"720px"></iframe> </div><script type"tex…

西北冬日的校园很静谧,却不失韵味,因为有我们美好的青春!

冬日的校园&#xff0c;从枯黄的落叶开始。。。 落叶与栅栏情深。 冬日的篮球场上&#xff0c;不乏挥汗如雨的你&#xff0c;因为你是梦想与自由的追逐者&#xff0c;你可以战胜自己的懒惰。 我们的测量实训场&#xff0c;英雄的用武之地。 测桩&#xff1a;测量的控制点&#…

ps、top 、free查看用户资源信息

查看root用户的进程信息。 运行命令&#xff1a; ps -u root 查看oracle用户的进程信息。 运行命令&#xff1a; ps -u oracle 若查看现在的资源占用情况&#xff0c;如何呢&#xff1f; 运行命令&#xff1a; top 可以很详细的查看各个进程的运行情况。 若查看内存使用情…

《iVX 高仿美团APP制作移动端完整项目》02 搜索、搜索提示及类别需求分析思路及制作流程

点击整个专栏查看其它系列文章 &#xff08;系列文章更新中…&#xff09;&#xff1a;《iVX 高仿美团APP制作移动端完整项目》 项目界面预览&#xff1a; 一、搜索制作 在上一节中我们完成了标题头的制作&#xff0c;接下来我们查看如何制作搜索栏以及分类区制作。 首先我…

C语言试题十一之计算并输出下列多项式值:sn=(1-1/2)+(1/3-1/4)+…+(1/(2n-1)1/2n).

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、 题目 请编写函…

C#封装FluentValidation,用了之后通篇还是AbstractValidator,真的看不下去了

讲故事前几天看公司一个新项目使用了FluentValidation&#xff0c;大家都知道FluentValidation是一个非常强大的用于构建强类型验证规则的 .NET 框架&#xff0c;帮程序员解决了繁琐的校验问题&#xff0c;用起来非常爽&#xff0c;但我还是遇到了一件非常不爽的事情,如下代码所…

用批处理修复 win10 无法升级的问题

win10无法升级&#xff0c;通常的做法是先停止windows update 服务&#xff0c;删除临时缓存升级目录&#xff0c;重新启动升级服务。 写成一个批处理文件&#xff0c;直接用管理员身份运行一下就搞定。echo offfor /f "skip3 tokens4" %%i in (sc query wuauserv) d…

http304状态码缓存设置问题

当浏览器第一次加载资源的时候&#xff0c;返回一般为200&#xff0c;意思是成功获取资源&#xff0c;并会在浏览器的缓存中记录下max-age&#xff0c;第二次访问的时候&#xff1a;如果只是用浏览器打开&#xff0c;那么浏览器会去判断这个资源在缓存里有没有&#xff0c;如果…

10.2.0.5启动enterprise manager

10.2.0.5启动enterprise manager OEM作为一个实用工具&#xff0c;随着10g和11g的普及&#xff0c;OEM功能越来越强大&#xff0c;oem也应用越来越广泛。但是如果是10.2.0.5的版本&#xff0c;并且安装时间在2010年1月之后&#xff0c;可能会遇到OEM无法启动的情况&#xff0c;…

【数据结构与算法】多种语言(VB、C、C#、JavaScript)系列数据结构算法经典案例教程合集目录

文章目录1. 专栏简介2. 专栏地址3. 专栏目录1. 专栏简介 2. 专栏地址 「 刘一哥与GIS的故事 」之《数据结构与算法》 3. 专栏目录 【经典回放】多种语言系列数据结构算法&#xff1a;二叉树&#xff08;JavaScript版&#xff09;【经典回放】多种语言系列数据结构算法&#…