本文实例为大家分享了C#编写折线图控件的具体代码,供大家参考,具体内容如下
简单解说这是第一次写博客,也是第一次发布自己写代码,有不足之处请多见谅。
源代码参考了网络搜索到的一些资源。
因为我需要的折线图数据没有小于0的,所以在计算时偷懒了。只支持大于0的数据。
上图
如何插入一段漂亮的代码片
因为自学编程,代码注释与命名比较乱,请见谅。
这是新建控件的代码。需要给控件添加FoldLineDiagram_Resize 事件。
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 System.Drawing.Drawing2D;
namespace vc_farm
{
/// <summary>
/// 折线图控件
/// 注意:
/// 1、数据列最少不小于2列。
/// 2、数据列与数据标题列长度必须保持一致
/// 3、数据标题长度最大为100
/// 4、折线数量不能大于10个
/// </summary>
public partial class FoldLineDiagram : UserControl
{
private Bitmap mImage; //画的折线图
private FoldLineData mData; //记录折线数据,在窗口大小改变时可重新计算
private List<SelectionArea> mSelectionArea = new List<SelectionArea>(); //可选择区域【此处无用,原用作记录数据点,方便判断光标是否选中某条数据折线】
private SelectionArea mNowSelectionArea; //当前选中的区域【此处无用】
public FoldLineDiagram()
{
InitializeComponent();
}
#region 禁止基类属性显示
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public override Image BackgroundImage
{
get { return base.BackgroundImage; }
set { base.BackgroundImage = value; }
}
#endregion
/// <summary>
/// 获取折线图片(只有使用了ShowFoldLineDiagram方法后才能正确获取)
/// </summary>
public Bitmap Image
{
get { return mImage; }
}
/// <summary>
/// 显示折线
/// </summary>
/// <param name="aData">折线数据对象</param>
public void ShowFoldLineDiagram(FoldLineData aData)
{
this.mData = aData;
mImage = CreateImageS(aData);
this.BackgroundImage = new Bitmap(mImage); //背景为复制的图片
//this.BackgroundImageLayout = ImageLayout.Stretch; //拉伸显示显示
}
/// <summary>
/// 保存 折线图 图片(只有使用了ShowFoldLineDiagram方法后才能正确保存)
/// </summary>
/// <param name="aSavePath">保存文件的路径</param>
/// <param name="aImageFormat">保存的格式</param>
public void SaveImage(string aSavePath, System.Drawing.Imaging.ImageFormat aImageFormat)
{
new Bitmap(mImage).Save(aSavePath, aImageFormat);
}
private Bitmap CreateImageS(FoldLineData data)
{
#region 数据验证
if (data.DataTitleText.Count <= 1) return null; //限制列数不能小于2
if (data.DataTitleText.Count >100) return null; //限制列数不能大于100
if (data.listFoldLineDataStyle.Count > 10) return null; //限制折线数量不能大于10
int temp = data.DataTitleText.Count; //获取数据标题长度
for (int i = 0; i < data.listFoldLineDataStyle.Count; i++) //循环所有数据
{
if (data.listFoldLineDataStyle[i].Data.Count !=temp) //当前数据长度 与数据标题长度不一致
{
return null;
}
}
#endregion
#region 函数内部变量赋值
this.mSelectionArea.Clear(); //记录数据清空
int height = this.Height, width = this.Width; //设置图片大小
//设置左右上下边框距离图片边框间距
int left = (int)(width * 0.1);
int right = (int)(width * 0.1);
int top = (int)(height * 0.1);
int bottom;
if (data.ShowLegend == true) bottom = (int)(height * 0.15); //显示图例时,下边框为0.2
else bottom = (int)(height * 0.1);
#endregion
Bitmap image = new Bitmap(width, height); //新建一张图片
Graphics g = Graphics.FromImage(image);
g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.CompositingQuality = CompositingQuality.HighQuality;
try
{
#region 绘图准备工作
g.Clear(Color.White); //清空图片背景色
Font font = data.DataTitleTextFont; //设置 X与Y轴 标题字体
Font font1 = data.FoldLineTextFont; //设置 标题 字体
//Font font2 = aLineDataFont; //设置 数据显示 字体
LinearGradientBrush brush = new LinearGradientBrush(
new Rectangle(0, 0, image.Width, image.Height), data.BackgroundBorderColor, data.BackgroundBorderColor, 1.2f, true);
g.FillRectangle(Brushes.AliceBlue, 0, 0, width, height);
#endregion
#region 画折线图标题
Brush brush1 = new SolidBrush(data.FoldLineTextColor);
SizeF sizeF = g.MeasureString(data.FoldLineText, font1); //计算标题文字大小
g.DrawString(data.FoldLineText, font1, brush1, (width - sizeF.Width) / 2, (top - sizeF.Height) / 2); //画标题
#endregion
#region 绘制框线
//画图片的边框线
g.DrawRectangle(new Pen(data.BackgroundBorderColor), 0, 0, image.Width - 1, image.Height - 1);
Pen mypen = new Pen(brush, 1); //边框线画笔
//绘制纵向线条
int xLineSpacing = (width - left - right) / (data.DataTitleText.Count - 1); //计算X轴 线条间距
int xPosition = left; //X轴开始位置
for (int i = 0; i < data.DataTitleText.Count; i++)
{
g.DrawLine(mypen, xPosition, top, xPosition, height - bottom); //画X轴竖线
sizeF = g.MeasureString(data.DataTitleText[i], font); //计算X轴文字大小
g.DrawString(data.DataTitleText[i], font, new SolidBrush(data.DataTitleTextColor), xPosition - (sizeF.Width / 2), height - bottom + 5); //设置文字内容及输出位置
xPosition += +xLineSpacing; //累加间距
}
//Pen mypen1 = new Pen(Color.Blue, 3);
xPosition = left;
g.DrawLine(mypen, xPosition, top, xPosition, height - bottom); //画X轴第1条线(粗线)
//绘制横向线条
List<int> yName = ReckonYLine(data.listFoldLineDataStyle);
int mLineCount = yName.Count; //计算Y轴行数
int yLineSpacing = (height - bottom - top) / (yName.Count - 1); //计算Y轴 线条间距
int yPosition = height - bottom; //Y轴开始点
for (int i = 0; i < yName.Count; i++)
{
g.DrawLine(mypen, left, yPosition, width - right, yPosition);
sizeF = g.MeasureString(yName[i].ToString(), font);
g.DrawString(yName[i].ToString(), font, new SolidBrush(data.DataTitleTextColor), left - sizeF.Width - 5, yPosition - (sizeF.Height / 2)); //设置文字内容及输出位置
yPosition -= yLineSpacing;
}
yPosition = height - bottom;
g.DrawLine(mypen, left, yPosition, width - right, yPosition); //Y轴最下面一天线加粗
#endregion
#region 画折线,及数据
for (int i = 0; i < data.listFoldLineDataStyle.Count; i++)
{
//显示折线效果
Pen mypen2 = new Pen(data.listFoldLineDataStyle[i].FoldLineColor, 2); //折线画笔
List<int> pointData = data.listFoldLineDataStyle[i].Data; //取出折线数据
xPosition = left;
float yMultiple = (float)(height - top - bottom) / (float)yName.Max(); //计算Y轴比例因子
List<Point> linePoint = new List<Point>(); //定义折线节点坐标
for (int j = 0; j < pointData.Count; j++)
{
Point point = new Point();
point.X = xPosition;
point.Y = top + (int)((yName.Max() - pointData[j]) * yMultiple);
xPosition += xLineSpacing;
linePoint.Add(point);
g.FillEllipse(new SolidBrush(data.listFoldLineDataStyle[i].FoldLineColor), point.X - 5, point.Y - 5, 10, 10); //画节点的圆点
g.DrawString(pointData[j].ToString(), data.listFoldLineDataStyle[i].FoldLineDataFont, new SolidBrush(data.listFoldLineDataStyle[i].FoldLineDataColor), point.X, point.Y + 10); //绘制节点文字
}
g.DrawLines(mypen2, linePoint.ToArray()); //绘制折线
//记录画图区域
SelectionArea sa = new SelectionArea();
sa.linePoint = linePoint;
//sa.rect = new Rectangle();
this.mSelectionArea.Add(sa);
}
#endregion
#region 画图例
if (data.ShowLegend ==true)
{
int length = 0; //绘制的长度
for (int i = 0; i < data.listFoldLineDataStyle.Count; i++)
{
//显示折线效果
Pen mypen2 = new Pen(data.listFoldLineDataStyle[i].FoldLineColor, 2); //折线画笔
if (data.listFoldLineDataStyle[i].DataName == "折线")
{
data.listFoldLineDataStyle[i].DataName += i.ToString(); //如果是默认名称,则给默认名称加数字
}
sizeF = g.MeasureString(data.listFoldLineDataStyle[i].DataName, data.DataTitleTextFont); //计算字体长度
//20:两个图例的间距,30:图例中颜色表示区宽度 ,10:图例颜色标识区与文本区间距
length += 20 + 30 + 10 + (int)sizeF.Width;
}
length += 20; //加上最后的间距
int startX = (width - length) / 2;
int startY = (int)(height * 0.92);
for (int i = 0; i < data.listFoldLineDataStyle.Count; i++)
{
//显示折线效果
Pen mypen2 = new Pen(data.listFoldLineDataStyle[i].FoldLineColor, 2); //折线画笔
if (data.listFoldLineDataStyle[i].DataName == "折线")
{
data.listFoldLineDataStyle[i].DataName += i.ToString(); //如果是默认名称,则给默认名称加数字
}
sizeF = g.MeasureString(data.listFoldLineDataStyle[i].DataName, data.DataTitleTextFont); //计算字体长度
g.FillRectangle(new SolidBrush(data.listFoldLineDataStyle[i].FoldLineColor), startX, startY, 30, 10); //绘制小矩形
g.DrawString(data.listFoldLineDataStyle[i].DataName, data.DataTitleTextFont, new SolidBrush(data.listFoldLineDataStyle[i].FoldLineColor), startX + 30 + 10, startY);
startX += 30 + 10 + (int)sizeF.Width+20;
//记录画图区域的 图例显示区域
Rectangle rect = new Rectangle(startX, startY, 30, 10);
SelectionArea sa = this.mSelectionArea[i];
sa.rect = rect;
this.mSelectionArea[i] = sa;
}
}
#endregion
return new Bitmap(image);
}
finally
{
g.Dispose();
image.Dispose();
}
}
/// <summary>
/// Y轴横线 及 Y轴标题内如 计算
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private List<int> ReckonYLine(List<FoldLineDataStyle> flData)
{
List<int> AllData = new List<int>(); //所有数据汇总在一起
foreach (FoldLineDataStyle item in flData)
{
AllData.AddRange(item.Data);
}
//定义最大值与最小值
int max = AllData.Max();
int min = AllData.Min();
List<int> yName = new List<int>();
int csMax = 0; //测算上限
/*如果需要增加小于0数据判断,则需要在此次增加一些判断。
*就是取最小值,判断是否为负数,是则取绝对值进行计算,不是则和现在计算方式一样
*/
if (max.ToString().Length > 1) //如果大于9
{
//测算最大上限值
string ling = "";
for (int i = 0; i < max.ToString().Length - 1; i++) //为数字末尾补0
ling += "0";
string temp = max.ToString().Substring(0, 1); //取出最高位数字
csMax = Int32.Parse((Int32.Parse(temp) + 1) + ling); //如果max=75162 则转成 80000
for (int i = 0; i <= (Int32.Parse(temp) + 1); i++)
{
yName.Add((Int32.Parse(i + ling)));
}
}
else
{
csMax = max + 1;
for (int i = 0; i <= csMax; i++)
{
yName.Add(i);
}
}
return yName;
}
private void FoldLineDiagram_Resize(object sender, EventArgs e)
{
if (mData!=null)
{
mImage = CreateImageS(mData);
this.BackgroundImage = new Bitmap(mImage); //背景为复制的图片
}
}
/// <summary>
/// 选择区域
/// </summary>
private struct SelectionArea
{
/// <summary>
/// 选择区域
/// </summary>
public Rectangle rect;
/// <summary>
/// 折线区域
/// </summary>
public List<Point> linePoint;
}
/// <summary>
/// 判断点是否在矩形范围内
/// </summary>
/// <param name="rect"></param>
/// <param name="pt"></param>
/// <returns></returns>
public static bool IsPointIn(RectangleF rect, PointF pt)
{
if (pt.X >= rect.X && pt.Y >= rect.Y && pt.X <= rect.X + rect.Width && pt.Y <= rect.Y + rect.Height)
{
return true;
}
else return false;
}
}
/// <summary>
/// 折线背景设置
/// </summary>
public class FoldLineData
{
/// <summary>
/// 全部折线 默认:空数据
/// </summary>
public List<FoldLineDataStyle> listFoldLineDataStyle;
/// <summary>
/// 折线图的标题文本 默认:空文本
/// </summary>
public List<string> DataTitleText;
/// <summary>
/// 折线图的标题文本 默认:空文本
/// </summary>
public string FoldLineText;
/// <summary>
/// 折线图的标题文本 字体颜色 默认:黑色
/// </summary>
public Color FoldLineTextColor;
/// <summary>
/// 折线图的标题文本 字体格式 默认:"宋体", 20
/// </summary>
public Font FoldLineTextFont;
/// <summary>
/// 数据列标题 字体颜色 默认:黑色
/// </summary>
public Color DataTitleTextColor;
/// <summary>
/// 数据列标题 字体格式 默认:"宋体", 9
/// </summary>
public Font DataTitleTextFont;
/// <summary>
/// 背景边框线 颜色 默认:深灰色
/// </summary>
public Color BackgroundBorderColor;
/// <summary>
/// 显示图例 默认:true
/// </summary>
public bool ShowLegend;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="flds">数据组。每组数据长度必须一致,且与数据列名称长度一致</param>
/// <param name="dataTitleText">数据列名称</param>
public FoldLineData(List<FoldLineDataStyle> flds, List<string> dataTitleText)
{
DataTitleText = dataTitleText;
listFoldLineDataStyle = flds;
FoldLineText = "";
FoldLineTextColor = Color.Black;
FoldLineTextFont = new System.Drawing.Font("宋体", 20, FontStyle.Regular);
DataTitleTextColor = Color.Black;
DataTitleTextFont = new System.Drawing.Font("Arial", 9, FontStyle.Regular);
BackgroundBorderColor = Color.DarkGray;
ShowLegend = true;
}
}
/// <summary>
/// 折线数据及样式
/// </summary>
public class FoldLineDataStyle
{
/// <summary>
/// 折线数据 默认:null
/// </summary>
public List<int> Data;
/// <summary>
/// 折线数据名称 默认:折线
/// </summary>
public string DataName;
/// <summary>
/// 折线颜色 默认:红色
/// </summary>
public Color FoldLineColor;
/// <summary>
/// 折线点上 显示的数据颜色 默认:红色
/// </summary>
public Color FoldLineDataColor;
/// <summary>
/// 折线点上 显示的数据字体格式 默认:"宋体", 8
/// </summary>
public Font FoldLineDataFont;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="data">数据。数据长度一定需要保持一致</param>
public FoldLineDataStyle(List<int> data)
{
Data = data;
FoldLineColor = Color.Red;
FoldLineDataColor = Color.Red;
FoldLineDataFont = new System.Drawing.Font("宋体", 9, FontStyle.Regular);
DataName = "折线";
}
}
}
测试数据代码
private void Form2_Load(object sender, EventArgs e)
{
List<string> name = new List<string> { "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月" };
List<int> data = new List<int> { 1150, 250, 1550, 1600, 1800, 900, 2500, 1700 };
List<int> data1 = new List<int> { 1250, 2250, 3550, 1600, 800, 900, 500, 2700 };
List<int> data2 = new List<int> { 2150, 250, 1550, 1600, 1700, 900, 200, 1700 };
FoldLineDataStyle fld = new FoldLineDataStyle(data); //默认格式
FoldLineDataStyle fld1 = new FoldLineDataStyle(data1);
fld1.DataName = "测试数据1";
fld1.FoldLineColor = Color.Green;
fld1.FoldLineDataColor = Color.Green;
FoldLineDataStyle fld2 = new FoldLineDataStyle(data2);
//fld2.DataName = "测试数据1";
fld2.FoldLineColor = Color.Blue;
fld2.FoldLineDataColor = Color.Blue;
FoldLineData foldLineData = new FoldLineData(new List<FoldLineDataStyle> { fld, fld1, fld2 }, name);
foldLineData.ShowLegend = true;
foldLineData.FoldLineText = "测试折线图";
this.foldLineDiagram1.ShowFoldLineDiagram(foldLineData);
}