You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
311 lines
12 KiB
C#
311 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using HslCommunication.Core;
|
|
|
|
namespace HslCommunication.Controls
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
/// 一个饼图的控件
|
|
/// </summary>
|
|
public partial class UserPieChart : UserControl
|
|
{
|
|
/// <summary>
|
|
/// 实例化一个饼图的控件
|
|
/// </summary>
|
|
public UserPieChart( )
|
|
{
|
|
InitializeComponent( );
|
|
random = new Random( );
|
|
DoubleBuffered = true;
|
|
|
|
formatCenter = new StringFormat( );
|
|
formatCenter.Alignment = StringAlignment.Center;
|
|
formatCenter.LineAlignment = StringAlignment.Center;
|
|
|
|
pieItems = new HslPieItem[0];
|
|
}
|
|
|
|
private void UserPieChart_Load( object sender, EventArgs e )
|
|
{
|
|
|
|
}
|
|
|
|
#region Private
|
|
|
|
private HslPieItem[] pieItems = new HslPieItem[0]; // 饼图的数据
|
|
private Random random = null; // 随机数
|
|
private StringFormat formatCenter = null; // 格式化的文本位置
|
|
private int margin = 40; // 边界距离
|
|
private bool m_IsRenderPercent = false; // 是否显示百分比
|
|
private bool m_IsRenderSmall = true; // 是否在图形上显示占比非常小的文本信息
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 是否显示百分比信息
|
|
/// </summary>
|
|
[Browsable( true )]
|
|
[Category( "外观" )]
|
|
[DefaultValue( false )]
|
|
[Description( "获取或设置是否显示百分比占用" )]
|
|
public bool IsRenderPercent
|
|
{
|
|
get { return m_IsRenderPercent; }
|
|
set { m_IsRenderPercent = value; Invalidate( ); }
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 是否在图形上显示占比非常小的文本信息
|
|
/// </summary>
|
|
[Browsable(true)]
|
|
[Category("外观")]
|
|
[Description("获取或设置是否显示占比很小的文本信息")]
|
|
[DefaultValue(true)]
|
|
public bool IsRenderSmall
|
|
{
|
|
get { return m_IsRenderSmall; }
|
|
set { m_IsRenderSmall = value; Invalidate( ); }
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetMarginPaint( int value )
|
|
{
|
|
if (value > 500)
|
|
{
|
|
margin = 80;
|
|
}
|
|
else if (value > 300)
|
|
{
|
|
margin = 60;
|
|
}
|
|
else
|
|
{
|
|
margin = 40;
|
|
}
|
|
}
|
|
|
|
private Point GetCenterPoint( out int width )
|
|
{
|
|
if (Width > Height)
|
|
{
|
|
SetMarginPaint( Height );
|
|
width = Height / 2 - margin;
|
|
return new Point( Height / 2 - 1, Height / 2 - 1 );
|
|
}
|
|
else
|
|
{
|
|
SetMarginPaint( Width );
|
|
width = Width / 2 - margin;
|
|
return new Point( Width / 2 - 1, Width / 2 - 1 );
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 随机生成颜色,该颜色相对于白色为深色颜色
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private Color GetRandomColor( )
|
|
{
|
|
int int_Red = random.Next( 256 );
|
|
int int_Green = random.Next( 256 );
|
|
int int_Blue = (int_Red + int_Green > 430) ? random.Next( 100 ) : random.Next( 200 );
|
|
return Color.FromArgb( int_Red, int_Green, int_Blue );
|
|
}
|
|
|
|
|
|
private void UserPieChart_Paint( object sender, PaintEventArgs e )
|
|
{
|
|
if (!Authorization.nzugaydgwadawdibbas( )) return;
|
|
// 画刷初始化
|
|
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
|
|
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
|
|
|
// 开始绘制饼图,寻找中心点
|
|
Point center = GetCenterPoint( out int width );
|
|
Rectangle rect_center = new Rectangle( center.X - width, center.Y - width, width + width, width + width );
|
|
|
|
if (width > 0 && pieItems.Length > 0)
|
|
{
|
|
e.Graphics.FillEllipse( Brushes.AliceBlue, rect_center );
|
|
e.Graphics.DrawEllipse( Pens.DodgerBlue, rect_center );
|
|
|
|
Rectangle rect_tran = new Rectangle( rect_center.X - center.X, rect_center.Y - center.Y, rect_center.Width, rect_center.Height );
|
|
e.Graphics.TranslateTransform( center.X, center.Y );
|
|
e.Graphics.RotateTransform( 90 );
|
|
e.Graphics.DrawLine( Pens.DimGray, 0, 0, width, 0 );
|
|
|
|
|
|
// 计算分布
|
|
int totle = pieItems.Sum( item => item.Value );
|
|
float totleAngle = 0; // 本次绘制的角度
|
|
float lastAngle = -90; // 上一次的角度
|
|
for (int i = 0; i < pieItems.Length; i++)
|
|
{
|
|
float single = 0;
|
|
if (totle == 0)
|
|
{
|
|
single = 360 / pieItems.Length;
|
|
}
|
|
else
|
|
{
|
|
single = Convert.ToSingle( pieItems[i].Value * 1.0d / totle * 360 );
|
|
}
|
|
|
|
|
|
using (Brush brush = new SolidBrush( pieItems[i].Back ))
|
|
{
|
|
e.Graphics.FillPie( brush, rect_tran, 0, -single );
|
|
}
|
|
e.Graphics.RotateTransform( 0 - single / 2 );
|
|
|
|
|
|
if (single < 2f && !IsRenderSmall)
|
|
{
|
|
totleAngle += single;
|
|
}
|
|
else
|
|
{
|
|
// 画标线
|
|
totleAngle += single / 2;
|
|
int mark = 8;
|
|
if (totleAngle < 45 || totleAngle > 315) mark = 15;
|
|
if (totleAngle > 135 && totleAngle < 225) mark = 15;
|
|
|
|
e.Graphics.DrawLine( Pens.DimGray, width * 2 / 3, 0, width + mark, 0 );
|
|
e.Graphics.TranslateTransform( width + mark, 0 );
|
|
|
|
if (totleAngle - lastAngle < 5)
|
|
{
|
|
// 两次的标线非常接近
|
|
|
|
}
|
|
lastAngle = totleAngle;
|
|
|
|
|
|
|
|
if (totleAngle < 90)
|
|
{
|
|
e.Graphics.RotateTransform( totleAngle - 90 );
|
|
e.Graphics.DrawLine( Pens.DimGray, 0, 0, margin - mark, 0 );
|
|
e.Graphics.DrawString( pieItems[i].Name, Font, Brushes.DimGray, new Point( 0, -Font.Height ) );
|
|
if (IsRenderPercent) e.Graphics.DrawString( Math.Round( single * 100 / 360, 2 ).ToString( ) + "%", Font, Brushes.DodgerBlue, new Point( 0, 1 ) );
|
|
e.Graphics.RotateTransform( 90 - totleAngle );
|
|
}
|
|
else if (totleAngle < 180)
|
|
{
|
|
e.Graphics.RotateTransform( totleAngle - 90 );
|
|
e.Graphics.DrawLine( Pens.DimGray, 0, 0, margin - mark, 0 );
|
|
e.Graphics.DrawString( pieItems[i].Name, Font, Brushes.DimGray, new Point( 0, -Font.Height ) );
|
|
if (IsRenderPercent) e.Graphics.DrawString( Math.Round( single * 100 / 360, 2 ).ToString( ) + "%", Font, Brushes.DodgerBlue, new Point( 0, 1 ) );
|
|
e.Graphics.RotateTransform( 90 - totleAngle );
|
|
}
|
|
else if (totleAngle < 270)
|
|
{
|
|
e.Graphics.RotateTransform( totleAngle - 270 );
|
|
e.Graphics.DrawLine( Pens.DimGray, 0, 0, margin - mark, 0 );
|
|
e.Graphics.TranslateTransform( margin - 8, 0 );
|
|
e.Graphics.RotateTransform( 180 );
|
|
e.Graphics.DrawString( pieItems[i].Name, Font, Brushes.DimGray, new Point( 0, -Font.Height ) );
|
|
if (IsRenderPercent) e.Graphics.DrawString( Math.Round( single * 100 / 360, 2 ).ToString( ) + "%", Font, Brushes.DodgerBlue, new Point( 0, 1 ) );
|
|
e.Graphics.RotateTransform( -180 );
|
|
e.Graphics.TranslateTransform( 8 - margin, 0 );
|
|
e.Graphics.RotateTransform( 270 - totleAngle );
|
|
}
|
|
else
|
|
{
|
|
e.Graphics.RotateTransform( totleAngle - 270 );
|
|
e.Graphics.DrawLine( Pens.DimGray, 0, 0, margin - mark, 0 );
|
|
e.Graphics.TranslateTransform( margin - 8, 0 );
|
|
e.Graphics.RotateTransform( 180 );
|
|
e.Graphics.DrawString( pieItems[i].Name, Font, Brushes.DimGray, new Point( 0, -Font.Height ) );
|
|
if (IsRenderPercent) e.Graphics.DrawString( Math.Round( single * 100 / 360, 2 ).ToString( ) + "%", Font, Brushes.DodgerBlue, new Point( 0, 1 ) );
|
|
e.Graphics.RotateTransform( -180 );
|
|
e.Graphics.TranslateTransform( 8 - margin, 0 );
|
|
e.Graphics.RotateTransform( 270 - totleAngle );
|
|
}
|
|
|
|
e.Graphics.TranslateTransform( -width - mark, 0 );
|
|
e.Graphics.RotateTransform( 0 - single / 2 );
|
|
totleAngle += single / 2;
|
|
}
|
|
}
|
|
e.Graphics.ResetTransform( );
|
|
}
|
|
else
|
|
{
|
|
e.Graphics.FillEllipse( Brushes.AliceBlue, rect_center );
|
|
e.Graphics.DrawEllipse( Pens.DodgerBlue, rect_center );
|
|
e.Graphics.DrawString( "空", Font, Brushes.DimGray, rect_center, formatCenter );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
#region Public Method
|
|
|
|
/// <summary>
|
|
/// 设置显示的数据源
|
|
/// </summary>
|
|
/// <param name="source">特殊的显示对象</param>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
public void SetDataSource( HslPieItem[] source )
|
|
{
|
|
if (source != null)
|
|
{
|
|
pieItems = source;
|
|
Invalidate( );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据名称和值进行数据源的显示,两者的长度需要一致
|
|
/// </summary>
|
|
/// <param name="names">名称</param>
|
|
/// <param name="values">值</param>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
public void SetDataSource( string[] names, int[] values )
|
|
{
|
|
if (names == null) throw new ArgumentNullException( "names" );
|
|
if (values == null) throw new ArgumentNullException( "values" );
|
|
if (names.Length != values.Length) throw new Exception( "两个数组的长度不一致!" );
|
|
|
|
pieItems = new HslPieItem[names.Length];
|
|
|
|
for (int i = 0; i < names.Length; i++)
|
|
{
|
|
pieItems[i] = new HslPieItem( )
|
|
{
|
|
Name = names[i],
|
|
Value = values[i],
|
|
Back = GetRandomColor( ),
|
|
};
|
|
}
|
|
|
|
Invalidate( );
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|