原文来自CodeProject。
有一项目需要在界面上显示采集到的数据,类似于NI中Graph控件,但C#中没有显示数据的控件,所以找到这篇文章来看看。
Introduction
在我们的应用中,需要输出多通道的心电图;查看商业代码库,没找到,所以就想设计出一个方便自己的简单应用:灵活易用的图表;
设计的库可以以不同模式显示多种图形;目前,可以显示5种模式:
1)通用:所有的数据显示在一个图形上,但对应不同得坐标;
2)叠加:所有数据显示在同一个图形上,竖直方向迭起,共享相同的横坐标轴不同的坐标;
3)竖直对齐:图表竖直方向对齐,共享相同的横坐标轴不同的坐标;
4)水平叠加:图形窗体竖直排列;
5)竖直叠加:图形窗体水平排列;
图形显示时可以为原始显示或自动缩放;在自动缩放模式,可见的图表部分自动填充满可视区域;
下面分别显示的是不同的模式:
通用:
叠加:
水平叠加:
竖直叠加:
竖直对齐:
自动缩放X轴:
右图是简单的心电图,8个数据源竖直叠加并自动缩放:
Using the Code
代码使用比较简单;只要看看下面简单的应用就行;下面的代码显示不同模式下设置:
protected void CalcDataGraphs()
{
this.SuspendLayout();
display.DataSources.Clear();
display.SetDisplayRangeX(0, 400);
for (int j = 0; j < NumGraphs; j++)
{
display.DataSources.Add(new DataSource());
display.DataSources[j].Name = "Graph " + (j + 1);
display.DataSources[j].OnRenderXAxisLabel += RenderXLabel;
switch (CurExample)
{
case "NORMAL":
this.Text = "Normal Graph";
display.DataSources[j].Length = 5800;
display.PanelLayout = PlotterGraphPaneEx.LayoutMode.NORMAL;
display.DataSources[j].AutoScaleY = false;
display.DataSources[j].SetDisplayRangeY(-300, 300);
display.DataSources[j].SetGridDistanceY(100);
display.DataSources[j].OnRenderYAxisLabel = RenderYLabel;
CalcSinusFunction_0(display.DataSources[j], j);
break;
case "NORMAL_AUTO":
this.Text = "Normal Graph Autoscaled";
display.DataSources[j].Length = 5800;
display.PanelLayout = PlotterGraphPaneEx.LayoutMode.NORMAL;
display.DataSources[j].AutoScaleY = true;
display.DataSources[j].SetDisplayRangeY(-300, 300);
display.DataSources[j].SetGridDistanceY(100);
display.DataSources[j].OnRenderYAxisLabel = RenderYLabel;
CalcSinusFunction_0(display.DataSources[j], j);
break;
case "STACKED":
this.Text = "Stacked Graph";
display.PanelLayout = PlotterGraphPaneEx.LayoutMode.STACKED;
display.DataSources[j].Length = 5800;
display.DataSources[j].AutoScaleY = false;
display.DataSources[j].SetDisplayRangeY(-250, 250);
display.DataSources[j].SetGridDistanceY(100);
CalcSinusFunction_1(display.DataSources[j], j);
break;
case "VERTICAL_ALIGNED":
this.Text = "Vertical aligned Graph";
display.PanelLayout =
PlotterGraphPaneEx.LayoutMode.VERTICAL_ARRANGED;
display.DataSources[j].Length = 5800;
display.DataSources[j].AutoScaleY = false;
display.DataSources[j].SetDisplayRangeY(-300, 300);
display.DataSources[j].SetGridDistanceY(100);
CalcSinusFunction_2(display.DataSources[j], j);
break;
case "VERTICAL_ALIGNED_AUTO":
this.Text = "Vertical aligned Graph autoscaled";
display.PanelLayout =
PlotterGraphPaneEx.LayoutMode.VERTICAL_ARRANGED;
display.DataSources[j].Length = 5800;
display.DataSources[j].AutoScaleY = true;
display.DataSources[j].SetDisplayRangeY(-300, 300);
display.DataSources[j].SetGridDistanceY(100);
CalcSinusFunction_2(display.DataSources[j], j);
break;
case "TILED_VERTICAL":
this.Text = "Tiled Graphs (vertical prefered)";
display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_VER;
display.DataSources[j].Length = 5800;
display.DataSources[j].AutoScaleY = false;
display.DataSources[j].SetDisplayRangeY(-300, 600);
display.DataSources[j].SetGridDistanceY(100);
CalcSinusFunction_2(display.DataSources[j], j);
break;
case "TILED_VERTICAL_AUTO":
this.Text = "Tiled Graphs (vertical prefered) autoscaled";
display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_VER;
display.DataSources[j].Length = 5800;
display.DataSources[j].AutoScaleY = true;
display.DataSources[j].SetDisplayRangeY(-300, 600);
display.DataSources[j].SetGridDistanceY(100);
CalcSinusFunction_2(display.DataSources[j], j);
break;
case "TILED_HORIZONTAL":
this.Text = "Tiled Graphs (horizontal prefered)";
display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_HOR;
display.DataSources[j].Length = 5800;
display.DataSources[j].AutoScaleY = false;
display.DataSources[j].SetDisplayRangeY(-300, 600);
display.DataSources[j].SetGridDistanceY(100);
CalcSinusFunction_2(display.DataSources[j], j);
break;
case "TILED_HORIZONTAL_AUTO":
this.Text = "Tiled Graphs (horizontal prefered) autoscaled";
display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_HOR;
display.DataSources[j].Length = 5800;
display.DataSources[j].AutoScaleY = true;
display.DataSources[j].SetDisplayRangeY(-300, 600);
display.DataSources[j].SetGridDistanceY(100);
CalcSinusFunction_2(display.DataSources[j], j);
break;
case "ANIMATED_AUTO":
this.Text = "Animated graphs fixed x range";
display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_HOR;
display.DataSources[j].Length = 402;
display.DataSources[j].AutoScaleY = false;
display.DataSources[j].AutoScaleX = true;
display.DataSources[j].SetDisplayRangeY(-300, 500);
display.DataSources[j].SetGridDistanceY(100);
display.DataSources[j].XAutoScaleOffset = 50;
CalcSinusFunction_3(display.DataSources[j], j, 0);
display.DataSources[j].OnRenderYAxisLabel = RenderYLabel;
break;
}
}
ApplyColorSchema();
this.ResumeLayout();
display.Refresh();
}
函数CalcSinusFunction_0
/1/2用于计算显示用的sin数据:
protected void CalcSinusFunction_0(DataSource src, int idx)
{
for (int i = 0; i < src.Length; i++)
{
src.Samples[i].x = i;
src.Samples[i].y = (float)(((float)200 * Math.Sin((idx + 1) *(
i + 1.0) * 48 / src.Length)));
}
}
函数RenderYLabel
/X用于显示图例Y/X:
private String RenderXLabel(DataSource s, int idx)
{
if (s.AutoScaleX)
{
int Value = (int)(s.Samples[idx].x );
return "" + Value;
}
else
{
int Value = (int)(s.Samples[idx].x / 200);
String Label = "" + Value + "\"";
return Label;
}
}
private String RenderYLabel(DataSource s, float value)
{
return String.Format("{0:0.0}", value);
}
Summary
代码中有很多参数在这里没有解释,我们只能多看代码;整个库还远未结束,但是个好的开端;代码简单易懂,易于使用。
源代码见这儿。