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
RevLine 
[683]1using System;
[861]2using System.Collections.Generic;
[928]3using System.Drawing;
[1559]4using System.Drawing.Drawing2D;
[928]5using System.Windows.Forms;
[697]6using HeuristicLab.Core;
[1781]7using HeuristicLab.Visualization.DataExport;
[1964]8using HeuristicLab.Visualization.Drawing;
[1233]9using HeuristicLab.Visualization.Legend;
[1195]10using HeuristicLab.Visualization.Options;
[1457]11using HeuristicLab.Visualization.Test;
[683]12
[861]13namespace HeuristicLab.Visualization {
[1187]14  public partial class LineChart : ViewBase {
[697]15    private readonly IChartDataRowsModel model;
[1240]16    private readonly Canvas canvas;
17
[1285]18    private readonly TextShape titleShape = new TextShape("Title");
19    private readonly LegendShape legendShape = new LegendShape();
20    private readonly XAxis xAxis = new XAxis();
[1876]21    private readonly XAxisGrid xAxisGrid = new XAxisGrid();
[1285]22    private readonly List<RowEntry> rowEntries = new List<RowEntry>();
[684]23
[1285]24    private readonly Dictionary<IDataRow, RowEntry> rowToRowEntry = new Dictionary<IDataRow, RowEntry>();
[1038]25
[1341]26    private readonly ViewSettings viewSettings;
27
[1285]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;
[983]31
[1285]32    private const int YAxisWidth = 100;
[1462]33    private const int XAxisHeight = 40;
[1883]34    private readonly TooltipListener toolTipListener;
35    private readonly ToolTip valueToolTip;
36    private Point currentMousePos;
[1285]37
[697]38    /// <summary>
39    /// This constructor shouldn't be called. Only required for the designer.
40    /// </summary>
[861]41    public LineChart() {
[684]42      InitializeComponent();
43    }
44
[697]45    /// <summary>
46    /// Initializes the chart.
47    /// </summary>
[754]48    /// <param name="model">Referenz to the model, for data</param>
[861]49    public LineChart(IChartDataRowsModel model) : this() {
[1045]50      if (model == null) {
[697]51        throw new NullReferenceException("Model cannot be null.");
[1045]52      }
[684]53
[1240]54      canvas = canvasUI.Canvas;
[983]55
[1285]56      this.model = model;
[1341]57      viewSettings = model.ViewSettings;
[1342]58      viewSettings.OnUpdateSettings += UpdateViewSettings;
[1038]59
[983]60      Item = model;
[1038]61
[1883]62      valueToolTip = new ToolTip();
63      toolTipListener = new TooltipListener();
64      toolTipListener.ShowToolTip += ShowToolTip;
65      mouseEventListener = toolTipListener;
66      currentMousePos = new Point(0, 0);
67
[1879]68      this.ResizeRedraw = true;
69
[1880]70      canvasUI.BeforePaint += delegate { UpdateLayout(); };
71
[1240]72      UpdateLayout();
[1285]73      ZoomToFullView();
[697]74    }
[684]75
[1346]76    /// <summary>
77    /// updates the view settings
78    /// </summary>
[1342]79    private void UpdateViewSettings() {
[1341]80      titleShape.Font = viewSettings.TitleFont;
81      titleShape.Color = viewSettings.TitleColor;
[1839]82      titleShape.Text = model.Title;
[1337]83
[1341]84      legendShape.Font = viewSettings.LegendFont;
85      legendShape.Color = viewSettings.LegendColor;
[1337]86
[1341]87      xAxis.Font = viewSettings.XAxisFont;
88      xAxis.Color = viewSettings.XAxisColor;
[1337]89
[1345]90      SetLegendPosition();
[1342]91
[1880]92      canvasUI.Invalidate();
[1337]93    }
94
[1038]95    /// <summary>
96    /// Layout management - arranges the inner shapes.
97    /// </summary>
98    private void UpdateLayout() {
[1285]99      canvas.ClearShapes();
100
[1608]101      titleShape.Text = model.Title;
102
[1881]103      if (model.XAxis.ShowGrid) {
[1885]104        xAxisGrid.Color = model.XAxis.GridColor;
[1876]105        canvas.AddShape(xAxisGrid);
106      }
107
[1350]108      foreach (YAxisDescriptor yAxisDescriptor in model.YAxes) {
109        YAxisInfo info = GetYAxisInfo(yAxisDescriptor);
[1458]110        if (yAxisDescriptor.ShowGrid) {
111          info.Grid.Color = yAxisDescriptor.GridColor;
112          canvas.AddShape(info.Grid);
113        }
[1285]114      }
115
116      foreach (RowEntry rowEntry in rowEntries) {
117        canvas.AddShape(rowEntry.LinesShape);
118      }
119
[1881]120      xAxis.ShowLabel = model.XAxis.ShowLabel;
121      xAxis.Label = model.XAxis.Label;
[1462]122
[1285]123      canvas.AddShape(xAxis);
124
[1457]125      int yAxesWidthLeft = 0;
126      int yAxesWidthRight = 0;
[1343]127
[1350]128      foreach (YAxisDescriptor yAxisDescriptor in model.YAxes) {
129        YAxisInfo info = GetYAxisInfo(yAxisDescriptor);
130        if (yAxisDescriptor.ShowYAxis) {
131          canvas.AddShape(info.YAxis);
[1462]132          info.YAxis.ShowLabel = yAxisDescriptor.ShowYAxisLabel;
133          info.YAxis.Label = yAxisDescriptor.Label;
[1457]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          }
[1343]145        }
[1285]146      }
147
148      canvas.AddShape(titleShape);
149      canvas.AddShape(legendShape);
150      canvas.AddShape(userInteractionShape);
151
[1038]152      titleShape.X = 10;
[1240]153      titleShape.Y = canvasUI.Height - 10;
[1038]154
[1457]155      RectangleD linesAreaBoundingBox = new RectangleD(yAxesWidthLeft,
[1285]156                                                       XAxisHeight,
[1457]157                                                       canvasUI.Width - yAxesWidthRight,
[1285]158                                                       canvasUI.Height);
[1240]159
[1285]160      foreach (RowEntry rowEntry in rowEntries) {
161        rowEntry.LinesShape.BoundingBox = linesAreaBoundingBox;
162      }
[1182]163
[1876]164      xAxisGrid.BoundingBox = linesAreaBoundingBox;
165
[1350]166      foreach (YAxisDescriptor yAxisDescriptor in model.YAxes) {
167        YAxisInfo info = GetYAxisInfo(yAxisDescriptor);
168        info.Grid.BoundingBox = linesAreaBoundingBox;
169      }
170
[1285]171      int yAxisLeft = 0;
[1883]172      int yAxisRight = (int) linesAreaBoundingBox.X2;
[1457]173
[1350]174      foreach (YAxisDescriptor yAxisDescriptor in model.YAxes) {
175        YAxisInfo info = GetYAxisInfo(yAxisDescriptor);
176        if (yAxisDescriptor.ShowYAxis) {
[1457]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          }
[1343]195        }
[1285]196      }
[1187]197
[1285]198      userInteractionShape.BoundingBox = linesAreaBoundingBox;
[1883]199      userInteractionShape.ClippingArea = new RectangleD(0, 0, userInteractionShape.BoundingBox.Width,
200                                                         userInteractionShape.BoundingBox.Height);
[1182]201
[1285]202      xAxis.BoundingBox = new RectangleD(linesAreaBoundingBox.X1,
[1038]203                                         0,
[1285]204                                         linesAreaBoundingBox.X2,
205                                         linesAreaBoundingBox.Y1);
[1049]206
[1345]207      SetLegendPosition();
[1342]208    }
209
[1350]210    private readonly Dictionary<YAxisDescriptor, YAxisInfo> yAxisInfos = new Dictionary<YAxisDescriptor, YAxisInfo>();
211
[1883]212    /// <summary>
213    ///
214    /// </summary>
215    /// <param name="yAxisDescriptor"></param>
216    /// <returns></returns>
[1350]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
[1883]228
229    #region Legend-specific
230
[1346]231    /// <summary>
232    /// sets the legend position
233    /// </summary>
[1345]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
[1342]254    public void setLegendRight() {
255      // legend right
[1883]256      legendShape.BoundingBox = new RectangleD(canvasUI.Width - legendShape.GetMaxLabelLength(), 10, canvasUI.Width,
257                                               canvasUI.Height - 50);
[1342]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
[1388]265      legendShape.BoundingBox = new RectangleD(10, 10, canvasUI.Width, canvasUI.Height - 50);
[1342]266      legendShape.ClippingArea = new RectangleD(0, 0, legendShape.BoundingBox.Width, legendShape.BoundingBox.Height);
267      legendShape.Row = false;
268      legendShape.CreateLegend();
[1285]269
[1880]270      canvasUI.Invalidate();
[1038]271    }
272
[1342]273    public void setLegendTop() {
274      // legend top
[1883]275      legendShape.BoundingBox = new RectangleD(100, canvasUI.Height - canvasUI.Height, canvasUI.Width,
276                                               canvasUI.Height - 10);
[1342]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
[1878]285      legendShape.BoundingBox = new RectangleD(100, 2, canvasUI.Width, canvasUI.Height);
[1342]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
[1883]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
[1242]318    private void optionsToolStripMenuItem_Click(object sender, EventArgs e) {
[1341]319      OptionsDialog optionsdlg = new OptionsDialog(model);
[1459]320      optionsdlg.Show();
[1883]321      mouseEventListener = toolTipListener;
[1242]322    }
323
[1781]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
[1242]334    public void OnDataRowChanged(IDataRow row) {
[1285]335      RowEntry rowEntry = rowToRowEntry[row];
336
337      rowEntry.LinesShape.UpdateStyle(row);
338
[1880]339      canvasUI.Invalidate();
[1242]340    }
341
[861]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;
[869]350
[1045]351      foreach (IDataRow row in model.Rows) {
[869]352        OnDataRowAdded(row);
[1045]353      }
[683]354    }
[684]355
[861]356    protected override void RemoveItemEvents() {
357      base.RemoveItemEvents();
358
359      model.DataRowAdded -= OnDataRowAdded;
360      model.DataRowRemoved -= OnDataRowRemoved;
361      model.ModelChanged -= OnModelChanged;
[697]362    }
363
[861]364    private void OnDataRowAdded(IDataRow row) {
365      row.ValueChanged += OnRowValueChanged;
366      row.ValuesChanged += OnRowValuesChanged;
[1237]367      row.DataRowChanged += OnDataRowChanged;
368
[1962]369      legendShape.AddLegendItem(new LegendItem(row.RowSettings.Label, row.RowSettings.Color, row.RowSettings.Thickness));
[1049]370      legendShape.CreateLegend();
[1285]371
[987]372      InitLineShapes(row);
[1285]373
[1880]374      canvasUI.Invalidate();
[684]375    }
[697]376
[1240]377    private void OnDataRowRemoved(IDataRow row) {
378      row.ValueChanged -= OnRowValueChanged;
379      row.ValuesChanged -= OnRowValuesChanged;
380      row.DataRowChanged -= OnDataRowChanged;
[1285]381
382      rowToRowEntry.Remove(row);
383      rowEntries.RemoveAll(delegate(RowEntry rowEntry) { return rowEntry.DataRow == row; });
384
[1880]385      canvasUI.Invalidate();
[1240]386    }
387
388    #endregion
389
[1249]390    public void ZoomToFullView() {
[1285]391      SetClipX(-0.1, model.MaxDataRowValues - 0.9);
[987]392
[1285]393      foreach (RowEntry rowEntry in rowEntries) {
[1350]394        YAxisDescriptor yAxisDescriptor = rowEntry.DataRow.YAxis;
[1249]395
[1285]396        SetClipY(rowEntry,
[1350]397                 yAxisDescriptor.MinValue - ((yAxisDescriptor.MaxValue - yAxisDescriptor.MinValue)*0.05),
398                 yAxisDescriptor.MaxValue + ((yAxisDescriptor.MaxValue - yAxisDescriptor.MinValue)*0.05));
[1285]399      }
400
[1880]401      canvasUI.Invalidate();
[987]402    }
403
[1285]404    private void SetClipX(double x1, double x2) {
[1876]405      xAxisGrid.ClippingArea = new RectangleD(x1,
406                                              xAxisGrid.ClippingArea.Y1,
407                                              x2,
408                                              xAxisGrid.ClippingArea.Y2);
409
[1285]410      xAxis.ClippingArea = new RectangleD(x1,
411                                          0,
412                                          x2,
413                                          XAxisHeight);
[1249]414
[1285]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);
[1249]420      }
[1350]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      }
[1285]433    }
[1249]434
[1350]435    private void SetClipY(RowEntry rowEntry, double y1, double y2) {
[1876]436      xAxisGrid.ClippingArea = new RectangleD(xAxisGrid.ClippingArea.X1,
437                                              y1,
438                                              xAxisGrid.ClippingArea.X2,
439                                              y2);
440
[1285]441      rowEntry.LinesShape.ClippingArea = new RectangleD(rowEntry.LinesShape.ClippingArea.X1,
442                                                        y1,
443                                                        rowEntry.LinesShape.ClippingArea.X2,
444                                                        y2);
[1350]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);
[981]456    }
457
[1883]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>
[987]462    private void InitLineShapes(IDataRow row) {
[1285]463      RowEntry rowEntry = new RowEntry(row);
464      rowEntries.Add(rowEntry);
465      rowToRowEntry[row] = rowEntry;
466
[1242]467      if ((row.LineType == DataRowType.SingleValue)) {
468        if (row.Count > 0) {
[1962]469          LineShape lineShape = new HorizontalLineShape(0, row[0], double.MaxValue, row[0], row.RowSettings.Color, row.RowSettings.Thickness,
[1242]470                                                        row.Style);
[1285]471          rowEntry.LinesShape.AddShape(lineShape);
[1242]472        }
[1883]473      } else if (row.LineType == DataRowType.Points) {
[1965]474        rowEntry.ShowMarkers(true);      //no lines, only markers are shown!!
[1883]475        for (int i = 0; i < row.Count; i++)
[1962]476          rowEntry.LinesShape.AddMarkerShape(new MarkerShape(i, row[i], 8, row.RowSettings.Color));
[1883]477      } else if (row.LineType == DataRowType.Normal) {
[1965]478        rowEntry.ShowMarkers(row.ShowMarkers);
[1242]479        for (int i = 1; i < row.Count; i++) {
[1962]480          LineShape lineShape = new LineShape(i - 1, row[i - 1], i, row[i], row.RowSettings.Color, row.RowSettings.Thickness, row.Style);
[1285]481          rowEntry.LinesShape.AddShape(lineShape);
[1962]482          rowEntry.LinesShape.AddMarkerShape(new MarkerShape(i - 1, row[i - 1], 8, row.RowSettings.Color));
[1242]483        }
[1608]484        if (row.Count > 0) {
[1962]485          rowEntry.LinesShape.AddMarkerShape(new MarkerShape((row.Count - 1), row[(row.Count - 1)], 8, row.RowSettings.Color));
[1608]486        }
[1242]487      }
[1249]488
[981]489      ZoomToFullView();
[697]490    }
491
[1883]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>
[869]499    private void OnRowValueChanged(IDataRow row, double value, int index, Action action) {
[1285]500      RowEntry rowEntry = rowToRowEntry[row];
501
[1242]502      if (row.LineType == DataRowType.SingleValue) {
503        if (action == Action.Added) {
[1962]504          LineShape lineShape = new HorizontalLineShape(0, row[0], double.MaxValue, row[0], row.RowSettings.Color, row.RowSettings.Thickness,
[1242]505                                                        row.Style);
[1285]506          rowEntry.LinesShape.AddShape(lineShape);
[1883]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){
[1285]510          LineShape lineShape = rowEntry.LinesShape.GetShape(0);
511          lineShape.Y1 = value;
512          lineShape.Y2 = value;
[1242]513        }
[1883]514      } else if (row.LineType == DataRowType.Points) {
515        if (action == Action.Added) {
516          if(rowEntry.LinesShape.Count==0)
[1962]517            rowEntry.LinesShape.AddMarkerShape(new MarkerShape(0, row[0], 8, row.RowSettings.Color));
[1883]518          if (index > 0 && index == rowEntry.LinesShape.Count + 1) {
[1962]519            LineShape lineShape = new LineShape(index - 1, row[index - 1], index, row[index], row.RowSettings.Color, row.RowSettings.Thickness,
[1883]520                                                row.Style);
521            rowEntry.LinesShape.AddShape(lineShape);
[1962]522            rowEntry.LinesShape.AddMarkerShape(new MarkerShape(index, row[index], 8, row.RowSettings.Color));
[1883]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) {
[1608]546        if (index > rowEntry.LinesShape.Count + 1) {
[1242]547          throw new NotImplementedException();
548        }
[861]549
[1603]550        if (action == Action.Added) {
[1883]551          if (rowEntry.LinesShape.Count == 0)
[1962]552            rowEntry.LinesShape.AddMarkerShape(new MarkerShape(0, row[0], 8, row.RowSettings.Color));
[1603]553          if (index > 0 && index == rowEntry.LinesShape.Count + 1) {
[1962]554            LineShape lineShape = new LineShape(index - 1, row[index - 1], index, row[index], row.RowSettings.Color, row.RowSettings.Thickness,
[1603]555                                                row.Style);
556            rowEntry.LinesShape.AddShape(lineShape);
[1962]557            rowEntry.LinesShape.AddMarkerShape(new MarkerShape(index, row[index], 8, row.RowSettings.Color));
[1603]558          }
[1608]559        } else if (action == Action.Modified) {
[1603]560          // not the first value
561          if (index > 0) {
562            rowEntry.LinesShape.GetShape(index - 1).Y2 = value;
[1883]563            ((MarkerShape) rowEntry.LinesShape.markersShape.GetShape(index - 1)).Y = value;
[1603]564          }
[861]565
[1603]566          // not the last value
[1883]567          if (index < row.Count - 1) {
[1603]568            rowEntry.LinesShape.GetShape(index).Y1 = value;
[1883]569            ((MarkerShape) rowEntry.LinesShape.markersShape.GetShape(index)).Y = value;
[1603]570          }
[1883]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!");
[1242]577        }
[1045]578      }
[861]579
[981]580      ZoomToFullView();
[697]581    }
582
[869]583    private void OnRowValuesChanged(IDataRow row, double[] values, int index, Action action) {
[1045]584      foreach (double value in values) {
[869]585        OnRowValueChanged(row, value, index++, action);
[1045]586      }
[861]587    }
[761]588
[1182]589    private void OnModelChanged() {
[1880]590      canvasUI.Invalidate();
[1182]591    }
592
[697]593    #region Begin-/EndUpdate
594
[1242]595    private int beginUpdateCount;
[697]596
[861]597    public void BeginUpdate() {
[697]598      beginUpdateCount++;
599    }
600
[861]601    public void EndUpdate() {
[1045]602      if (beginUpdateCount == 0) {
[697]603        throw new InvalidOperationException("Too many EndUpdates.");
[1045]604      }
[697]605
606      beginUpdateCount--;
607
[1045]608      if (beginUpdateCount == 0) {
[1880]609        canvasUI.Invalidate();
[1045]610      }
[697]611    }
612
613    #endregion
[928]614
[1059]615    #region Zooming / Panning
616
[1249]617    private void Pan(Point startPoint, Point endPoint) {
[1351]618      RectangleD clippingArea = Translate.ClippingArea(startPoint, endPoint, xAxis.ClippingArea, xAxis.Viewport);
[1285]619
[1351]620      SetClipX(clippingArea.X1, clippingArea.X2);
[1285]621
622      foreach (RowEntry rowEntry in rowEntries) {
[1390]623        if (rowEntry.DataRow.YAxis.ClipChangeable) {
[1883]624          clippingArea = Translate.ClippingArea(startPoint, endPoint, rowEntry.LinesShape.ClippingArea,
625                                                rowEntry.LinesShape.Viewport);
[1390]626          SetClipY(rowEntry, clippingArea.Y1, clippingArea.Y2);
627        }
[1285]628      }
629
[1880]630      canvasUI.Invalidate();
[1249]631    }
632
[1351]633    private void PanEnd(Point startPoint, Point endPoint) {
634      Pan(startPoint, endPoint);
[1249]635    }
636
637    private void SetClippingArea(Rectangle rectangle) {
[1351]638      RectangleD clippingArea = Transform.ToWorld(rectangle, xAxis.Viewport, xAxis.ClippingArea);
639
640      SetClipX(clippingArea.X1, clippingArea.X2);
641
[1285]642      foreach (RowEntry rowEntry in rowEntries) {
[1390]643        if (rowEntry.DataRow.YAxis.ClipChangeable) {
644          clippingArea = Transform.ToWorld(rectangle, rowEntry.LinesShape.Viewport, rowEntry.LinesShape.ClippingArea);
[1249]645
[1390]646          SetClipY(rowEntry, clippingArea.Y1, clippingArea.Y2);
647        }
[1285]648      }
649
[1249]650      userInteractionShape.RemoveShape(rectangleShape);
[1880]651      canvasUI.Invalidate();
[1249]652    }
653
654    private void DrawRectangle(Rectangle rectangle) {
[1883]655      rectangleShape.Rectangle = Transform.ToWorld(rectangle, userInteractionShape.Viewport,
656                                                   userInteractionShape.ClippingArea);
[1880]657      canvasUI.Invalidate();
[1249]658    }
659
[1608]660    private void canvasUI1_KeyDown(object sender, KeyEventArgs e) {}
[1059]661
[928]662    private void canvasUI1_MouseDown(object sender, MouseEventArgs e) {
[1058]663      Focus();
[1249]664
[1237]665      if (e.Button == MouseButtons.Right) {
[1883]666        valueToolTip.Hide(this);
667        mouseEventListener = null;
668        this.contextMenu.Show(PointToScreen(e.Location));
[1249]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;
[1187]685        }
686      }
[928]687    }
688
[1249]689    private void canvasUI_MouseMove(object sender, MouseEventArgs e) {
[1883]690      if (currentMousePos == e.Location)
691        return;
[1249]692      if (mouseEventListener != null) {
693        mouseEventListener.MouseMove(sender, e);
694      }
[1883]695
696      currentMousePos = e.Location;
[1249]697    }
[1244]698
[1249]699    private void canvasUI_MouseUp(object sender, MouseEventArgs e) {
700      if (mouseEventListener != null) {
701        mouseEventListener.MouseUp(sender, e);
702      }
[1240]703
[1883]704      mouseEventListener = toolTipListener;
[1240]705    }
706
[1058]707    private void canvasUI1_MouseWheel(object sender, MouseEventArgs e) {
708      if (ModifierKeys == Keys.Control) {
[1351]709        double zoomFactor = (e.Delta > 0) ? 0.7 : 1.3;
[1058]710
[1351]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
[1285]720        foreach (RowEntry rowEntry in rowEntries) {
[1351]721          world = Transform.ToWorld(e.Location, rowEntry.LinesShape.Viewport, rowEntry.LinesShape.ClippingArea);
722
[1608]723          double y1 = world.Y - (world.Y - rowEntry.LinesShape.ClippingArea.Y1)*zoomFactor;
[1351]724          double y2 = world.Y + (rowEntry.LinesShape.ClippingArea.Y2 - world.Y)*zoomFactor;
725
726          SetClipY(rowEntry, y1, y2);
[1285]727        }
[1351]728
[1880]729        canvasUI.Invalidate();
[1058]730      }
731    }
732
[1249]733    #endregion
[928]734
[1879]735    protected override void OnPaint(PaintEventArgs e) {
736      UpdateLayout();
737      base.OnPaint(e);
738    }
739
[1285]740    private class LinesShape : WorldShape {
[1559]741      public readonly CompositeShape markersShape = new CompositeShape();
742
[1285]743      public void UpdateStyle(IDataRow row) {
744        foreach (IShape shape in shapes) {
745          LineShape lineShape = shape as LineShape;
746          if (lineShape != null) {
[1962]747            lineShape.LSColor = row.RowSettings.Color;
[1285]748            lineShape.LSDrawingStyle = row.Style;
[1962]749            lineShape.LSThickness = row.RowSettings.Thickness;
[1285]750          }
751        }
[1883]752        markersShape.ShowChildShapes = row.ShowMarkers;
[1285]753      }
[928]754
[1883]755      /// <summary>
756      /// Draws all Shapes in the chart
757      /// </summary>
758      /// <param name="graphics"></param>
[1559]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
[1883]776      public void RemoveMarkerShape(IShape shape) {
777        shape.Parent = this;
778        markersShape.RemoveShape(shape);
779      }
780
[1285]781      public int Count {
782        get { return shapes.Count; }
783      }
[928]784
[1285]785      public LineShape GetShape(int index) {
[1883]786        return (LineShape) shapes[index]; //shapes[0] is markersShape!!
[1285]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;
[1559]797        linesShape.markersShape.Parent = linesShape;
[1285]798      }
799
800      public IDataRow DataRow {
801        get { return dataRow; }
802      }
803
[1350]804      public LinesShape LinesShape {
805        get { return linesShape; }
806      }
[1559]807
[1965]808      public void ShowMarkers(bool flag) {
[1561]809        linesShape.markersShape.ShowChildShapes = flag;
[1559]810      }
[1350]811    }
812
[1608]813    private class YAxisInfo {
[1876]814      private readonly YAxisGrid grid = new YAxisGrid();
[1350]815      private readonly YAxis yAxis = new YAxis();
816
[1876]817      public YAxisGrid Grid {
[1285]818        get { return grid; }
819      }
820
821      public YAxis YAxis {
822        get { return yAxis; }
823      }
824    }
[684]825  }
[1608]826}
Note: See TracBrowser for help on using the repository browser.