Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Visualization/LineChart.cs @ 961

Last change on this file since 961 was 928, checked in by bspisic, 16 years ago

#424
Added getter and setter by WorldShape
Implemented panning in LineChart

File size: 5.8 KB
RevLine 
[683]1using System;
[861]2using System.Collections.Generic;
[928]3using System.Diagnostics;
4using System.Drawing;
5using System.Windows.Forms;
[697]6using HeuristicLab.Core;
[683]7
[861]8namespace HeuristicLab.Visualization {
9  public partial class LineChart : ViewBase {
[697]10    private readonly IChartDataRowsModel model;
[684]11
[697]12    /// <summary>
13    /// This constructor shouldn't be called. Only required for the designer.
14    /// </summary>
[861]15    public LineChart() {
[684]16      InitializeComponent();
17    }
18
[697]19    /// <summary>
20    /// Initializes the chart.
21    /// </summary>
[754]22    /// <param name="model">Referenz to the model, for data</param>
[861]23    public LineChart(IChartDataRowsModel model) : this() {
[928]24      if (model == null) {
[697]25        throw new NullReferenceException("Model cannot be null.");
[928]26      }
[684]27
[754]28      //TODO: correct Rectangle to fit
[861]29      RectangleD clientRectangle = new RectangleD(-1, -1, 11, 11);
[754]30      canvasUI1.MainCanvas.WorldShape = new WorldShape(clientRectangle, clientRectangle);
[869]31
[928]32      CreateMouseEventListeners();
33
[869]34      this.model = model;
[928]35      Item = (IItem)model;
[697]36    }
[684]37
[861]38    #region Add-/RemoveItemEvents
39
40    protected override void AddItemEvents() {
41      base.AddItemEvents();
42
43      model.DataRowAdded += OnDataRowAdded;
44      model.DataRowRemoved += OnDataRowRemoved;
45      model.ModelChanged += OnModelChanged;
[869]46
47      foreach (IDataRow row in model.Rows) {
48        OnDataRowAdded(row);
49      }
[683]50    }
[684]51
[861]52    protected override void RemoveItemEvents() {
53      base.RemoveItemEvents();
54
55      model.DataRowAdded -= OnDataRowAdded;
56      model.DataRowRemoved -= OnDataRowRemoved;
57      model.ModelChanged -= OnModelChanged;
[697]58    }
59
[861]60    private void OnDataRowAdded(IDataRow row) {
61      row.ValueChanged += OnRowValueChanged;
62      row.ValuesChanged += OnRowValuesChanged;
63
64      InitShapes(row);
[684]65    }
[697]66
[861]67    private void InitShapes(IDataRow row) {
68      List<LineShape> lineShapes = new List<LineShape>();
69
70      for (int i = 1; i < row.Count; i++) {
[869]71        LineShape lineShape = new LineShape(i - 1, row[i - 1], i, row[i], 0, row.Color, row.Thickness);
[861]72        lineShapes.Add(lineShape);
[870]73        // TODO each DataRow needs its own WorldShape so Y Axes can be zoomed independently.
[861]74        canvasUI1.MainCanvas.WorldShape.AddShape(lineShape);
75      }
76
77      rowToLineShapes[row] = lineShapes;
78
79      canvasUI1.Invalidate();
[697]80    }
81
[861]82    private void OnDataRowRemoved(IDataRow row) {
83      row.ValueChanged -= OnRowValueChanged;
84      row.ValuesChanged -= OnRowValuesChanged;
[697]85    }
86
[861]87    private readonly IDictionary<IDataRow, List<LineShape>> rowToLineShapes = new Dictionary<IDataRow, List<LineShape>>();
[697]88
[870]89    // TODO use action parameter
[869]90    private void OnRowValueChanged(IDataRow row, double value, int index, Action action) {
[861]91      List<LineShape> lineShapes = rowToLineShapes[row];
92
[928]93      if (index > lineShapes.Count + 1) {
[861]94        throw new NotImplementedException();
[928]95      }
[861]96
97      // new value was added
[928]98      if (index > 0 && index == lineShapes.Count + 1) {
[869]99        LineShape lineShape = new LineShape(index - 1, row[index - 1], index, row[index], 0, row.Color, row.Thickness);
[861]100        lineShapes.Add(lineShape);
[870]101        // TODO each DataRow needs its own WorldShape so Y Axes can be zoomed independently.
[861]102        canvasUI1.MainCanvas.WorldShape.AddShape(lineShape);
103      }
104
105      // not the first value
[928]106      if (index > 0) {
107        lineShapes[index - 1].Y2 = value;
108      }
[861]109
110      // not the last value
[928]111      if (index > 0 && index < row.Count - 1) {
[861]112        lineShapes[index].Y1 = value;
[928]113      }
[861]114
115      canvasUI1.Invalidate();
[697]116    }
117
[870]118    // TODO use action parameter
[869]119    private void OnRowValuesChanged(IDataRow row, double[] values, int index, Action action) {
[861]120      foreach (double value in values) {
[869]121        OnRowValueChanged(row, value, index++, action);
[861]122      }
123    }
[761]124
[928]125    private void OnModelChanged() {}
[697]126
127    #endregion
128
129    #region Begin-/EndUpdate
130
131    private int beginUpdateCount = 0;
132
[861]133    public void BeginUpdate() {
[697]134      beginUpdateCount++;
135    }
136
[861]137    public void EndUpdate() {
[928]138      if (beginUpdateCount == 0) {
[697]139        throw new InvalidOperationException("Too many EndUpdates.");
[928]140      }
[697]141
142      beginUpdateCount--;
143
[928]144      if (beginUpdateCount == 0) {
[697]145        Invalidate();
[928]146      }
[697]147    }
148
149    #endregion
[928]150
151    private MouseEventListener panListener;
152
153    private void CreateMouseEventListeners() {
154      panListener = new MouseEventListener();
155      panListener.OnMouseMove += Pan_OnMouseMove;
156      panListener.OnMouseUp += Pan_OnMouseUp;
157    }
158
159
160    private RectangleD startClippingArea;
161
162    private void canvasUI1_MouseDown(object sender, MouseEventArgs e) {
163      panListener.StartPoint = e.Location;
164      canvasUI1.MouseEventListener = panListener;
165
166      startClippingArea = canvasUI1.MainCanvas.WorldShape.ClippingArea;
167    }
168
169    private void Pan_OnMouseUp(Point startPoint, Point actualPoint) {
170       canvasUI1.MouseEventListener = null;
171    }
172
173    private void Pan_OnMouseMove(Point startPoint, Point actualPoint) {
174      Rectangle viewPort = canvasUI1.ClientRectangle;
175
176      PointD worldStartPoint = Transform.ToWorld(startPoint, viewPort, startClippingArea);
177      PointD worldActualPoint = Transform.ToWorld(actualPoint, viewPort, startClippingArea);
178
179      double xDiff = worldActualPoint.X - worldStartPoint.X;
180      double yDiff = worldActualPoint.Y - worldStartPoint.Y;
181
182      RectangleD newClippingArea = new RectangleD();
183      newClippingArea.X1 = startClippingArea.X1 - xDiff;
184      newClippingArea.X2 = startClippingArea.X2 - xDiff;
185      newClippingArea.Y1 = startClippingArea.Y1 - yDiff;
186      newClippingArea.Y2 = startClippingArea.Y2 - yDiff;
187
188      canvasUI1.MainCanvas.WorldShape.ClippingArea = newClippingArea;
189      panListener.StartPoint = startPoint;
190
191      canvasUI1.Invalidate();
192    }
[684]193  }
194}
Note: See TracBrowser for help on using the repository browser.