Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Visualization/3.2/LineChart.cs @ 1876

Last change on this file since 1876 was 1876, checked in by mstoeger, 15 years ago

x-axis grid can be enabled/disabled #629

File size: 23.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Drawing;
4using System.Drawing.Drawing2D;
5using System.Windows.Forms;
6using HeuristicLab.Core;
7using HeuristicLab.Visualization.DataExport;
8using HeuristicLab.Visualization.Legend;
9using HeuristicLab.Visualization.Options;
10using HeuristicLab.Visualization.Test;
11
12namespace HeuristicLab.Visualization {
13  public partial class LineChart : ViewBase {
14    private readonly IChartDataRowsModel model;
15    private readonly Canvas canvas;
16
17    private readonly TextShape titleShape = new TextShape("Title");
18    private readonly LegendShape legendShape = new LegendShape();
19    private readonly XAxis xAxis = new XAxis();
20    private readonly XAxisGrid xAxisGrid = new XAxisGrid();
21    private readonly List<RowEntry> rowEntries = new List<RowEntry>();
22
23    private readonly Dictionary<IDataRow, RowEntry> rowToRowEntry = new Dictionary<IDataRow, RowEntry>();
24
25    private readonly ViewSettings viewSettings;
26
27    private readonly WorldShape userInteractionShape = new WorldShape();
28    private readonly RectangleShape rectangleShape = new RectangleShape(0, 0, 0, 0, Color.FromArgb(50, 0, 0, 255));
29    private IMouseEventListener mouseEventListener;
30
31    private const int YAxisWidth = 100;
32    private const int XAxisHeight = 40;
33
34    /// <summary>
35    /// This constructor shouldn't be called. Only required for the designer.
36    /// </summary>
37    public LineChart() {
38      InitializeComponent();
39    }
40
41    /// <summary>
42    /// Initializes the chart.
43    /// </summary>
44    /// <param name="model">Referenz to the model, for data</param>
45    public LineChart(IChartDataRowsModel model) : this() {
46      if (model == null) {
47        throw new NullReferenceException("Model cannot be null.");
48      }
49
50      canvas = canvasUI.Canvas;
51
52      this.model = model;
53      viewSettings = model.ViewSettings;
54      viewSettings.OnUpdateSettings += UpdateViewSettings;
55
56      Item = model;
57
58      UpdateLayout();
59      canvasUI.Resize += delegate { UpdateLayout(); };
60
61      ZoomToFullView();
62    }
63
64    /// <summary>
65    /// updates the view settings
66    /// </summary>
67    private void UpdateViewSettings() {
68      titleShape.Font = viewSettings.TitleFont;
69      titleShape.Color = viewSettings.TitleColor;
70      titleShape.Text = model.Title;
71
72      legendShape.Font = viewSettings.LegendFont;
73      legendShape.Color = viewSettings.LegendColor;
74
75      xAxis.Font = viewSettings.XAxisFont;
76      xAxis.Color = viewSettings.XAxisColor;
77
78      SetLegendPosition();
79
80      canvasUI.Invalidate();
81    }
82
83    /// <summary>
84    /// Layout management - arranges the inner shapes.
85    /// </summary>
86    private void UpdateLayout() {
87      canvas.ClearShapes();
88
89      titleShape.Text = model.Title;
90
91      if (model.ShowXAxisGrid) {
92        canvas.AddShape(xAxisGrid);
93      }
94
95      foreach (YAxisDescriptor yAxisDescriptor in model.YAxes) {
96        YAxisInfo info = GetYAxisInfo(yAxisDescriptor);
97        if (yAxisDescriptor.ShowGrid) {
98          info.Grid.Color = yAxisDescriptor.GridColor;
99          canvas.AddShape(info.Grid);
100        }
101      }
102
103      foreach (RowEntry rowEntry in rowEntries) {
104        canvas.AddShape(rowEntry.LinesShape);
105      }
106
107      xAxis.ShowLabel = model.ShowXAxisLabel;
108      xAxis.Label = model.XAxisLabel;
109
110      canvas.AddShape(xAxis);
111
112      int yAxesWidthLeft = 0;
113      int yAxesWidthRight = 0;
114
115      foreach (YAxisDescriptor yAxisDescriptor in model.YAxes) {
116        YAxisInfo info = GetYAxisInfo(yAxisDescriptor);
117        if (yAxisDescriptor.ShowYAxis) {
118          canvas.AddShape(info.YAxis);
119          info.YAxis.ShowLabel = yAxisDescriptor.ShowYAxisLabel;
120          info.YAxis.Label = yAxisDescriptor.Label;
121          info.YAxis.Position = yAxisDescriptor.Position;
122          switch (yAxisDescriptor.Position) {
123            case AxisPosition.Left:
124              yAxesWidthLeft += YAxisWidth;
125              break;
126            case AxisPosition.Right:
127              yAxesWidthRight += YAxisWidth;
128              break;
129            default:
130              throw new NotImplementedException();
131          }
132        }
133      }
134
135      canvas.AddShape(titleShape);
136      canvas.AddShape(legendShape);
137
138      canvas.AddShape(userInteractionShape);
139
140      titleShape.X = 10;
141      titleShape.Y = canvasUI.Height - 10;
142
143      RectangleD linesAreaBoundingBox = new RectangleD(yAxesWidthLeft,
144                                                       XAxisHeight,
145                                                       canvasUI.Width - yAxesWidthRight,
146                                                       canvasUI.Height);
147
148      foreach (RowEntry rowEntry in rowEntries) {
149        rowEntry.LinesShape.BoundingBox = linesAreaBoundingBox;
150      }
151
152      xAxisGrid.BoundingBox = linesAreaBoundingBox;
153
154      foreach (YAxisDescriptor yAxisDescriptor in model.YAxes) {
155        YAxisInfo info = GetYAxisInfo(yAxisDescriptor);
156        info.Grid.BoundingBox = linesAreaBoundingBox;
157      }
158
159      int yAxisLeft = 0;
160      int yAxisRight = (int)linesAreaBoundingBox.X2;
161
162      foreach (YAxisDescriptor yAxisDescriptor in model.YAxes) {
163        YAxisInfo info = GetYAxisInfo(yAxisDescriptor);
164        if (yAxisDescriptor.ShowYAxis) {
165          switch (yAxisDescriptor.Position) {
166            case AxisPosition.Left:
167              info.YAxis.BoundingBox = new RectangleD(yAxisLeft,
168                                                      linesAreaBoundingBox.Y1,
169                                                      yAxisLeft + YAxisWidth,
170                                                      linesAreaBoundingBox.Y2);
171              yAxisLeft += YAxisWidth;
172              break;
173            case AxisPosition.Right:
174              info.YAxis.BoundingBox = new RectangleD(yAxisRight,
175                                                      linesAreaBoundingBox.Y1,
176                                                      yAxisRight + YAxisWidth,
177                                                      linesAreaBoundingBox.Y2);
178              yAxisRight += YAxisWidth;
179              break;
180            default:
181              throw new NotImplementedException();
182          }
183        }
184      }
185
186      userInteractionShape.BoundingBox = linesAreaBoundingBox;
187      userInteractionShape.ClippingArea = new RectangleD(0, 0, userInteractionShape.BoundingBox.Width, userInteractionShape.BoundingBox.Height);
188
189      xAxis.BoundingBox = new RectangleD(linesAreaBoundingBox.X1,
190                                         0,
191                                         linesAreaBoundingBox.X2,
192                                         linesAreaBoundingBox.Y1);
193
194      SetLegendPosition();
195    }
196
197    private readonly Dictionary<YAxisDescriptor, YAxisInfo> yAxisInfos = new Dictionary<YAxisDescriptor, YAxisInfo>();
198
199    private YAxisInfo GetYAxisInfo(YAxisDescriptor yAxisDescriptor) {
200      YAxisInfo info;
201
202      if (!yAxisInfos.TryGetValue(yAxisDescriptor, out info)) {
203        info = new YAxisInfo();
204        yAxisInfos[yAxisDescriptor] = info;
205      }
206
207      return info;
208    }
209
210    /// <summary>
211    /// sets the legend position
212    /// </summary>
213    private void SetLegendPosition() {
214      switch (viewSettings.LegendPosition) {
215        case LegendPosition.Bottom:
216          setLegendBottom();
217          break;
218
219        case LegendPosition.Top:
220          setLegendTop();
221          break;
222
223        case LegendPosition.Left:
224          setLegendLeft();
225          break;
226
227        case LegendPosition.Right:
228          setLegendRight();
229          break;
230      }
231    }
232
233    public void setLegendRight() {
234      // legend right
235      legendShape.BoundingBox = new RectangleD(canvasUI.Width - legendShape.GetMaxLabelLength(), 10, canvasUI.Width, canvasUI.Height - 50);
236      legendShape.ClippingArea = new RectangleD(0, 0, legendShape.BoundingBox.Width, legendShape.BoundingBox.Height);
237      legendShape.Row = false;
238      legendShape.CreateLegend();
239    }
240
241    public void setLegendLeft() {
242      // legend left
243      legendShape.BoundingBox = new RectangleD(10, 10, canvasUI.Width, canvasUI.Height - 50);
244      legendShape.ClippingArea = new RectangleD(0, 0, legendShape.BoundingBox.Width, legendShape.BoundingBox.Height);
245      legendShape.Row = false;
246      legendShape.CreateLegend();
247
248      canvasUI.Invalidate();
249    }
250
251    public void setLegendTop() {
252      // legend top
253      legendShape.BoundingBox = new RectangleD(100, canvasUI.Height - canvasUI.Height, canvasUI.Width, canvasUI.Height - 10);
254      legendShape.ClippingArea = new RectangleD(0, 0, legendShape.BoundingBox.Width, legendShape.BoundingBox.Height);
255      legendShape.Row = true;
256      legendShape.Top = true;
257      legendShape.CreateLegend();
258    }
259
260    public void setLegendBottom() {
261      // legend bottom
262      legendShape.BoundingBox = new RectangleD(100, 10, canvasUI.Width, canvasUI.Height /*legendShape.GetHeight4Rows()*/);
263      legendShape.ClippingArea = new RectangleD(0, 0, legendShape.BoundingBox.Width, legendShape.BoundingBox.Height);
264      legendShape.Row = true;
265      legendShape.Top = false;
266      legendShape.CreateLegend();
267    }
268
269    private void optionsToolStripMenuItem_Click(object sender, EventArgs e) {
270      OptionsDialog optionsdlg = new OptionsDialog(model);
271      optionsdlg.Show();
272    }
273
274    private void exportToolStripMenuItem_Click(object sender, EventArgs e) {
275      ExportDialog exportdlg = new ExportDialog();
276      exportdlg.ShowDialog(this);
277
278      IExporter exporter = exportdlg.SelectedExporter;
279
280      if (exporter != null)
281        exporter.Export(model);
282    }
283
284    public void OnDataRowChanged(IDataRow row) {
285      RowEntry rowEntry = rowToRowEntry[row];
286
287      rowEntry.LinesShape.UpdateStyle(row);
288
289      UpdateLayout();
290
291      canvasUI.Invalidate();
292    }
293
294    #region Add-/RemoveItemEvents
295
296    protected override void AddItemEvents() {
297      base.AddItemEvents();
298
299      model.DataRowAdded += OnDataRowAdded;
300      model.DataRowRemoved += OnDataRowRemoved;
301      model.ModelChanged += OnModelChanged;
302
303      foreach (IDataRow row in model.Rows) {
304        OnDataRowAdded(row);
305      }
306    }
307
308    protected override void RemoveItemEvents() {
309      base.RemoveItemEvents();
310
311      model.DataRowAdded -= OnDataRowAdded;
312      model.DataRowRemoved -= OnDataRowRemoved;
313      model.ModelChanged -= OnModelChanged;
314    }
315
316    private void OnDataRowAdded(IDataRow row) {
317      row.ValueChanged += OnRowValueChanged;
318      row.ValuesChanged += OnRowValuesChanged;
319      row.DataRowChanged += OnDataRowChanged;
320
321      legendShape.AddLegendItem(new LegendItem(row.Label, row.Color, row.Thickness));
322      legendShape.CreateLegend();
323
324      InitLineShapes(row);
325
326      UpdateLayout();
327    }
328
329    private void OnDataRowRemoved(IDataRow row) {
330      row.ValueChanged -= OnRowValueChanged;
331      row.ValuesChanged -= OnRowValuesChanged;
332      row.DataRowChanged -= OnDataRowChanged;
333
334      rowToRowEntry.Remove(row);
335      rowEntries.RemoveAll(delegate(RowEntry rowEntry) { return rowEntry.DataRow == row; });
336
337      UpdateLayout();
338    }
339
340    #endregion
341
342    public void ZoomToFullView() {
343      SetClipX(-0.1, model.MaxDataRowValues - 0.9);
344
345      foreach (RowEntry rowEntry in rowEntries) {
346        YAxisDescriptor yAxisDescriptor = rowEntry.DataRow.YAxis;
347
348        SetClipY(rowEntry,
349                 yAxisDescriptor.MinValue - ((yAxisDescriptor.MaxValue - yAxisDescriptor.MinValue)*0.05),
350                 yAxisDescriptor.MaxValue + ((yAxisDescriptor.MaxValue - yAxisDescriptor.MinValue)*0.05));
351      }
352
353      canvasUI.Invalidate();
354    }
355
356    private void SetClipX(double x1, double x2) {
357      xAxisGrid.ClippingArea = new RectangleD(x1,
358                                              xAxisGrid.ClippingArea.Y1,
359                                              x2,
360                                              xAxisGrid.ClippingArea.Y2);
361
362      xAxis.ClippingArea = new RectangleD(x1,
363                                          0,
364                                          x2,
365                                          XAxisHeight);
366
367      foreach (RowEntry rowEntry in rowEntries) {
368        rowEntry.LinesShape.ClippingArea = new RectangleD(x1,
369                                                          rowEntry.LinesShape.ClippingArea.Y1,
370                                                          x2,
371                                                          rowEntry.LinesShape.ClippingArea.Y2);
372      }
373
374      foreach (YAxisDescriptor yAxisDescriptor in model.YAxes) {
375        YAxisInfo info = GetYAxisInfo(yAxisDescriptor);
376        info.Grid.ClippingArea = new RectangleD(x1,
377                                                info.Grid.ClippingArea.Y1,
378                                                x2,
379                                                info.Grid.ClippingArea.Y2);
380        info.YAxis.ClippingArea = new RectangleD(0,
381                                                 info.YAxis.ClippingArea.Y1,
382                                                 YAxisWidth,
383                                                 info.YAxis.ClippingArea.Y2);
384      }
385    }
386
387    private void SetClipY(RowEntry rowEntry, double y1, double y2) {
388      xAxisGrid.ClippingArea = new RectangleD(xAxisGrid.ClippingArea.X1,
389                                              y1,
390                                              xAxisGrid.ClippingArea.X2,
391                                              y2);
392
393      rowEntry.LinesShape.ClippingArea = new RectangleD(rowEntry.LinesShape.ClippingArea.X1,
394                                                        y1,
395                                                        rowEntry.LinesShape.ClippingArea.X2,
396                                                        y2);
397
398      YAxisInfo info = GetYAxisInfo(rowEntry.DataRow.YAxis);
399
400      info.Grid.ClippingArea = new RectangleD(info.Grid.ClippingArea.X1,
401                                              y1,
402                                              info.Grid.ClippingArea.X2,
403                                              y2);
404      info.YAxis.ClippingArea = new RectangleD(info.YAxis.ClippingArea.X1,
405                                               y1,
406                                               info.YAxis.ClippingArea.X2,
407                                               y2);
408    }
409
410    private void InitLineShapes(IDataRow row) {
411      RowEntry rowEntry = new RowEntry(row);
412      rowEntries.Add(rowEntry);
413      rowToRowEntry[row] = rowEntry;
414
415      if ((row.LineType == DataRowType.SingleValue)) {
416        if (row.Count > 0) {
417          LineShape lineShape = new HorizontalLineShape(0, row[0], double.MaxValue, row[0], row.Color, row.Thickness,
418                                                        row.Style);
419          rowEntry.LinesShape.AddShape(lineShape);
420        }
421      } else {
422        rowEntry.showMarkers(row.ShowMarkers);
423        for (int i = 1; i < row.Count; i++) {
424          LineShape lineShape = new LineShape(i - 1, row[i - 1], i, row[i], row.Color, row.Thickness, row.Style);
425          rowEntry.LinesShape.AddShape(lineShape);
426          rowEntry.LinesShape.AddMarkerShape(new MarkerShape(i - 1, row[i - 1], 8, row.Color));
427        }
428        if (row.Count > 0) {
429          rowEntry.LinesShape.AddMarkerShape(new MarkerShape((row.Count - 1), row[(row.Count - 1)], 8, row.Color));
430        }
431      }
432
433      ZoomToFullView();
434    }
435
436    private void OnRowValueChanged(IDataRow row, double value, int index, Action action) {
437      RowEntry rowEntry = rowToRowEntry[row];
438
439      if (row.LineType == DataRowType.SingleValue) {
440        if (action == Action.Added) {
441          LineShape lineShape = new HorizontalLineShape(0, row[0], double.MaxValue, row[0], row.Color, row.Thickness,
442                                                        row.Style);
443          rowEntry.LinesShape.AddShape(lineShape);
444        } else {
445          LineShape lineShape = rowEntry.LinesShape.GetShape(0);
446          lineShape.Y1 = value;
447          lineShape.Y2 = value;
448        }
449      } else {
450        if (index > rowEntry.LinesShape.Count + 1) {
451          //MarkersShape is on position zero
452          throw new NotImplementedException();
453        }
454
455        if (action == Action.Added) {
456          // new value was added
457          if (index > 0 && index == rowEntry.LinesShape.Count + 1) {
458            LineShape lineShape = new LineShape(index - 1, row[index - 1], index, row[index], row.Color, row.Thickness,
459                                                row.Style);
460            rowEntry.LinesShape.AddShape(lineShape);
461            rowEntry.LinesShape.AddMarkerShape(new MarkerShape(index, row[index], 8, row.Color));
462          }
463        } else if (action == Action.Modified) {
464          // not the first value
465          if (index > 0) {
466            rowEntry.LinesShape.GetShape(index - 1).Y2 = value;
467            ((MarkerShape)rowEntry.LinesShape.markersShape.GetShape(index - 1)).Y = value;
468          }
469
470          // not the last value
471          if (index > 0 && index < row.Count - 1) {
472            rowEntry.LinesShape.GetShape(index).Y1 = value;
473            ((MarkerShape)rowEntry.LinesShape.markersShape.GetShape(index)).Y = value;
474          }
475        }
476      }
477
478      ZoomToFullView();
479    }
480
481    private void OnRowValuesChanged(IDataRow row, double[] values, int index, Action action) {
482      foreach (double value in values) {
483        OnRowValueChanged(row, value, index++, action);
484      }
485    }
486
487    private void OnModelChanged() {
488      UpdateLayout();
489      canvasUI.Invalidate();
490    }
491
492    #region Begin-/EndUpdate
493
494    private int beginUpdateCount;
495
496    public void BeginUpdate() {
497      beginUpdateCount++;
498    }
499
500    public void EndUpdate() {
501      if (beginUpdateCount == 0) {
502        throw new InvalidOperationException("Too many EndUpdates.");
503      }
504
505      beginUpdateCount--;
506
507      if (beginUpdateCount == 0) {
508        canvasUI.Invalidate();
509      }
510    }
511
512    #endregion
513
514    #region Zooming / Panning
515
516    private void Pan(Point startPoint, Point endPoint) {
517      RectangleD clippingArea = Translate.ClippingArea(startPoint, endPoint, xAxis.ClippingArea, xAxis.Viewport);
518
519      SetClipX(clippingArea.X1, clippingArea.X2);
520
521      foreach (RowEntry rowEntry in rowEntries) {
522        if (rowEntry.DataRow.YAxis.ClipChangeable) {
523          clippingArea = Translate.ClippingArea(startPoint, endPoint, rowEntry.LinesShape.ClippingArea, rowEntry.LinesShape.Viewport);
524          SetClipY(rowEntry, clippingArea.Y1, clippingArea.Y2);
525        }
526      }
527
528      canvasUI.Invalidate();
529    }
530
531    private void PanEnd(Point startPoint, Point endPoint) {
532      Pan(startPoint, endPoint);
533    }
534
535    private void SetClippingArea(Rectangle rectangle) {
536      RectangleD clippingArea = Transform.ToWorld(rectangle, xAxis.Viewport, xAxis.ClippingArea);
537
538      SetClipX(clippingArea.X1, clippingArea.X2);
539
540      foreach (RowEntry rowEntry in rowEntries) {
541        if (rowEntry.DataRow.YAxis.ClipChangeable) {
542          clippingArea = Transform.ToWorld(rectangle, rowEntry.LinesShape.Viewport, rowEntry.LinesShape.ClippingArea);
543
544          SetClipY(rowEntry, clippingArea.Y1, clippingArea.Y2);
545        }
546      }
547
548      userInteractionShape.RemoveShape(rectangleShape);
549      canvasUI.Invalidate();
550    }
551
552    private void DrawRectangle(Rectangle rectangle) {
553      rectangleShape.Rectangle = Transform.ToWorld(rectangle, userInteractionShape.Viewport, userInteractionShape.ClippingArea);
554      canvasUI.Invalidate();
555    }
556
557    private void canvasUI1_KeyDown(object sender, KeyEventArgs e) {}
558
559    private void canvasUI1_MouseDown(object sender, MouseEventArgs e) {
560      Focus();
561
562      if (e.Button == MouseButtons.Right) {
563        contextMenu.Show(PointToScreen(e.Location));
564      } else if (e.Button == MouseButtons.Left) {
565        if (ModifierKeys == Keys.None) {
566          PanListener panListener = new PanListener(e.Location);
567          panListener.Pan += Pan;
568          panListener.PanEnd += PanEnd;
569
570          mouseEventListener = panListener;
571        } else if (ModifierKeys == Keys.Control) {
572          ZoomListener zoomListener = new ZoomListener(e.Location);
573          zoomListener.DrawRectangle += DrawRectangle;
574          zoomListener.SetClippingArea += SetClippingArea;
575
576          rectangleShape.Rectangle = RectangleD.Empty;
577          userInteractionShape.AddShape(rectangleShape);
578
579          mouseEventListener = zoomListener;
580        }
581      }
582    }
583
584    private void canvasUI_MouseMove(object sender, MouseEventArgs e) {
585      if (mouseEventListener != null) {
586        mouseEventListener.MouseMove(sender, e);
587      }
588    }
589
590    private void canvasUI_MouseUp(object sender, MouseEventArgs e) {
591      if (mouseEventListener != null) {
592        mouseEventListener.MouseUp(sender, e);
593      }
594
595      mouseEventListener = null;
596    }
597
598    private void canvasUI1_MouseWheel(object sender, MouseEventArgs e) {
599      if (ModifierKeys == Keys.Control) {
600        double zoomFactor = (e.Delta > 0) ? 0.7 : 1.3;
601
602        PointD world;
603
604        world = Transform.ToWorld(e.Location, xAxis.Viewport, xAxis.ClippingArea);
605
606        double x1 = world.X - (world.X - xAxis.ClippingArea.X1)*zoomFactor;
607        double x2 = world.X + (xAxis.ClippingArea.X2 - world.X)*zoomFactor;
608
609        SetClipX(x1, x2);
610
611        foreach (RowEntry rowEntry in rowEntries) {
612          world = Transform.ToWorld(e.Location, rowEntry.LinesShape.Viewport, rowEntry.LinesShape.ClippingArea);
613
614          double y1 = world.Y - (world.Y - rowEntry.LinesShape.ClippingArea.Y1)*zoomFactor;
615          double y2 = world.Y + (rowEntry.LinesShape.ClippingArea.Y2 - world.Y)*zoomFactor;
616
617          SetClipY(rowEntry, y1, y2);
618        }
619
620        canvasUI.Invalidate();
621      }
622    }
623
624    #endregion
625
626    private class LinesShape : WorldShape {
627      public readonly CompositeShape markersShape = new CompositeShape();
628
629      public void UpdateStyle(IDataRow row) {
630        foreach (IShape shape in shapes) {
631          LineShape lineShape = shape as LineShape;
632          if (lineShape != null) {
633            lineShape.LSColor = row.Color;
634            lineShape.LSDrawingStyle = row.Style;
635            lineShape.LSThickness = row.Thickness;
636          }
637        }
638        this.markersShape.ShowChildShapes = row.ShowMarkers;
639      }
640
641      public override void Draw(Graphics graphics) {
642        GraphicsState gstate = graphics.Save();
643
644        graphics.SetClip(Viewport);
645        foreach (IShape shape in shapes) {
646          // draw child shapes using our own clipping area
647          shape.Draw(graphics);
648        }
649        markersShape.Draw(graphics);
650        graphics.Restore(gstate);
651      }
652
653      public void AddMarkerShape(IShape shape) {
654        shape.Parent = this;
655        markersShape.AddShape(shape);
656      }
657
658      public int Count {
659        get { return shapes.Count; }
660      }
661
662      public LineShape GetShape(int index) {
663        return (LineShape)shapes[index]; //shapes[0] is markersShape!!
664      }
665    }
666
667    private class RowEntry {
668      private readonly IDataRow dataRow;
669
670      private readonly LinesShape linesShape = new LinesShape();
671
672      public RowEntry(IDataRow dataRow) {
673        this.dataRow = dataRow;
674        linesShape.markersShape.Parent = linesShape;
675      }
676
677      public IDataRow DataRow {
678        get { return dataRow; }
679      }
680
681      public LinesShape LinesShape {
682        get { return linesShape; }
683      }
684
685      public void showMarkers(bool flag) {
686        linesShape.markersShape.ShowChildShapes = flag;
687      }
688    }
689
690    private class YAxisInfo {
691      private readonly YAxisGrid grid = new YAxisGrid();
692      private readonly YAxis yAxis = new YAxis();
693
694      public YAxisGrid Grid {
695        get { return grid; }
696      }
697
698      public YAxis YAxis {
699        get { return yAxis; }
700      }
701    }
702  }
703}
Note: See TracBrowser for help on using the repository browser.