Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
09/14/11 13:59:25 (13 years ago)
Author:
epitzer
Message:

#1530 integrate changes from trunk

Location:
branches/PersistenceSpeedUp
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/PersistenceSpeedUp

  • branches/PersistenceSpeedUp/HeuristicLab.Analysis.Views/3.3/DataTableView.cs

    r5445 r6760  
    3636  [View("DataTable View")]
    3737  [Content(typeof(DataTable), true)]
    38   public partial class DataTableView : NamedItemView {
     38  public partial class DataTableView : NamedItemView, IConfigureableView {
    3939    protected List<Series> invisibleSeries;
    4040    protected Dictionary<IObservableList<double>, DataRow> valuesRowsTable;
     
    6060    }
    6161
     62    #region Event Handler Registration
    6263    /// <summary>
    6364    /// Removes the eventhandlers from the underlying <see cref="Variable"/>.
     
    8990        RegisterDataRowEvents(row);
    9091    }
     92
     93    /// <summary>
     94    /// Automatically called for every existing data row and whenever a data row is added
     95    /// to the data table. Do not call this method directly.
     96    /// </summary>
     97    /// <param name="row">The DataRow that was added.</param>
     98    protected virtual void RegisterDataRowEvents(DataRow row) {
     99      row.NameChanged += new EventHandler(Row_NameChanged);
     100      row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
     101      valuesRowsTable.Add(row.Values, row);
     102      row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
     103      row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
     104      row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
     105      row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
     106      row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
     107    }
     108
     109    /// <summary>
     110    /// Automatically called for every data row that is removed from the DataTable. Do
     111    /// not directly call this method.
     112    /// </summary>
     113    /// <param name="row">The DataRow that was removed.</param>
     114    protected virtual void DeregisterDataRowEvents(DataRow row) {
     115      row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
     116      row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
     117      row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
     118      row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
     119      row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
     120      valuesRowsTable.Remove(row.Values);
     121      row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
     122      row.NameChanged -= new EventHandler(Row_NameChanged);
     123    }
     124    #endregion
    91125
    92126    protected override void OnContentChanged() {
     
    102136        foreach (DataRow row in Content.Rows)
    103137          AddDataRow(row);
    104         chart.ChartAreas[0].AxisX.Title = Content.VisualProperties.XAxisTitle;
    105         chart.ChartAreas[0].AxisY.Title = Content.VisualProperties.YAxisTitle;
    106         chart.ChartAreas[0].AxisY2.Title = Content.VisualProperties.SecondYAxisTitle;
     138        ConfigureChartArea(chart.ChartAreas[0]);
     139        RecalculateAxesScale(chart.ChartAreas[0]);
    107140      }
    108141    }
     
    113146    }
    114147
     148    public void ShowConfiguration() {
     149      if (Content != null) {
     150        DataTableVisualPropertiesDialog dialog = new DataTableVisualPropertiesDialog(Content);
     151        dialog.ShowDialog();
     152      } else MessageBox.Show("Nothing to configure.");
     153    }
    115154
    116155    /// <summary>
     
    120159    protected virtual void AddDataRow(DataRow row) {
    121160      Series series = new Series(row.Name);
     161      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
     162      else series.LegendText = row.Name;
     163      ConfigureSeries(series, row);
     164      FillSeriesWithRowValues(series, row);
     165
     166      chart.Series.Add(series);
     167      ConfigureChartArea(chart.ChartAreas[0]);
     168      RecalculateAxesScale(chart.ChartAreas[0]);
     169      UpdateYCursorInterval();
     170    }
     171
     172    private void ConfigureSeries(Series series, DataRow row) {
     173      RemoveCustomPropertyIfExists(series, "PointWidth");
     174      series.BorderWidth = 1;
     175      series.BorderDashStyle = ChartDashStyle.Solid;
     176      series.BorderColor = Color.Empty;
     177
     178      if (row.VisualProperties.Color != Color.Empty)
     179        series.Color = row.VisualProperties.Color;
     180      else series.Color = Color.Empty;
     181
    122182      switch (row.VisualProperties.ChartType) {
    123183        case DataRowVisualProperties.DataRowChartType.Line:
    124184          series.ChartType = SeriesChartType.FastLine;
     185          series.BorderWidth = row.VisualProperties.LineWidth;
     186          series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);
    125187          break;
    126188        case DataRowVisualProperties.DataRowChartType.Bars:
    127           series.ChartType = SeriesChartType.Bar;
     189          // Bar is incompatible with anything but Bar and StackedBar*
     190          if (!chart.Series.Any(x => x.ChartType != SeriesChartType.Bar && x.ChartType != SeriesChartType.StackedBar && x.ChartType != SeriesChartType.StackedBar100))
     191            series.ChartType = SeriesChartType.Bar;
     192          else {
     193            series.ChartType = SeriesChartType.FastPoint; //default
     194            row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
     195          }
    128196          break;
    129197        case DataRowVisualProperties.DataRowChartType.Columns:
     
    133201          series.ChartType = SeriesChartType.FastPoint;
    134202          break;
     203        case DataRowVisualProperties.DataRowChartType.Histogram:
     204          series.ChartType = SeriesChartType.Column;
     205          series.SetCustomProperty("PointWidth", "1");
     206          if (!series.Color.IsEmpty && series.Color.GetBrightness() < 0.25)
     207            series.BorderColor = Color.White;
     208          else series.BorderColor = Color.Black;
     209          break;
    135210        default:
    136211          series.ChartType = SeriesChartType.FastPoint;
     
    138213      }
    139214      series.YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary;
    140       if (row.VisualProperties.Color != Color.Empty) series.Color = row.VisualProperties.Color;
    141       series.ToolTip = row.Name + " X = #INDEX, Y = #VAL";
    142       FillSeriesWithRowValues(series, row);
    143       chart.Series.Add(series);
    144       chart.ChartAreas[0].RecalculateAxesScale();
    145       UpdateYCursorInterval();
    146     }
    147 
     215      series.XAxisType = row.VisualProperties.SecondXAxis ? AxisType.Secondary : AxisType.Primary;
     216      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
     217      else series.LegendText = row.Name;
     218      series.ToolTip = series.LegendText + " X = #INDEX, Y = #VAL";
     219    }
     220
     221    private void ConfigureChartArea(ChartArea area) {
     222      if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;
     223      if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;
     224
     225      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
     226      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
     227      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
     228
     229      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX2.TitleFont = Content.VisualProperties.AxisTitleFont;
     230      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX2.TitleForeColor = Content.VisualProperties.AxisTitleColor;
     231      area.AxisX2.Title = Content.VisualProperties.SecondXAxisTitle;
     232
     233      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
     234      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
     235      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
     236
     237      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY2.TitleFont = Content.VisualProperties.AxisTitleFont;
     238      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY2.TitleForeColor = Content.VisualProperties.AxisTitleColor;
     239      area.AxisY2.Title = Content.VisualProperties.SecondYAxisTitle;
     240    }
     241
     242    private void RecalculateAxesScale(ChartArea area) {
     243      // Reset the axes bounds so that RecalculateAxesScale() will assign new bounds
     244      foreach (Axis a in area.Axes) {
     245        a.Minimum = double.NaN;
     246        a.Maximum = double.NaN;
     247      }
     248      area.RecalculateAxesScale();
     249      area.AxisX.IsMarginVisible = false;
     250      area.AxisX2.IsMarginVisible = false;
     251
     252      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
     253      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
     254      if (!Content.VisualProperties.SecondXAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMinimumFixedValue)) area.AxisX2.Minimum = Content.VisualProperties.SecondXAxisMinimumFixedValue;
     255      if (!Content.VisualProperties.SecondXAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMaximumFixedValue)) area.AxisX2.Maximum = Content.VisualProperties.SecondXAxisMaximumFixedValue;
     256      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
     257      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
     258      if (!Content.VisualProperties.SecondYAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMinimumFixedValue)) area.AxisY2.Minimum = Content.VisualProperties.SecondYAxisMinimumFixedValue;
     259      if (!Content.VisualProperties.SecondYAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMaximumFixedValue)) area.AxisY2.Maximum = Content.VisualProperties.SecondYAxisMaximumFixedValue;
     260      if (area.AxisX.Minimum >= area.AxisX.Maximum) area.AxisX.Maximum = area.AxisX.Minimum + 1;
     261      if (area.AxisX2.Minimum >= area.AxisX2.Maximum) area.AxisX2.Maximum = area.AxisX2.Minimum + 1;
     262      if (area.AxisY.Minimum >= area.AxisY.Maximum) area.AxisY.Maximum = area.AxisY.Minimum + 1;
     263      if (area.AxisY2.Minimum >= area.AxisY2.Maximum) area.AxisY2.Maximum = area.AxisY2.Minimum + 1;
     264    }
    148265
    149266    /// <summary>
     
    151268    /// </summary>
    152269    protected virtual void UpdateYCursorInterval() {
    153       double interestingValuesRange = (from series in chart.Series
    154                                        where series.Enabled
    155                                        let values = (from point in series.Points
    156                                                      where !point.IsEmpty
    157                                                      select point.YValues[0])
    158                                                      .DefaultIfEmpty(1.0)
    159                                        let range = values.Max() - values.Min()
    160                                        where range > 0.0
    161                                        select range)
    162                                        .DefaultIfEmpty(1.0)
    163                                        .Min();
     270      double interestingValuesRange = (
     271        from series in chart.Series
     272        where series.Enabled
     273        let values = (from point in series.Points
     274                      where !point.IsEmpty
     275                      select point.YValues[0]).DefaultIfEmpty(1.0)
     276        let range = values.Max() - values.Min()
     277        where range > 0.0
     278        select range
     279        ).DefaultIfEmpty(1.0).Min();
    164280
    165281      double digits = (int)Math.Log10(interestingValuesRange) - 3;
     
    178294      if (invisibleSeries.Contains(series))
    179295        invisibleSeries.Remove(series);
    180       chart.ChartAreas[0].RecalculateAxesScale();
    181     }
    182 
    183     #region Content Events
    184     /// <summary>
    185     /// Automatically called for every existing data row and whenever a data row is added
    186     /// to the data table. Do not call this method directly.
    187     /// </summary>
    188     /// <param name="row">The DataRow that was added.</param>
    189     protected virtual void RegisterDataRowEvents(DataRow row) {
    190       row.NameChanged += new EventHandler(Row_NameChanged);
    191       row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
    192       valuesRowsTable.Add(row.Values, row);
    193       row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
    194       row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
    195       row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
    196       row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
    197       row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
    198     }
    199 
    200     /// <summary>
    201     /// Automatically called for every data row that is removed from the DataTable. Do
    202     /// not directly call this method.
    203     /// </summary>
    204     /// <param name="row">The DataRow that was removed.</param>
    205     protected virtual void DeregisterDataRowEvents(DataRow row) {
    206       row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
    207       row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
    208       row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
    209       row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
    210       row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
    211       valuesRowsTable.Remove(row.Values);
    212       row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
    213       row.NameChanged -= new EventHandler(Row_NameChanged);
    214     }
     296      RecalculateAxesScale(chart.ChartAreas[0]);
     297    }
     298
     299    #region Event Handlers
     300    #region Content Event Handlers
    215301    protected override void Content_NameChanged(object sender, EventArgs e) {
    216302      if (InvokeRequired)
     
    225311        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
    226312      else {
    227         chart.ChartAreas[0].AxisX.Title = Content.VisualProperties.XAxisTitle;
    228         chart.ChartAreas[0].AxisY.Title = Content.VisualProperties.YAxisTitle;
    229         chart.ChartAreas[0].AxisY2.Title = Content.VisualProperties.SecondYAxisTitle;
    230       }
    231     }
     313        ConfigureChartArea(chart.ChartAreas[0]);
     314        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
     315      }
     316    }
     317    #endregion
     318    #region Rows Event Handlers
    232319    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
    233320      if (InvokeRequired)
     
    278365      }
    279366    }
     367    #endregion
     368    #region Row Event Handlers
    280369    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
    281370      if (InvokeRequired)
     
    283372      else {
    284373        DataRow row = (DataRow)sender;
    285         switch (row.VisualProperties.ChartType) {
    286           case DataRowVisualProperties.DataRowChartType.Line:
    287             chart.Series[row.Name].ChartType = SeriesChartType.FastLine;
    288             break;
    289           case DataRowVisualProperties.DataRowChartType.Bars:
    290             chart.Series[row.Name].ChartType = SeriesChartType.Bar;
    291             break;
    292           case DataRowVisualProperties.DataRowChartType.Columns:
    293             chart.Series[row.Name].ChartType = SeriesChartType.Column;
    294             break;
    295           case DataRowVisualProperties.DataRowChartType.Points:
    296             chart.Series[row.Name].ChartType = SeriesChartType.FastPoint;
    297             break;
    298           default:
    299             chart.Series[row.Name].ChartType = SeriesChartType.FastPoint;
    300             break;
    301         }
    302         chart.Series[row.Name].YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary;
    303         if (row.VisualProperties.Color != Color.Empty) chart.Series[row.Name].Color = row.VisualProperties.Color;
    304         chart.ChartAreas[0].RecalculateAxesScale();
     374        Series series = chart.Series[row.Name];
     375        series.Points.Clear();
     376        ConfigureSeries(series, row);
     377        FillSeriesWithRowValues(series, row);
     378        RecalculateAxesScale(chart.ChartAreas[0]);
    305379      }
    306380    }
     
    313387      }
    314388    }
     389    #endregion
     390    #region Values Event Handlers
    315391    private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
    316392      if (InvokeRequired)
     
    324400            rowSeries.Points.Clear();
    325401            FillSeriesWithRowValues(rowSeries, row);
     402            RecalculateAxesScale(chart.ChartAreas[0]);
    326403            UpdateYCursorInterval();
    327404          }
     
    340417            rowSeries.Points.Clear();
    341418            FillSeriesWithRowValues(rowSeries, row);
     419            RecalculateAxesScale(chart.ChartAreas[0]);
    342420            UpdateYCursorInterval();
    343421          }
     
    354432          Series rowSeries = chart.Series[row.Name];
    355433          if (!invisibleSeries.Contains(rowSeries)) {
    356             foreach (IndexedItem<double> item in e.Items) {
    357               if (IsInvalidValue(item.Value))
    358                 rowSeries.Points[item.Index].IsEmpty = true;
    359               else {
    360                 rowSeries.Points[item.Index].YValues = new double[] { item.Value };
    361                 rowSeries.Points[item.Index].IsEmpty = false;
     434            if (row.VisualProperties.ChartType == DataRowVisualProperties.DataRowChartType.Histogram) {
     435              rowSeries.Points.Clear();
     436              FillSeriesWithRowValues(rowSeries, row);
     437            } else {
     438              foreach (IndexedItem<double> item in e.Items) {
     439                if (IsInvalidValue(item.Value))
     440                  rowSeries.Points[item.Index].IsEmpty = true;
     441                else {
     442                  rowSeries.Points[item.Index].YValues = new double[] { item.Value };
     443                  rowSeries.Points[item.Index].IsEmpty = false;
     444                }
    362445              }
    363446            }
     447            RecalculateAxesScale(chart.ChartAreas[0]);
    364448            UpdateYCursorInterval();
    365449          }
     
    378462            rowSeries.Points.Clear();
    379463            FillSeriesWithRowValues(rowSeries, row);
     464            RecalculateAxesScale(chart.ChartAreas[0]);
    380465            UpdateYCursorInterval();
    381466          }
     
    395480            rowSeries.Points.Clear();
    396481            FillSeriesWithRowValues(rowSeries, row);
     482            RecalculateAxesScale(chart.ChartAreas[0]);
    397483            UpdateYCursorInterval();
    398484          }
     
    401487    }
    402488    #endregion
    403 
    404     #region Chart Events
     489    #endregion
     490
     491    #region Chart Event Handlers
    405492    private void chart_MouseDown(object sender, MouseEventArgs e) {
    406493      HitTestResult result = chart.HitTest(e.X, e.Y);
     
    409496      }
    410497    }
     498    private void chart_MouseMove(object sender, MouseEventArgs e) {
     499      HitTestResult result = chart.HitTest(e.X, e.Y);
     500      if (result.ChartElementType == ChartElementType.LegendItem)
     501        this.Cursor = Cursors.Hand;
     502      else
     503        this.Cursor = Cursors.Default;
     504    }
     505    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
     506      foreach (LegendItem legendItem in e.LegendItems) {
     507        var series = chart.Series[legendItem.SeriesName];
     508        if (series != null) {
     509          bool seriesIsInvisible = invisibleSeries.Contains(series);
     510          foreach (LegendCell cell in legendItem.Cells) {
     511            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
     512          }
     513        }
     514      }
     515    }
     516    #endregion
    411517
    412518    private void ToggleSeriesVisible(Series series) {
     
    423529          FillSeriesWithRowValues(series, row);
    424530          this.chart.Legends[series.Legend].ForeColor = Color.Black;
     531          RecalculateAxesScale(chart.ChartAreas[0]);
    425532          UpdateYCursorInterval();
    426533        }
     
    429536
    430537    private void FillSeriesWithRowValues(Series series, DataRow row) {
    431       for (int i = 0; i < row.Values.Count; i++) {
    432         var value = row.Values[i];
    433         DataPoint point = new DataPoint();
    434         point.XValue = row.VisualProperties.StartIndexZero ? i : i + 1;
    435         if (IsInvalidValue(value))
    436           point.IsEmpty = true;
    437         else
    438           point.YValues = new double[] { value };
    439         series.Points.Add(point);
    440       }
    441     }
    442 
    443     private void chart_MouseMove(object sender, MouseEventArgs e) {
    444       HitTestResult result = chart.HitTest(e.X, e.Y);
    445       if (result.ChartElementType == ChartElementType.LegendItem)
    446         this.Cursor = Cursors.Hand;
    447       else
    448         this.Cursor = Cursors.Default;
    449     }
    450     private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
    451       foreach (LegendItem legendItem in e.LegendItems) {
    452         var series = chart.Series[legendItem.SeriesName];
    453         if (series != null) {
    454           bool seriesIsInvisible = invisibleSeries.Contains(series);
    455           foreach (LegendCell cell in legendItem.Cells) {
    456             cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
    457           }
    458         }
    459       }
    460     }
    461     #endregion
    462 
     538      switch (row.VisualProperties.ChartType) {
     539        case DataRowVisualProperties.DataRowChartType.Histogram:
     540          CalculateHistogram(series, row);
     541          break;
     542        default: {
     543            for (int i = 0; i < row.Values.Count; i++) {
     544              var value = row.Values[i];
     545              DataPoint point = new DataPoint();
     546              point.XValue = row.VisualProperties.StartIndexZero ? i : i + 1;
     547              if (IsInvalidValue(value))
     548                point.IsEmpty = true;
     549              else
     550                point.YValues = new double[] { value };
     551              series.Points.Add(point);
     552            }
     553          }
     554          break;
     555      }
     556    }
     557
     558    protected virtual void CalculateHistogram(Series series, DataRow row) {
     559      series.Points.Clear();
     560      if (!row.Values.Any()) return;
     561      int bins = row.VisualProperties.Bins;
     562
     563      double minValue = row.Values.Min();
     564      double maxValue = row.Values.Max();
     565      double intervalWidth = (maxValue - minValue) / bins;
     566      if (intervalWidth < 0) return;
     567      if (intervalWidth == 0) {
     568        series.Points.AddXY(minValue, row.Values.Count);
     569        return;
     570      }
     571
     572      if (!row.VisualProperties.ExactBins) {
     573        intervalWidth = HumanRoundRange(intervalWidth);
     574        minValue = Math.Floor(minValue / intervalWidth) * intervalWidth;
     575        maxValue = Math.Ceiling(maxValue / intervalWidth) * intervalWidth;
     576      }
     577
     578      double current = minValue, intervalCenter = intervalWidth / 2.0;
     579      int frequency = 0;
     580      series.Points.AddXY(current - intervalCenter, 0); // so that the first column is not visually truncated
     581      foreach (double v in row.Values.Where(x => !IsInvalidValue(x)).OrderBy(x => x)) {
     582        while (v > current + intervalWidth) {
     583          series.Points.AddXY(current + intervalCenter, frequency);
     584          current += intervalWidth;
     585          frequency = 0;
     586        }
     587        frequency++;
     588      }
     589      series.Points.AddXY(current + intervalCenter, frequency);
     590      series.Points.AddXY(current + 3 * intervalCenter, 0); // so that the last column is not visually truncated
     591    }
     592
     593    #region Helpers
     594    protected void RemoveCustomPropertyIfExists(Series series, string property) {
     595      if (series.IsCustomPropertySet(property)) series.DeleteCustomProperty(property);
     596    }
     597
     598    private double HumanRoundRange(double range) {
     599      double base10 = Math.Pow(10.0, Math.Floor(Math.Log10(range)));
     600      double rounding = range / base10;
     601      if (rounding <= 1.5) rounding = 1;
     602      else if (rounding <= 2.25) rounding = 2;
     603      else if (rounding <= 3.75) rounding = 2.5;
     604      else if (rounding <= 7.5) rounding = 5;
     605      else rounding = 10;
     606      return rounding * base10;
     607    }
     608
     609    private double HumanRoundMax(double max) {
     610      double base10;
     611      if (max > 0) base10 = Math.Pow(10.0, Math.Floor(Math.Log10(max)));
     612      else base10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(-max)));
     613      double rounding = (max > 0) ? base10 : -base10;
     614      while (rounding < max) rounding += base10;
     615      return rounding;
     616    }
     617
     618    private ChartDashStyle ConvertLineStyle(DataRowVisualProperties.DataRowLineStyle dataRowLineStyle) {
     619      switch (dataRowLineStyle) {
     620        case DataRowVisualProperties.DataRowLineStyle.Dash:
     621          return ChartDashStyle.Dash;
     622        case DataRowVisualProperties.DataRowLineStyle.DashDot:
     623          return ChartDashStyle.DashDot;
     624        case DataRowVisualProperties.DataRowLineStyle.DashDotDot:
     625          return ChartDashStyle.DashDotDot;
     626        case DataRowVisualProperties.DataRowLineStyle.Dot:
     627          return ChartDashStyle.Dot;
     628        case DataRowVisualProperties.DataRowLineStyle.NotSet:
     629          return ChartDashStyle.NotSet;
     630        case DataRowVisualProperties.DataRowLineStyle.Solid:
     631          return ChartDashStyle.Solid;
     632        default:
     633          return ChartDashStyle.NotSet;
     634      }
     635    }
    463636
    464637    /// <summary>
     
    471644      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
    472645    }
     646    #endregion
    473647  }
    474648}
Note: See TracChangeset for help on using the changeset viewer.