Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 978 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
Line 
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Drawing;
5using System.Windows.Forms;
6using HeuristicLab.Core;
7
8namespace HeuristicLab.Visualization {
9  public partial class LineChart : ViewBase {
10    private readonly IChartDataRowsModel model;
11
12    /// <summary>
13    /// This constructor shouldn't be called. Only required for the designer.
14    /// </summary>
15    public LineChart() {
16      InitializeComponent();
17    }
18
19    /// <summary>
20    /// Initializes the chart.
21    /// </summary>
22    /// <param name="model">Referenz to the model, for data</param>
23    public LineChart(IChartDataRowsModel model) : this() {
24      if (model == null) {
25        throw new NullReferenceException("Model cannot be null.");
26      }
27
28      //TODO: correct Rectangle to fit
29      RectangleD clientRectangle = new RectangleD(-1, -1, 11, 11);
30      canvasUI1.MainCanvas.WorldShape = new WorldShape(clientRectangle, clientRectangle);
31
32      CreateMouseEventListeners();
33
34      this.model = model;
35      Item = (IItem)model;
36    }
37
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;
46
47      foreach (IDataRow row in model.Rows) {
48        OnDataRowAdded(row);
49      }
50    }
51
52    protected override void RemoveItemEvents() {
53      base.RemoveItemEvents();
54
55      model.DataRowAdded -= OnDataRowAdded;
56      model.DataRowRemoved -= OnDataRowRemoved;
57      model.ModelChanged -= OnModelChanged;
58    }
59
60    private void OnDataRowAdded(IDataRow row) {
61      row.ValueChanged += OnRowValueChanged;
62      row.ValuesChanged += OnRowValuesChanged;
63
64      InitShapes(row);
65    }
66
67    private void InitShapes(IDataRow row) {
68      List<LineShape> lineShapes = new List<LineShape>();
69
70      for (int i = 1; i < row.Count; i++) {
71        LineShape lineShape = new LineShape(i - 1, row[i - 1], i, row[i], 0, row.Color, row.Thickness);
72        lineShapes.Add(lineShape);
73        // TODO each DataRow needs its own WorldShape so Y Axes can be zoomed independently.
74        canvasUI1.MainCanvas.WorldShape.AddShape(lineShape);
75      }
76
77      rowToLineShapes[row] = lineShapes;
78
79      canvasUI1.Invalidate();
80    }
81
82    private void OnDataRowRemoved(IDataRow row) {
83      row.ValueChanged -= OnRowValueChanged;
84      row.ValuesChanged -= OnRowValuesChanged;
85    }
86
87    private readonly IDictionary<IDataRow, List<LineShape>> rowToLineShapes = new Dictionary<IDataRow, List<LineShape>>();
88
89    // TODO use action parameter
90    private void OnRowValueChanged(IDataRow row, double value, int index, Action action) {
91      List<LineShape> lineShapes = rowToLineShapes[row];
92
93      if (index > lineShapes.Count + 1) {
94        throw new NotImplementedException();
95      }
96
97      // new value was added
98      if (index > 0 && index == lineShapes.Count + 1) {
99        LineShape lineShape = new LineShape(index - 1, row[index - 1], index, row[index], 0, row.Color, row.Thickness);
100        lineShapes.Add(lineShape);
101        // TODO each DataRow needs its own WorldShape so Y Axes can be zoomed independently.
102        canvasUI1.MainCanvas.WorldShape.AddShape(lineShape);
103      }
104
105      // not the first value
106      if (index > 0) {
107        lineShapes[index - 1].Y2 = value;
108      }
109
110      // not the last value
111      if (index > 0 && index < row.Count - 1) {
112        lineShapes[index].Y1 = value;
113      }
114
115      canvasUI1.Invalidate();
116    }
117
118    // TODO use action parameter
119    private void OnRowValuesChanged(IDataRow row, double[] values, int index, Action action) {
120      foreach (double value in values) {
121        OnRowValueChanged(row, value, index++, action);
122      }
123    }
124
125    private void OnModelChanged() {}
126
127    #endregion
128
129    #region Begin-/EndUpdate
130
131    private int beginUpdateCount = 0;
132
133    public void BeginUpdate() {
134      beginUpdateCount++;
135    }
136
137    public void EndUpdate() {
138      if (beginUpdateCount == 0) {
139        throw new InvalidOperationException("Too many EndUpdates.");
140      }
141
142      beginUpdateCount--;
143
144      if (beginUpdateCount == 0) {
145        Invalidate();
146      }
147    }
148
149    #endregion
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    }
193  }
194}
Note: See TracBrowser for help on using the repository browser.