Free cookie consent management tool by TermsFeed Policy Generator

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

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

upper/lowercase #498

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