Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 1962 was 1962, checked in by cbahner, 15 years ago

#636 first impl. of drawingStyle (DataRowSettings)

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