Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Hive_Milestone2/sources/HeuristicLab.Visualization/3.2/LineChart.cs @ 6452

Last change on this file since 6452 was 1781, checked in by mstoeger, 16 years ago

Data Export (CSV) #588

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