Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 1867 was 1839, checked in by bspisic, 15 years ago

Model.Title is changeable in OptionsDialog now (#590)

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