WPF制作带明细的环形图标
效果
明细用Popup实现的,录gif时,Popup显示不出来,不知道为什么,所以静态图凑合看吧

大体思路
图表使用Arc+Popup实现
图表分为两部分,一是环形部分,一是标注的明细部分.
环形部分使用Arc图形表示.需要注意这个Arc是Blend里的图形.用Blend建项目的话可以直接用,使用VS建项目需要添加引用 Microsoft.Expression.Drawing 在引用管理器=>程序集=>扩展 下(前提是已经安装了Blend)
明细部分使用Popup控件,IsOpen属性绑定到Arc的IsMouseOver,也就是鼠标进入圆弧的时候,Popup就打开显示.
Popup内部一个椭圆控件当作背景,一个文字显示,一个折线虚线化当作指针
然后就是把Popup定位到对应圆弧合适的位置去显示(这里取的是圆弧的中间)
比较抱歉的是样式比较丑陋,忽略吧,重点看定位.
圆弧部分
Arc有两个重要的属性:StartAngle起始角度和EndAngle终结角度.这两个属性决定了圆弧占所在圆环的比例.
每一个数据项就对应一个圆弧,把所有圆弧都放到一个容器里,首尾相连
数据项的总和为100,那么所有圆弧也就组成一个完整的圆环.
Popup明细部分
明细部分分为四种,见图

椭圆
从图可知,作为背景的椭圆分为两种情况,小于180度,椭圆靠容器的右边对齐,大于180度,靠容器的左边对齐
也就是代码的这部分:
Ellipse ell = new Ellipse() { Fill = brush };
//中间点角度小于180 明细靠右显示 否则靠左显示
Grid detailGrid = new Grid() { Width = _popupHeight, HorizontalAlignment = HorizontalAlignment.Right };
if (middleAngle > )
{
detailGrid.HorizontalAlignment = HorizontalAlignment.Left;
}
折线
折线是分为四种,每一个角度区间都对应一种
private Polyline GetPopupPolyline(double middleAngle)
{
Polyline pLine = new Polyline() { Stroke = new SolidColorBrush(Color.FromRgb(, , )), StrokeDashArray = new DoubleCollection(new double[] { , }) };
double x1 = , y1 = ;
double x2 = , y2 = ;
double x3 = , y3 = ;
if (middleAngle > && middleAngle <= )
{
x1 = ; y1 = _popupHeight;
x2 = _popupWidth / ; y2 = _popupHeight;
x3 = _popupWidth * / ; y3 = _popupHeight / ;
}
if (middleAngle > && middleAngle <= )
{
x1 = ; y1 = ;
x2 = _popupWidth / ; y2 = ;
x3 = _popupWidth * / ; y3 = _popupHeight / ;
}
if (middleAngle > && middleAngle <= )
{
x1 = _popupWidth; y1 = ;
x2 = _popupWidth / ; y2 = ;
x3 = _popupWidth / ; y3 = _popupHeight / ;
}
if (middleAngle > && middleAngle <= )
{
x1 = _popupWidth; y1 = _popupHeight;
x2 = _popupWidth / ; y2 = _popupHeight;
x3 = _popupWidth / ; y3 = _popupHeight / ;
}
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的值已知了,那么就可以求出a和b的长度,然后就可以去移动Popup了
一.0-90度
X轴:1.向右移动二分之一个容器的width 2.向右移动一个b的距离

Y轴:1.向上移动二分之一个容器的height 2.向上移动一个Popup的height 3.向上移动一个a的距离

二.90-180度
X轴:1.向右移动二分之一个容器的width 2.向右移动一个a的距离

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

三.180-270度
X轴:1.向左移动一个b的距离

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

四.270-360度
X轴:1.向左移动一个a的距离

Y轴:1.向上移动二分之一个容器的height 2.向上移动一个Popup的height 3.向上移动一个b的距离

代码部分
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 / - _arcThickness / ;
double offsetX = , offsetY = ;
if (middleAngle > && middleAngle <= )
{
double sinA = Math.Sin(Math.PI * ( - middleAngle) / );
double a = r * sinA;
double c = r;
double b = Math.Sqrt(c * c - a * a);
offsetX = _chartSize / + b;
offsetY = -(_chartSize / + _popupHeight + a);
}
if (middleAngle > && middleAngle <= )
{
double sinA = Math.Sin(Math.PI * ( - middleAngle) / );
double a = r * sinA;
double c = r;
double b = Math.Sqrt(c * c - a * a);
offsetX = _chartSize / + a;
offsetY = -(_arcThickness / + (r - b));
}
if (middleAngle > && middleAngle <= )
{
double sinA = Math.Sin(Math.PI * ( - middleAngle) / );
double a = r * sinA;
double c = r;
double b = Math.Sqrt(c * c - a * a);
offsetX = -_popupWidth + (r - b) + _arcThickness / ;
offsetY = -(_arcThickness / + (r - a));
}
if (middleAngle > && middleAngle <= )
{
double sinA = Math.Sin(Math.PI * ( - middleAngle) / );
double a = r * sinA;
double c = r;
double b = Math.Sqrt(c * c - a * a);
offsetX = -_popupWidth + (r - a) + _arcThickness / ;
offsetY = -(_chartSize / + _popupHeight + b);
}
popup.HorizontalOffset = offsetX;
popup.VerticalOffset = offsetY; return popup;
}
差不多主要的就是这些了.到这.画图有点累.
源码下载:ArcChart.zip
2017-07-13更新:
昨天刚发了博客,今天就发现了bug,真尴尬.180-270度和270-360度的算法有问题,由于例子选用尺寸的问题,早时没有发现.
正确的算法:
180-270度:
X轴:1.向左移动一个Popup的Width 2.向右移动一个(r-b)的距离 3.向右移动二分之一个ArcThickness的距离
Y轴不变
270-360度:
X轴:1.向左移动一个Popup的Width 2.向右移动一个(r-a)的距离 3.向右移动二分之一个ArcThickness的距离
Y轴不变
源码已更新,欢迎重新下载
WPF制作带明细的环形图标的更多相关文章
- WPF制作带明细的环形图表
效果 明细用Popup实现的,录gif时,Popup显示不出来,不知道为什么,所以静态图凑合看吧 大体思路 图表使用Arc+Popup实现 图表分为两部分,一是环形部分,一是标注的明细部分. 环形部分 ...
- WPF中制作带中国农历的万年历
原文:WPF中制作带中国农历的万年历 本例应用.net 2.0中的ChineseLunisolarCalendar类,制作出带中国农历的万年历. 先看看效果图片(已缩小,原始图片为:http://p ...
- WPF制作的小型笔记本
WPF制作的小型笔记本-仿有道云笔记 楼主所在的公司不允许下载外部资源, 不允许私自安装应用程序, 平时记录东西都是用记事本,时间久了很难找到以前记的东西. 平时在家都用有道笔记, 因此就模仿着做了一 ...
- WPF编游戏系列 之二 图标效果
原文:WPF编游戏系列 之二 图标效果 本篇将要实现图标的两个效果:1. 显示图标标签,2. 图标模糊效果.在上一篇中提到Image没有HTML <img>的Title属性( ...
- WPF 自带Datagrid编辑后无法更新数据源的问题
原文 WPF 自带Datagrid编辑后无法更新数据源的问题 解决办法: 在列的绑定属性里加上UpdateSourceTrigger,示例XAML如下 <DataGrid Grid.Row=& ...
- AndroidStudio制作欢迎界面与应用图标
前言 大家好,给大家带来AndroidStudio制作欢迎界面与应用图标的概述,希望你们喜欢 欢迎界面与应用图标 本项目使用Android Studio 3.0.1作为开发工具 activity_sp ...
- 基于jQuery环形图标菜单旋转切换特效
分享一款基于jQuery环形图标旋转切换特效.这是一款鼠标点击图标菜单圆形顺时针或者逆时针旋转切换代码.效果图如下: 在线预览 源码下载 实现的代码. js代码: /* 图片地址可以是相对路径或绝 ...
- WPF制作表示透明区域的马赛克画刷
最近在用WPF制作一款软件,需要像ps一样表示透明区域,于是制作了一个马赛克背景的style.实现比较简单,那么过程和思路就不表了,直接上代码 <DrawingBrush TileMode=&q ...
- WPF制作的小时钟
原文:WPF制作的小时钟 周末无事, 看到WEB QQ上的小时钟挺可爱的, 于是寻思着用WPF模仿着做一个. 先看下WEB QQ的图: 打开VS, 开始动工. 建立好项目后, 面对一个空荡荡的页面, ...
随机推荐
- node使用消息队列RabbitMQ一
基础发布和订阅 消息队列RabbitMQ使用 1 安装RabbitMQ服务器 安装erlang服务 下载地址 http://www.erlang.org/downloads 安装RabbitMQ 下载 ...
- 前端向后台的华丽转身 — PHP入门篇
三个月就这么悄悄溜走了,本K对于前端虽然有了一定的认识,但对一些方面还是处于一种比较萌币的状态,就在这种萌币状态下,本K又跟着大神浩开始了后台语言-PHP语言的学习.PHP的学习对于学过其他语言的人来 ...
- Java IO流之缓冲流
一.缓冲流简介 二.BufferedInputStream 三.其他三种缓冲流
- python3 简单实现从csv文件中读取内容,并对内容进行分类统计
新手python刚刚上路,在实际工作中遇到如题所示的问题,尝试使用python3简单实现如下,欢迎高手前来优化import csv #打开文件,用with打开可以不用去特意关闭file了,python ...
- mysql之 mysql 5.6不停机主从搭建(一主一从基于GTID复制)
环境说明:版本 version 5.6.25-log 主库ip: 10.219.24.25从库ip:10.219.24.22os 版本: centos 6.7已安装热备软件:xtrabackup 防火 ...
- Windows系统前端常用PS快捷键:
1.设置滚轮放大缩小: 编辑--首选项--常规--用滚轮缩放 2.V 移动 ctrl+v 自动选中(图层), 3.M 选框 Shift+M 变换形状 Alt :确定圆形/矩形中心 Shift: 圆形/ ...
- python基础之字典dict和集合set
作者:tongqingliu 转载请注明出处:http://www.cnblogs.com/liutongqing/p/7043642.html python基础之字典dict和集合set 字典dic ...
- nginx之 nginx + tomcat + redis 负载均衡且session一致性
说明: 本文描述的是 nginx + tomcat + redis 实现应用负载均衡且满足session一致性,从安装到配置的全部过程,供大家学习!nginx 代理服务器ip: 10.219.24.2 ...
- mysql的my.ini文件详解
mysql数据库在配置时包含很多信息:端口号,字符编码,指定根路径 basedir,指定数据存放的路径等信息 mysql的字体编码分为两种: 服务器编码 客户端输入的编码 通常服务器的编码都是utf- ...
- 添加保存less报错
编辑器在添加保存less文件弹出一下错误: re-evaluation native module sources is not supported,if you are using the grac ...