参考文档:
1、x轴怎么显示时间
c#chart 的x轴设置时间格式,第一个坐标从0开始_c# chart 坐标轴-优快云博客
2、动态曲线绘制(能局部放大)
C# winform 多个chart动态曲线绘制(能局部放大)_winform 曲线图表-优快云博客
3、当数据量较大时,x轴出现滚动条
C#中chart控件--(当数据量较大时,x轴出现滚动条)_winform chart x轴 毫秒级 滚动条-优快云博客
4、添加边界线条
c# chart控件添加边界值线条以及扩展性功能 - AKA-Green - 博客园 (cnblogs.com)
结合以上参考 x轴设置为ms显示滚动条可以拖拽,支持放大缩小,支持最大值显示
X轴类型设置
//间隔
//chartArea.AxisY.Interval = 20;
//chartArea.AxisY.Minimum = 0;
//chartArea.AxisY.Maximum = 100;
chartArea.AxisX.LabelStyle.Format = "yy-MM-dd\r\nHH:mm:ss.fff"; //横坐标格式
chartArea.AxisX.IntervalType = DateTimeIntervalType.Milliseconds;//如果是时间类型的数据,间隔方式可以是秒、分、时
//chartArea.AxisX.Minimum = dateTime.ToOADate();
//chartArea.AxisX.Maximum = dateTime.AddMilliseconds(1000).ToOADate();
chartArea.AxisX.Interval = DateTime.Parse("00:00:00.100").Millisecond;
特别注意 数据视图的设置否则鼠标无法拖动滚动轴
//数据视图
chartArea.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.All;//启用X轴滚动条按钮
chartArea.AxisX.ScaleView.SizeType = DateTimeIntervalType.Auto;
chartArea.AxisX.ScaleView.MinSize = 100;
chartArea.AxisX.ScaleView.MinSizeType = DateTimeIntervalType.Milliseconds;
chartArea.AxisX.ScaleView.SmallScrollMinSize = 100;
chartArea.AxisX.ScaleView.SmallScrollMinSizeType = DateTimeIntervalType.Milliseconds;
chartArea.AxisX.ScaleView.SmallScrollSize = 100;
chartArea.AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Milliseconds;
chartArea.AxisX.ScaleView.Zoomable = true;
其中的类型设置为ms,默认的话滚动轴的单位太大界面是ms显示就会出现无法拖动滚动轴的情况
要实现滚动条实时跟随曲线主要设置chart1.ChartAreas[0].AxisX.ScaleView.Position这个参数的值
一个页面最大显示多少个数据受chart1.ChartAreas[0].AxisX.ScaleView.Size,再结合间隔中设置的chartArea.AxisX.Interval = DateTime.Parse("00:00:00.100").Millisecond;参数就可以计算出一个页面显示几个数据了。
range = r.Next(1, 60); //随机取数
dateTime = dateTime.AddMilliseconds(100);
series1.Points.AddXY(dateTime, 5 + range); //设置series点
chart1.ChartAreas[0].AxisX.ScaleView.Size = dateTime.AddMilliseconds(900).ToOADate() - dateTime.ToOADate();
sum++;
if (sum <= chart1.ChartAreas[0].AxisX.ScaleView.Size)
chart1.ChartAreas[0].AxisX.ScaleView.Position = dateTime.ToOADate();
else
chart1.ChartAreas[0].AxisX.ScaleView.Position = dateTime.ToOADate() - chart1.ChartAreas[0].AxisX.ScaleView.Size;
总体代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using ToolTip = System.Windows.Forms.ToolTip;
namespace TemperDisplay
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
createSeries();
CreateChart();
}
private void CreateChart()
{
ChartArea chartArea = chart1.ChartAreas[0];
dateTime = DateTime.Now;
//游标
chartArea.CursorX.IsUserEnabled = true;
chartArea.CursorX.IsUserSelectionEnabled = true;
chartArea.CursorX.AutoScroll = true;
chartArea.CursorX.SelectionColor = Color.SkyBlue;
chartArea.CursorX.IntervalType = DateTimeIntervalType.Milliseconds;
chartArea.CursorX.Interval = 1;
chartArea.CursorX.AxisType = AxisType.Primary;
//数据视图
chartArea.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.All;//启用X轴滚动条按钮
chartArea.AxisX.ScaleView.SizeType = DateTimeIntervalType.Auto;
chartArea.AxisX.ScaleView.MinSize = 100;
chartArea.AxisX.ScaleView.MinSizeType = DateTimeIntervalType.Milliseconds;
chartArea.AxisX.ScaleView.SmallScrollMinSize = 100;
chartArea.AxisX.ScaleView.SmallScrollMinSizeType = DateTimeIntervalType.Milliseconds;
chartArea.AxisX.ScaleView.SmallScrollSize = 100;
chartArea.AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Milliseconds;
chartArea.AxisX.ScaleView.Zoomable = true;
//外观
chartArea.BackColor = Color.AliceBlue; //背景色
chartArea.BackSecondaryColor = Color.White; //渐变背景色
chartArea.BackGradientStyle = GradientStyle.TopBottom; //渐变方式
chartArea.BackHatchStyle = ChartHatchStyle.None; //背景阴影
chartArea.BorderDashStyle = ChartDashStyle.NotSet; //边框线样式
chartArea.BorderWidth = 1; //边框宽度
chartArea.BorderColor = Color.Black;
//分割线
chartArea.AxisX.MajorGrid.Enabled = true;
chartArea.AxisY.MajorGrid.Enabled = true;
// Axis 标签
chartArea.AxisY.Title = @"Value";
chartArea.AxisY.LabelAutoFitMinFontSize = 5;
chartArea.AxisX.Title = @"Time";
chartArea.AxisX.IsLabelAutoFit = true;
chartArea.AxisX.LabelAutoFitMinFontSize = 5;
chartArea.AxisX.LabelStyle.Angle = 0; //标签旋转角度 -90 --- 90
chartArea.AxisX.LabelStyle.IsEndLabelVisible = true;
chartArea.AxisX.TextOrientation = TextOrientation.Auto; //文本方向
//间隔
//chartArea.AxisY.Interval = 20;
//chartArea.AxisY.Minimum = 0;
//chartArea.AxisY.Maximum = 100;
chartArea.AxisX.LabelStyle.Format = "yy-MM-dd\r\nHH:mm:ss.fff"; //横坐标格式
chartArea.AxisX.IntervalType = DateTimeIntervalType.Milliseconds;//如果是时间类型的数据,间隔方式可以是秒、分、时
//chartArea.AxisX.Minimum = dateTime.ToOADate();
//chartArea.AxisX.Maximum = dateTime.AddMilliseconds(1000).ToOADate();
chartArea.AxisX.Interval = DateTime.Parse("00:00:00.100").Millisecond;
//外观
chartArea.AxisY.LineWidth = 2; //数据表纵向边沿宽度
chartArea.AxisY.LineColor = Color.Black; //数据表纵向边沿颜色
chartArea.AxisY.Enabled = AxisEnabled.True;
chartArea.AxisX.LineWidth = 2;
chartArea.AxisX.LineColor = Color.Black;
chartArea.AxisX.Enabled = AxisEnabled.True;
//辅助线条
double max = 25;
StripLine stripMax = new StripLine();
stripMax.Text = string.Format("最大:{0:F}", max);//展示文本
stripMax.BackColor = Color.FromArgb(208, 109, 106);//背景色
stripMax.Interval = 0;//间隔
stripMax.IntervalOffset = max;//偏移量
stripMax.StripWidth = 0.001;//线宽
stripMax.ForeColor = Color.Yellow;//前景色
stripMax.TextAlignment = StringAlignment.Near;//文本对齐方式
chartArea.AxisY.StripLines.Add(stripMax);//添加到ChartAreas中
//图表区矩形位置
//chartArea.Position.Height = 85;
//chartArea.Position.Width = 85;
//chartArea.Position.X = 5;
//chartArea.Position.Y = 7;
//渐变样式
chart1.BackGradientStyle = GradientStyle.TopBottom;
//图表的边框颜色、
chart1.BorderlineColor = Color.FromArgb(26, 59, 105);
//图表的边框线条样式
chart1.BorderlineDashStyle = ChartDashStyle.Solid;
//图表边框线条的宽度
chart1.BorderlineWidth = 2;
//图表边框的皮肤
chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
}
Series series1;
private void createSeries()
{
//Series1
series1 = chart1.Series[0];
//Series1 style
series1.ToolTip = "温度:#VALY{F1}\n时间:#VALX{HH-mm-dd.fff}"; //鼠标停留在数据点上,显示XY值
series1.Name = "PT1000温度";
series1.ChartType = SeriesChartType.Spline; // type
series1.BorderWidth = 2; //线条宽度
series1.Color = Color.Red; //线条颜色
series1.XValueType = ChartValueType.DateTime; //显示时间
series1.YValueType = ChartValueType.Auto;
series1.IsValueShownAsLabel = true; //显示数据值
series1.LabelFormat = "F1"; //显示数据格式
series1.LabelForeColor = Color.Black; //显示数据颜色
series1.LabelBackColor = Color.AliceBlue; //显示数据背景色
//Marker
series1.MarkerStyle = MarkerStyle.Square; //标签点样式
series1.MarkerSize = 5;
series1.MarkerColor = Color.Black; //标签点颜色
//图标图例
//停靠
chart1.Legends[0].Alignment = StringAlignment.Far; //靠右
chart1.Legends[0].Docking = Docking.Top; //靠上
}
static int range = 0;
Random r = new Random(6);
int sum = 1;
bool flag = false;
DateTime dateTime;
private void timer1_Tick(object sender, EventArgs e)
{
if (flag)
return;
else
{
range = r.Next(1, 60); //随机取数
dateTime = dateTime.AddMilliseconds(100);
series1.Points.AddXY(dateTime, 5 + range); //设置series点
chart1.ChartAreas[0].AxisX.ScaleView.Size = dateTime.AddMilliseconds(900).ToOADate() - dateTime.ToOADate();
sum++;
if (sum <= chart1.ChartAreas[0].AxisX.ScaleView.Size)
chart1.ChartAreas[0].AxisX.ScaleView.Position = dateTime.ToOADate();
else
chart1.ChartAreas[0].AxisX.ScaleView.Position = dateTime.ToOADate() - chart1.ChartAreas[0].AxisX.ScaleView.Size;
//series1.Points.AddXY(sum, 5 + range);
//sum++;
//if (comboBox1.SelectedItem.ToString() == "OverView") //切换试图
//{
// chart1.ChartAreas[0].AxisX.ScaleView.Position = 1;
// if (sum > 10)
// {
// double max = chart1.ChartAreas[0].AxisX.Maximum;
// max = (sum / 10 + 1) * 10;
// chart1.ChartAreas[0].AxisX.Interval = max / 10;
// }
// chart1.ChartAreas[0].AxisX.ScaleView.Size = sum * 1.1;
// //chart.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.None;//启用X轴滚动条按钮
//}
//if (comboBox1.SelectedItem.ToString() == "Follow")
//{
// //chart1.ChartAreas[0].AxisX.Interval = 1D;
// chart1.ChartAreas[0].AxisX.ScaleView.Size = 10D;
// if (sum <= chart1.ChartAreas[0].AxisX.ScaleView.Size)
// chart1.ChartAreas[0].AxisX.ScaleView.Position = 1;
// else
// chart1.ChartAreas[0].AxisX.ScaleView.Position = sum - chart1.ChartAreas[0].AxisX.ScaleView.Size;
//}
}
}
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "开始")
{
timer1.Start();
button1.Text = "暂停";
}
else
{
timer1.Stop();
button1.Text = "开始";
}
}
private void chart1_SelectionRangeChanged(object sender, CursorEventArgs e)
{
//无数据时返回
if (chart1.Series[0].Points.Count == 0)
return;
double start_position = 0.0;
double end_position = 0.0;
double myInterval = 0.0;
start_position = e.NewSelectionStart;
end_position = e.NewSelectionEnd;
myInterval = Math.Abs(start_position - end_position);
Console.WriteLine(start_position.ToString() + " "+ end_position.ToString() + " "+myInterval.ToString());
//if (myInterval == 0.0)
// return;
////X轴视图起点
//chart1.ChartAreas[0].AxisX.ScaleView.Position = Math.Min(start_position, end_position);
////X轴视图长度
//chart1.ChartAreas[0].AxisX.ScaleView.Size = myInterval;
////X轴间隔
//if (myInterval < dateTime.AddMilliseconds(900).ToOADate() - dateTime.ToOADate())
//{
// chart1.ChartAreas[0].AxisX.Interval = 100;
//}
//else
//{
// chart1.ChartAreas[0].AxisX.Interval = Math.Floor(myInterval / 10);
//}
//flag = true;
//if (!comboBox1.Items.Contains("Zoom"))
//{
// comboBox1.Items.Add("Zoom");
// comboBox1.SelectedItem = "Zoom";
//}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedItem.ToString() == "Zoom")
{
flag = true;
}
else if (comboBox1.SelectedItem.ToString() == "OverView" || comboBox1.SelectedItem.ToString() == "Follow")
{
comboBox1.Items.Remove("Zoom");
flag = false;
}
}
Point lastPoint = new Point();//上次点的坐标
ToolTip tp = new ToolTip();//tooltip展示条
//绘制竖线坐标
Point p1 = new Point(0, 0);
Point p2 = new Point(0, 0);
/// <summary>
/// 鼠标移动事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
this.Refresh();//刷新chart,使用clear会使chart上的图形完全清空
Pen pen = new Pen(Color.Yellow);
Graphics g = chart1.CreateGraphics();
string seriesInfo = ""; //tooltip文本
if (e.Location != lastPoint)//如果在上次点的位置不进行操作,此处操作会引发chart控件的refresh操作造成界面闪烁
{
for (int y = 0; y <= chart1.Size.Height; y++)//线条范围进行碰撞检测
{
HitTestResult result = chart1.HitTest(e.X, y);
if (result.ChartElementType == ChartElementType.DataPoint)
{
foreach (DataPoint dpp in result.Series.Points)//数据点默认样式 使用索引的方式修改偶尔会出现无法正常修改完
{
dpp.MarkerStyle = MarkerStyle.Diamond;
dpp.MarkerColor = Color.White;
dpp.MarkerSize = 5;
}
int i = result.PointIndex;
DataPoint dp = result.Series.Points[i];
dp.MarkerStyle = MarkerStyle.Star4;//捕获到数据点的样式
dp.MarkerColor = Color.Orange;
dp.MarkerSize = 15;
//获取数据点的相对坐标
p1 = new Point((int)chart1.ChartAreas[0].AxisX.ValueToPixelPosition(dp.XValue), 0);
p2 = new Point((int)chart1.ChartAreas[0].AxisX.ValueToPixelPosition(dp.XValue), chart1.Size.Height);
seriesInfo = string.Format("分项:{0} 时间:{1} 能耗值:{2}", result.Series.LegendText, DateTime.FromOADate(dp.XValue), dp.YValues[0]);
break;
}
}
tp.AutoPopDelay = 5000;//展示tooltip
tp.ShowAlways = false;
tp.IsBalloon = true;
tp.SetToolTip(chart1, seriesInfo);
}
lastPoint = e.Location;//记录本次位置
g.DrawLine(pen, p1, p2);//绘制竖线
}
}
}
设计界面

需要添加的事件

最终效果


放大效果

辅助线条未关联,可根据实际情况关联就行。
摸着石头过河,感谢其他博主提供的代码,开源万岁!
3046





