winform中使用ZedGraphControl控件做图。
一些方法的总结
public class ChartEx : ZedGraph.ZedGraphControl
{
#region init
private readonly Color[] colorPool = new Color[8];
public int colorPoolIndex { get; set; } = 0;
public ChartEx() : base()
{
InitGui();
InitColorPool();
}
private void InitGui()
{
this.SuspendLayout();
this.Name = "ChartEx";
this.Dock = DockStyle.Fill;
this.IsZoomOnMouseCenter = false;
this.IsEnableHZoom = true;
this.IsEnableVZoom = true;
this.IsSynchronizeXAxes = true;
this.IsSynchronizeYAxes = false;
this.IsShowPointValues = true;
this.MasterPane.Border.IsVisible = false;
this.MasterPane.InnerPaneGap = 1;
this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.chartEx_MouseClick);
this.PointValueEvent += new ZedGraphControl.PointValueHandler(this.chartEx_PointValueEvent);
this.ZoomEvent += new ZedGraph.ZedGraphControl.ZoomEventHandler(this.chartEx_ZoomEvent);
//this.MouseDownEvent += new ZedMouseEventHandler(this.chartEx_MouseDownEvent);
this.ContextMenuBuilder += new ZedGraphControl.ContextMenuBuilderEventHandler(this.chartEx_ContextMenuBuilder);
this.ResumeLayout(false);
}
#endregion
private void InitColorPool()
{
colorPool[0] = ColorPool.Pool[0];
colorPool[1] = ColorPool.Pool[1];
colorPool[2] = ColorPool.Pool[2];
colorPool[3] = ColorPool.Pool[3];
colorPool[4] = ColorPool.Pool[4];
colorPool[5] = ColorPool.Pool[5];
colorPool[6] = ColorPool.Pool[6];
colorPool[7] = ColorPool.Pool[7];
}
public Color GetNextColor()
{
var color = colorPool[0];
if (colorPoolIndex >= colorPool.Length)
{
colorPoolIndex = 0;
}
color = colorPool[colorPoolIndex];
colorPoolIndex++;
return color;
}
#region public function
public GraphPane FormatGraphPane(GraphPane gp)
{
gp.Border.IsVisible = false;
gp.Title.IsVisible = false;
gp.IsFontsScaled = false;
gp.Margin.All = 1;
gp.Legend.IsVisible = true;
gp.Legend.FontSpec.Size = 11;
gp.Legend.FontSpec.FontColor = Color.Black;
gp.Legend.Fill = new Fill(Color.FromArgb(255, 255, 255, 255), Color.FromArgb(255, 255, 255, 255));
gp.Legend.Border.IsVisible = false;
gp.Chart.Border.Color = Color.LightGray;
gp.Fill = new Fill(Color.White, Color.White, 0F);
gp.Chart.Fill = new Fill(Color.White, Color.White, 0);
if (gp.XAxis != null) FormatXAxis(gp.XAxis);
if (gp.YAxis != null) FormatYAxis(gp.YAxis);
return gp;
}
public XAxis FormatXAxis(XAxis xAxis)
{
xAxis.Title.IsVisible = false;
xAxis.Title.FontSpec.Size = 11;
xAxis.Scale.FontSpec.Size = 11;
xAxis.MajorTic.Color = Color.Gray;
xAxis.MinorTic.Color = Color.LightGray;
xAxis.Scale.FontSpec.FontColor = Color.Gray;
xAxis.Title.FontSpec.FontColor = Color.Gray;
return xAxis;
}
public YAxis FormatYAxis(YAxis yAxis)
{
yAxis.Title.IsVisible = false;
yAxis.Title.FontSpec.Size = 11;
yAxis.Scale.FontSpec.Size = 11;
yAxis.Color = Color.LightGray;
yAxis.MajorTic.Color = Color.Gray;
yAxis.MinorTic.Color = Color.LightGray;
yAxis.Scale.FontSpec.FontColor = Color.Gray;
yAxis.Title.FontSpec.FontColor = Color.Gray;
return yAxis;
}
public LineObj DrawLineX(GraphPane gp, double x)
{
return DrawLineX(gp, x, Color.Red);
}
public LineObj DrawLineX(GraphPane gp, double x, Color color)
{
this.AxisChange();
LineObj obj = new LineObj(color, x, gp.YAxis.Scale.Min, x, gp.YAxis.Scale.Max);
obj.Tag = "LineX";
obj.Line.Style = DashStyle.Dash;
obj.ZOrder = ZOrder.E_BehindCurves;
obj.Line.Width = 1;
gp.GraphObjList.Add(obj);
return obj;
}
public LineObj DrawLineY(GraphPane gp, double y)
{
return DrawLineY(gp, y, Color.Red);
}
public LineObj DrawLineY(GraphPane gp, double y, Color color)
{
this.AxisChange();
LineObj obj = new LineObj(color, gp.XAxis.Scale.Min, y, gp.XAxis.Scale.Max, y);
obj.Tag = "LineY";
obj.Line.Style = DashStyle.Dash;
obj.ZOrder = ZOrder.E_BehindCurves;
obj.Line.Width = 1;
gp.GraphObjList.Add(obj);
return obj;
}
public BoxObj DrawRangeX(GraphPane gp, double x1, double x2)
{
return DrawRangeX(gp, x1, x2, Color.Empty, Color.FromArgb(50, Color.LightGreen));
}
public BoxObj DrawRangeX(GraphPane gp, double x1, double x2, Color borderColor, Color fillColor)
{
this.AxisChange();
BoxObj obj = new BoxObj(x1, gp.YAxis.Scale.Max, x2 - x1, gp.YAxis.Scale.Max - gp.YAxis.Scale.Min, borderColor, fillColor);
obj.Tag = "RangeX";
obj.ZOrder = ZOrder.F_BehindGrid;
//obj.IsClippedToChartRect = true;
//obj.Location.CoordinateFrame = CoordType.AxisXYScale;
gp.GraphObjList.Add(obj);
return obj;
}
public BoxObj DrawRangeXWithText(GraphPane gp, double x1, double x2)
{
return DrawRangeXWithText(gp, x1, x2, Color.Empty, Color.FromArgb(50, Color.LightGreen));
}
//2. 多个Range范围标注文字拥挤问题:过载实现一个y轴可以偏移文字标注方法。 内部嵌套的range,y轴向下偏移一个字符的高度。
//ccc-285
public List<TextObj> DrawRangeXWithText(GraphPane gp, double x1, double x2, Color borderColor, Color fillColor, int fontIndex)
{
var fonts = new List<TextObj>(); ;
this.AxisChange();
BoxObj obj = new BoxObj(x1 < x2 ? x1 : x2, gp.YAxis.Scale.Max, Math.Abs(x2 - x1), gp.YAxis.Scale.Max - gp.YAxis.Scale.Min, borderColor, fillColor);
obj.Tag = "RangeX";
obj.ZOrder = ZOrder.F_BehindGrid;
//obj.IsClippedToChartRect = true;
//obj.Location.CoordinateFrame = CoordType.AxisXYScale;
gp.GraphObjList.Add(obj);
if (x1 > x2)
{
double temp = x1;
x1 = x2;
x2 = temp;
}
fonts.Add(DrawTextX(gp, x1, $"{x1}>", Color.Black, fontIndex, AlignH.Right));
fonts.Add(DrawTextX(gp, x2, $"<{x2}", Color.Black, fontIndex, AlignH.Left));
return fonts;
}
public BoxObj DrawRangeXWithText(GraphPane gp, double x1, double x2, Color borderColor, Color fillColor)
{
this.AxisChange();
BoxObj obj = new BoxObj(x1 < x2 ? x1 : x2, gp.YAxis.Scale.Max, Math.Abs(x2 - x1), gp.YAxis.Scale.Max - gp.YAxis.Scale.Min, borderColor, fillColor);
obj.Tag = "RangeX";
obj.ZOrder = ZOrder.F_BehindGrid;
//obj.IsClippedToChartRect = true;
//obj.Location.CoordinateFrame = CoordType.AxisXYScale;
gp.GraphObjList.Add(obj);
if (x1 > x2)
{
double temp = x1;
x1 = x2;
x2 = temp;
}
DrawTextX(gp, x1, $"{x1}>", Color.Black, AlignH.Right);
DrawTextX(gp, x2, $"<{x2}", Color.Black, AlignH.Left);
return obj;
}
public BoxObj DrawRangeY(GraphPane gp, double y1, double y2)
{
return DrawRangeY(gp, y1, y2, Color.Empty, Color.FromArgb(50, Color.LightGreen));
}
public BoxObj DrawRangeY(GraphPane gp, double y1, double y2, Color borderColor, Color fillColor)
{
this.AxisChange();
BoxObj obj = new BoxObj(gp.XAxis.Scale.Min, y2, gp.XAxis.Scale.Max - gp.XAxis.Scale.Min, y2 - y1, borderColor, fillColor);
obj.Tag = "RangeY";
obj.ZOrder = ZOrder.F_BehindGrid;
//box.IsClippedToChartRect = true;
//box.Location.CoordinateFrame = CoordType.AxisXYScale;
gp.GraphObjList.Add(obj);
return obj;
}
public TextObj DrawTextX(GraphPane gp, double x, string text, Color color, AlignH alignH = AlignH.Left)
{
this.AxisChange();
TextObj obj = new TextObj(text, x, gp.YAxis.Scale.Max, CoordType.AxisXYScale, alignH, AlignV.Top);
obj.Tag = "TextX";
obj.FontSpec.Border.IsVisible = false;
obj.FontSpec.Fill.Color = Color.FromArgb(0, 0, 0, 0);
obj.FontSpec.Size = 12;
obj.FontSpec.FontColor = color;
obj.ZOrder = ZOrder.E_BehindCurves;
gp.GraphObjList.Add(obj);
return obj;
}
public TextObj DrawTextX(GraphPane gp, double x, string text, Color color, int ordinal, AlignH alignH = AlignH.Left)
{
this.AxisChange();
TextObj obj = new TextObj(text, x, gp.YAxis.Scale.Max, CoordType.AxisXYScale, alignH, AlignV.Top);
obj.Tag = "TextX";
obj.FontSpec.Border.IsVisible = false;
obj.FontSpec.Fill.Color = Color.FromArgb(0, 0, 0, 0);
obj.FontSpec.Size = 12;
obj.FontSpec.FontColor = color;
obj.ZOrder = ZOrder.E_BehindCurves;
gp.GraphObjList.Add(obj);
//obj.Location.Y = obj.Location.Y - ((double)ordinal) * 12;
return obj;
}
public TextObj DrawTextY(GraphPane gp, double y, string text, Color color, AlignV alignV = AlignV.Top)
{
this.AxisChange();
TextObj obj = new TextObj(text, gp.XAxis.Scale.Max, y, CoordType.AxisXYScale, AlignH.Right, alignV);
obj.Tag = "TextY";
obj.FontSpec.Border.IsVisible = false;
obj.FontSpec.Fill.Color = Color.FromArgb(0, 0, 0, 0);
obj.FontSpec.Size = 12;
obj.FontSpec.FontColor = color;
obj.ZOrder = ZOrder.E_BehindCurves;
gp.GraphObjList.Add(obj);
return obj;
}
#endregion
#region private function
private void chartEx_ContextMenuBuilder(ZedGraphControl control, ContextMenuStrip menuStrip, Point mousePt, ZedGraphControl.ContextMenuObjectState objState)
{
{//remove default menu item
foreach (ToolStripMenuItem item in menuStrip.Items)
{
if ((string)item.Tag == "page_setup") item.Visible = false;
if ((string)item.Tag == "print") item.Visible = false;
//if ((string) item.Tag == "set_default") item.Visible = false;
if ((string)item.Tag == "undo_all") item.Visible = false;
if ((string)item.Tag == "unzoom") item.Visible = false;
}
}
{//add new menu item
var sep = new ToolStripSeparator();
menuStrip.Items.Add(sep);
var item = new ToolStripMenuItem();
item.Name = "menuZoomXY";
item.Tag = "menuZoomXY";
item.Text = "Zoom X Only";
item.Click += new System.EventHandler(menuZoomXY_event);
item.Checked = !this.IsEnableVZoom;
menuStrip.Items.Add(item);
}
}
protected void menuZoomXY_event(object sender, System.EventArgs e)
{
Logger.Debug($"menuZoomXY_event object={sender}, System.EventArgs={e}");
this.IsEnableHZoom = true;
this.IsEnableVZoom = !this.IsEnableVZoom;
}
private bool chartEx_MouseDownEvent(ZedGraphControl sender, MouseEventArgs e)
{
//TODO
Logger.Debug($"chartEx_MouseDownEvent ZedGraphControl={sender}, MouseEventArgs={e}");
foreach (GraphPane gp in sender.MasterPane.PaneList)
{
object clickedObject;
var index = int.MinValue;
var g = this.CreateGraphics();
var isObjectFound = gp.FindNearestObject(e.Location, g, out clickedObject, out index);
if (!isObjectFound) continue;
if (!(clickedObject is Legend)) continue;
if (gp.Legend == null || index < 0) continue;
gp.CurveList.Move(index, -index);
/*
var nearestCurve = (LineItem)gp.CurveList[index];
nearestCurve.IsVisible = !nearestCurve.IsVisible;
*/
}
return true;
}
private string chartEx_PointValueEvent(ZedGraphControl sender, GraphPane pane, CurveItem curve, int iPt)
{
var curveName = curve.Label.Text.ToString();
var pt = curve[iPt];
return String.Format("{0}\r\nY: {1} [{2}]\r\nX: {3}", curveName, pt.Y, "0x" + ((long)pt.Y).ToString("X"), pt.X);
}
private void chartEx_ZoomEvent(ZedGraphControl sender, ZoomState oldState, ZoomState newState)
{
this.RefreshDraw();
}
private readonly Dictionary<GraphPane, LineObj> clickMarkerLineDict = new Dictionary<GraphPane, LineObj>();
private void chartEx_MouseClick(object sender, MouseEventArgs e)
{
double x, y;
try
{
this.GraphPane.ReverseTransform(e.Location, out x, out y); // get X & Y CO-Ordinates by current mouse location
}
catch (NullReferenceException nex)
{
nex.ToString();
return;
}
foreach (GraphPane gp in this.MasterPane.PaneList)
{
{ // draw dash line
LineObj lineX = null;
var isOk = clickMarkerLineDict.TryGetValue(gp, out lineX);
if (isOk) gp.GraphObjList.Remove(lineX); // Clear the previous values if any
lineX = new LineObj(Color.DarkGray, x, gp.YAxis.Scale.Min, x, gp.YAxis.Scale.Max);
lineX.Tag = "LineX";
lineX.Line.Style = DashStyle.Dash;
lineX.ZOrder = ZOrder.E_BehindCurves;
gp.GraphObjList.Add(lineX);
if (clickMarkerLineDict.ContainsKey(gp)) clickMarkerLineDict.Remove(gp);
clickMarkerLineDict.Add(gp, lineX);
this.Refresh();
}
{ // show curve on top
object clickedObject;
var index = int.MinValue;
var g = this.CreateGraphics();
var isObjectFound = gp.FindNearestObject(e.Location, g, out clickedObject, out index);
if (!isObjectFound) continue;
if (!(clickedObject is Legend)) continue;
if (gp.Legend == null || index < 0) continue;
gp.CurveList.Move(index, -index);
}
}
}
// an example for reformat y axis label
// if (isHex) yAxis.ScaleFormatEvent += new YAxis.ScaleFormatHandler(this.chartX_ScaleFormatHandler);
public string chartEx_ScaleFormatHandler(GraphPane pane, Axis axis, double val, int index)
{
var v = (long)val;
return "0x" + v.ToString("X");
}
private void RefreshDraw()
{
foreach (var gp in this.MasterPane.PaneList)
{
foreach (var gObj in gp.GraphObjList)
{
if (gObj is LineObj)
{
var line = (LineObj)gObj;
var tag = (string)line.Tag;
if ("LineX".Equals(tag))
{
line.Location.Y = gp.YAxis.Scale.Min;
line.Location.Height = gp.YAxis.Scale.Max - gp.YAxis.Scale.Min;
}
else if ("LineY".Equals(tag))
{
line.Location.X = gp.XAxis.Scale.Min;
line.Location.Width = gp.XAxis.Scale.Max - gp.XAxis.Scale.Min;
}
}
else if (gObj is BoxObj)
{
var box = (BoxObj)gObj;
var tag = (string)box.Tag;
if ("RangeX".Equals(tag))
{
box.Location.Y = gp.YAxis.Scale.Max;
box.Location.Height = gp.YAxis.Scale.Max - gp.YAxis.Scale.Min;
}
else if ("RangeY".Equals(tag))
{
box.Location.X = gp.XAxis.Scale.Min;
box.Location.Width = gp.XAxis.Scale.Max - gp.XAxis.Scale.Min;
}
}
else if (gObj is TextObj)
{
var text = (TextObj)gObj;
var tag = (string)text.Tag;
if ("TextX".Equals(tag))
{
text.Location.Y = gp.YAxis.Scale.Max;
}
else if ("TextY".Equals(tag))
{
text.Location.X = gp.XAxis.Scale.Max;
}
}
}
}
}
#endregion
public static void ShowCase(DataRow[] rows, params string[] signals)
{
//1. draw line 1
var chart = new ChartEx();
var gp = chart.GraphPane;
gp = chart.FormatGraphPane(gp);
List<PointPairList> ppls = new List<PointPairList>();
signals.ToList().ForEach(s =>
{
var ppl = new PointPairList();
for (int i = 0; i < rows.Length; i++)
{
var row = rows[i];
var time = (double)row["TIME"];
var val = (double)row[s];
ppl.Add(time, val);
}
ppls.Add(ppl);
var line = gp.AddCurve(s, ppl, chart.GetNextColor(), SymbolType.None);
});
chart.AxisChange();
chart.Refresh();
using (var g = chart.CreateGraphics())
{
//chart.MasterPane.SetLayout(g, PaneLayout.SquareRowPreferred);
chart.MasterPane.SetLayout(g, PaneLayout.SingleColumn);
}
var frm = new Form();
frm.StartPosition = FormStartPosition.CenterScreen;
frm.Controls.Add(chart);
frm.ShowDialog();
}
#region showcase
public static ChartEx ShowCase(bool inForm = true)
{
var ppl = new PointPairList();
ppl.Add(1, 7);
ppl.Add(2, 3);
ppl.Add(3, 1);
ppl.Add(4, 2.5);
var ppl1 = new PointPairList();
ppl1.Add(1, 1);
ppl1.Add(2, 3);
ppl1.Add(3, 6);
ppl1.Add(4, 3);
var ppl2 = new PointPairList();
ppl2.Add(1, 8);
ppl2.Add(2, 2.4);
ppl2.Add(3, 4);
ppl2.Add(4, 6);
//1. draw line 1
var chart = new ChartEx();
var gp = chart.GraphPane;
gp = chart.FormatGraphPane(gp);
//gp.XAxis.Title.Text = "Timestamp (Seconds)";
gp.YAxis.Title.Text = "lalala";
//LineItem line = gp.AddCurve("test", ppl, Color.Blue, SymbolType.None);
var i = gp.AddYAxis("test");
//gp.YAxisList[i].Color = Color.Orange;
//gp.YAxisList[i].Scale.IsVisible = false;
//gp.YAxisList[i].MajorTic.IsAllTics = false;
//gp.YAxisList[i].MinorTic.IsAllTics = false;
{
var line = gp.AddCurve("test1", ppl2, Color.Yellow, SymbolType.Default);
line.Line.IsVisible = false;
line.YAxisIndex = i;
}
{
var line = gp.AddCurve("test1", ppl, Color.Blue, SymbolType.None);
line.YAxisIndex = i;
}
var gp2 = new GraphPane();
gp2 = chart.FormatGraphPane(gp2);
gp2.Margin.Left = 93;
gp2.XAxis.Title.Text = "Timestamp (Seconds)";
chart.MasterPane.Add(gp2);
{
var line = gp2.AddCurve("test2", ppl1, Color.Red, SymbolType.Circle);
line.Line.IsSmooth = true;
//line.YAxisIndex = i;
}
{
chart.DrawLineX(gp, 3.5, Color.Red);
chart.DrawTextX(gp, 3.5, "Left", Color.Red);
chart.DrawTextX(gp, 3.5, "Right", Color.Red, AlignH.Right);
}
{
chart.DrawLineY(gp2, 3, Color.Red);
chart.DrawTextY(gp2, 3, "top:3", Color.Red);
chart.DrawTextY(gp2, 3, "Bottom:3", Color.Red, AlignV.Bottom);
}
{
var box = chart.DrawRangeX(gp, 2, 3, Color.Empty, Color.FromArgb(150, Color.LightGreen));
chart.DrawRangeX(gp2, 2, 3, Color.Empty, Color.FromArgb(150, Color.LightGreen));
//BoxObj box = chart.drawRangeY(gp, 2, 3, Color.Empty, Color.FromArgb(150, Color.LightGreen));
}
chart.Width = 400;
chart.Height = 300;
//chart.AxisChange();
chart.Refresh();
using (var g = chart.CreateGraphics())
{
//chart.MasterPane.SetLayout(g, PaneLayout.SquareRowPreferred);
chart.MasterPane.SetLayout(g, PaneLayout.SingleColumn);
}
//TextObj to = new TextObj("ZoomFlag", 3, 1);
//to.FontSpec.Border.IsVisible = false;
//to.FontSpec.Fill.Color = Color.FromArgb(0, 0, 0, 0);
//to.FontSpec.Size = 12;
//to.FontSpec.FontColor = Color.Blue;
//to.ZOrder = ZOrder.E_BehindCurves;
//gp.GraphObjList.Add(to);
//var pf = to.Location.Transform(gp);
var loc3 = new Location(3, 1, CoordType.AxisXYScale);
var pf2 = loc3.Transform(gp);
//gp2.GraphObjList.Add(to);
//chart.Refresh();
//gp2.XAxis.Scale.Min = 4;
//gp2.XAxis.Scale.Max = 6;
//var x = gp.XAxis.Scale.Max;
//var y = gp.XAxis.Scale.Min;
//var x1 = gp2.XAxis.Scale.Max;
//var y1 = gp2.XAxis.Scale.Min;
//chart.ZoomPane(gp, 5, pf2, false, true);//every +n, xaxis portion add by n*max, set false for zoom center, shrink, zoom out fraction
//chart.AxisChange();
chart.Refresh();
chart.Refresh();
var x = gp.XAxis.Scale.Max;
var y = gp.XAxis.Scale.Min;
var x1 = gp2.XAxis.Scale.Max;
var y1 = gp2.XAxis.Scale.Min;
chart.IsEnableHZoom = true;
chart.IsEnableVZoom = false;
double axisStart = 0;
double axisEnd = 20;
double fraction = (axisEnd - axisStart) / x - y;
chart.ZoomPane(chart.GraphPane, fraction, new PointF(3, 1), false);
gp.XAxis.Scale.Min = axisStart;
gp.XAxis.Scale.Max = axisEnd;
//chart.GraphPane.XAxis.Scale.Min = 0;
//chart.GraphPane.XAxis.Scale.Max = 100;
//chart.AxisChange();
chart.Refresh();
if (inForm)
{
var frm = new Form() { Width = 800, Height = 600 };
frm.StartPosition = FormStartPosition.CenterScreen;
frm.Controls.Add(chart);
frm.ShowDialog();
}
return chart;
}
#endregion
}