Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
05/30/11 18:07:32 (13 years ago)
Author:
abeham
Message:

#1465, #1469, #1470, #1494, #1496, #1497, #1539, #1487

  • merged to trunk
Location:
trunk/sources
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources

  • trunk/sources/HeuristicLab.Analysis.Views/3.3/DataTableView.cs

    r5445 r6342  
    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      ConfigureSeries(series, row);
     162      FillSeriesWithRowValues(series, row);
     163
     164      chart.Series.Add(series);
     165      ConfigureChartArea(chart.ChartAreas[0]);
     166      RecalculateAxesScale(chart.ChartAreas[0]);
     167      UpdateYCursorInterval();
     168    }
     169
     170    private void ConfigureSeries(Series series, DataRow row) {
     171      RemoveCustomPropertyIfExists(series, "PointWidth");
     172      series.BorderWidth = 1;
     173      series.BorderDashStyle = ChartDashStyle.Solid;
     174      series.BorderColor = Color.Empty;
     175
     176      if (row.VisualProperties.Color != Color.Empty)
     177        series.Color = row.VisualProperties.Color;
     178      else series.Color = Color.Empty;
     179
    122180      switch (row.VisualProperties.ChartType) {
    123181        case DataRowVisualProperties.DataRowChartType.Line:
    124182          series.ChartType = SeriesChartType.FastLine;
     183          series.BorderWidth = row.VisualProperties.LineWidth;
     184          series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);
    125185          break;
    126186        case DataRowVisualProperties.DataRowChartType.Bars:
    127           series.ChartType = SeriesChartType.Bar;
     187          // Bar is incompatible with anything but Bar and StackedBar*
     188          if (!chart.Series.Any(x => x.ChartType != SeriesChartType.Bar && x.ChartType != SeriesChartType.StackedBar && x.ChartType != SeriesChartType.StackedBar100))
     189            series.ChartType = SeriesChartType.Bar;
     190          else {
     191            series.ChartType = SeriesChartType.FastPoint; //default
     192            row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
     193          }
    128194          break;
    129195        case DataRowVisualProperties.DataRowChartType.Columns:
     
    133199          series.ChartType = SeriesChartType.FastPoint;
    134200          break;
     201        case DataRowVisualProperties.DataRowChartType.Histogram:
     202          series.ChartType = SeriesChartType.Column;
     203          series.SetCustomProperty("PointWidth", "1");
     204          if (!series.Color.IsEmpty && series.Color.GetBrightness() < 0.25)
     205            series.BorderColor = Color.White;
     206          else series.BorderColor = Color.Black;
     207          break;
    135208        default:
    136209          series.ChartType = SeriesChartType.FastPoint;
     
    138211      }
    139212      series.YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary;
    140       if (row.VisualProperties.Color != Color.Empty) series.Color = row.VisualProperties.Color;
     213      series.XAxisType = row.VisualProperties.SecondXAxis ? AxisType.Secondary : AxisType.Primary;
    141214      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    }
     216
     217    private void ConfigureChartArea(ChartArea area) {
     218      if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;
     219      if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;
     220
     221      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
     222      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
     223      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
     224
     225      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX2.TitleFont = Content.VisualProperties.AxisTitleFont;
     226      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX2.TitleForeColor = Content.VisualProperties.AxisTitleColor;
     227      area.AxisX2.Title = Content.VisualProperties.SecondXAxisTitle;
     228
     229      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
     230      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
     231      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
     232
     233      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY2.TitleFont = Content.VisualProperties.AxisTitleFont;
     234      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY2.TitleForeColor = Content.VisualProperties.AxisTitleColor;
     235      area.AxisY2.Title = Content.VisualProperties.SecondYAxisTitle;
     236    }
     237
     238    private void RecalculateAxesScale(ChartArea area) {
     239      // Reset the axes bounds so that RecalculateAxesScale() will assign new bounds
     240      foreach (Axis a in area.Axes) {
     241        a.Minimum = double.NaN;
     242        a.Maximum = double.NaN;
     243      }
     244      area.RecalculateAxesScale();
     245      area.AxisX.IsMarginVisible = false;
     246      area.AxisX2.IsMarginVisible = false;
     247
     248      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
     249      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
     250      if (!Content.VisualProperties.SecondXAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMinimumFixedValue)) area.AxisX2.Minimum = Content.VisualProperties.SecondXAxisMinimumFixedValue;
     251      if (!Content.VisualProperties.SecondXAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMaximumFixedValue)) area.AxisX2.Maximum = Content.VisualProperties.SecondXAxisMaximumFixedValue;
     252      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
     253      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
     254      if (!Content.VisualProperties.SecondYAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMinimumFixedValue)) area.AxisY2.Minimum = Content.VisualProperties.SecondYAxisMinimumFixedValue;
     255      if (!Content.VisualProperties.SecondYAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMaximumFixedValue)) area.AxisY2.Maximum = Content.VisualProperties.SecondYAxisMaximumFixedValue;
     256      if (area.AxisX.Minimum > area.AxisX.Maximum) area.AxisX.Maximum = area.AxisX.Minimum + 1;
     257      if (area.AxisX2.Minimum > area.AxisX2.Maximum) area.AxisX2.Maximum = area.AxisX2.Minimum + 1;
     258      if (area.AxisY.Minimum > area.AxisY.Maximum) area.AxisY.Maximum = area.AxisY.Minimum + 1;
     259      if (area.AxisY2.Minimum > area.AxisY2.Maximum) area.AxisY2.Maximum = area.AxisY2.Minimum + 1;
     260    }
    148261
    149262    /// <summary>
     
    151264    /// </summary>
    152265    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();
     266      double interestingValuesRange = (
     267        from series in chart.Series
     268        where series.Enabled
     269        let values = (from point in series.Points
     270                      where !point.IsEmpty
     271                      select point.YValues[0]).DefaultIfEmpty(1.0)
     272        let range = values.Max() - values.Min()
     273        where range > 0.0
     274        select range
     275        ).DefaultIfEmpty(1.0).Min();
    164276
    165277      double digits = (int)Math.Log10(interestingValuesRange) - 3;
     
    178290      if (invisibleSeries.Contains(series))
    179291        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     }
     292      RecalculateAxesScale(chart.ChartAreas[0]);
     293    }
     294
     295    #region Event Handlers
     296    #region Content Event Handlers
    215297    protected override void Content_NameChanged(object sender, EventArgs e) {
    216298      if (InvokeRequired)
     
    225307        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
    226308      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     }
     309        ConfigureChartArea(chart.ChartAreas[0]);
     310        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
     311      }
     312    }
     313    #endregion
     314    #region Rows Event Handlers
    232315    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
    233316      if (InvokeRequired)
     
    278361      }
    279362    }
     363    #endregion
     364    #region Row Event Handlers
    280365    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
    281366      if (InvokeRequired)
     
    283368      else {
    284369        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();
     370        Series series = chart.Series[row.Name];
     371        series.Points.Clear();
     372        ConfigureSeries(series, row);
     373        FillSeriesWithRowValues(series, row);
     374        RecalculateAxesScale(chart.ChartAreas[0]);
    305375      }
    306376    }
     
    313383      }
    314384    }
     385    #endregion
     386    #region Values Event Handlers
    315387    private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
    316388      if (InvokeRequired)
     
    324396            rowSeries.Points.Clear();
    325397            FillSeriesWithRowValues(rowSeries, row);
     398            RecalculateAxesScale(chart.ChartAreas[0]);
    326399            UpdateYCursorInterval();
    327400          }
     
    340413            rowSeries.Points.Clear();
    341414            FillSeriesWithRowValues(rowSeries, row);
     415            RecalculateAxesScale(chart.ChartAreas[0]);
    342416            UpdateYCursorInterval();
    343417          }
     
    354428          Series rowSeries = chart.Series[row.Name];
    355429          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;
     430            if (row.VisualProperties.ChartType == DataRowVisualProperties.DataRowChartType.Histogram) {
     431              rowSeries.Points.Clear();
     432              FillSeriesWithRowValues(rowSeries, row);
     433            } else {
     434              foreach (IndexedItem<double> item in e.Items) {
     435                if (IsInvalidValue(item.Value))
     436                  rowSeries.Points[item.Index].IsEmpty = true;
     437                else {
     438                  rowSeries.Points[item.Index].YValues = new double[] { item.Value };
     439                  rowSeries.Points[item.Index].IsEmpty = false;
     440                }
    362441              }
    363442            }
     443            RecalculateAxesScale(chart.ChartAreas[0]);
    364444            UpdateYCursorInterval();
    365445          }
     
    378458            rowSeries.Points.Clear();
    379459            FillSeriesWithRowValues(rowSeries, row);
     460            RecalculateAxesScale(chart.ChartAreas[0]);
    380461            UpdateYCursorInterval();
    381462          }
     
    395476            rowSeries.Points.Clear();
    396477            FillSeriesWithRowValues(rowSeries, row);
     478            RecalculateAxesScale(chart.ChartAreas[0]);
    397479            UpdateYCursorInterval();
    398480          }
     
    401483    }
    402484    #endregion
    403 
    404     #region Chart Events
     485    #endregion
     486
     487    #region Chart Event Handlers
    405488    private void chart_MouseDown(object sender, MouseEventArgs e) {
    406489      HitTestResult result = chart.HitTest(e.X, e.Y);
     
    409492      }
    410493    }
     494    private void chart_MouseMove(object sender, MouseEventArgs e) {
     495      HitTestResult result = chart.HitTest(e.X, e.Y);
     496      if (result.ChartElementType == ChartElementType.LegendItem)
     497        this.Cursor = Cursors.Hand;
     498      else
     499        this.Cursor = Cursors.Default;
     500    }
     501    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
     502      foreach (LegendItem legendItem in e.LegendItems) {
     503        var series = chart.Series[legendItem.SeriesName];
     504        if (series != null) {
     505          bool seriesIsInvisible = invisibleSeries.Contains(series);
     506          foreach (LegendCell cell in legendItem.Cells) {
     507            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
     508          }
     509        }
     510      }
     511    }
     512    #endregion
    411513
    412514    private void ToggleSeriesVisible(Series series) {
     
    423525          FillSeriesWithRowValues(series, row);
    424526          this.chart.Legends[series.Legend].ForeColor = Color.Black;
     527          RecalculateAxesScale(chart.ChartAreas[0]);
    425528          UpdateYCursorInterval();
    426529        }
     
    429532
    430533    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 
     534      switch (row.VisualProperties.ChartType) {
     535        case DataRowVisualProperties.DataRowChartType.Histogram:
     536          CalculateHistogram(series, row);
     537          break;
     538        default: {
     539            for (int i = 0; i < row.Values.Count; i++) {
     540              var value = row.Values[i];
     541              DataPoint point = new DataPoint();
     542              point.XValue = row.VisualProperties.StartIndexZero ? i : i + 1;
     543              if (IsInvalidValue(value))
     544                point.IsEmpty = true;
     545              else
     546                point.YValues = new double[] { value };
     547              series.Points.Add(point);
     548            }
     549          }
     550          break;
     551      }
     552    }
     553
     554    protected virtual void CalculateHistogram(Series series, DataRow row) {
     555      series.Points.Clear();
     556      if (!row.Values.Any()) return;
     557      int bins = row.VisualProperties.Bins;
     558
     559      double minValue = row.Values.Min();
     560      double maxValue = row.Values.Max();
     561      double intervalWidth = (maxValue - minValue) / bins;
     562      if (intervalWidth < 0) return;
     563      if (intervalWidth == 0) {
     564        series.Points.AddXY(minValue, row.Values.Count);
     565        return;
     566      }
     567
     568      if (!row.VisualProperties.ExactBins) {
     569        intervalWidth = HumanRoundRange(intervalWidth);
     570        minValue = Math.Floor(minValue / intervalWidth) * intervalWidth;
     571        maxValue = Math.Ceiling(maxValue / intervalWidth) * intervalWidth;
     572      }
     573
     574      double current = minValue, intervalCenter = intervalWidth / 2.0;
     575      int frequency = 0;
     576      series.Points.AddXY(current - intervalCenter, 0); // so that the first column is not visually truncated
     577      foreach (double v in row.Values.Where(x => !IsInvalidValue(x)).OrderBy(x => x)) {
     578        while (v > current + intervalWidth) {
     579          series.Points.AddXY(current + intervalCenter, frequency);
     580          current += intervalWidth;
     581          frequency = 0;
     582        }
     583        frequency++;
     584      }
     585      series.Points.AddXY(current + intervalCenter, frequency);
     586      series.Points.AddXY(current + 3 * intervalCenter, 0); // so that the last column is not visually truncated
     587    }
     588
     589    #region Helpers
     590    protected void RemoveCustomPropertyIfExists(Series series, string property) {
     591      if (series.IsCustomPropertySet(property)) series.DeleteCustomProperty(property);
     592    }
     593
     594    private double HumanRoundRange(double range) {
     595      double base10 = Math.Pow(10.0, Math.Floor(Math.Log10(range)));
     596      double rounding = range / base10;
     597      if (rounding <= 1.5) rounding = 1;
     598      else if (rounding <= 2.25) rounding = 2;
     599      else if (rounding <= 3.75) rounding = 2.5;
     600      else if (rounding <= 7.5) rounding = 5;
     601      else rounding = 10;
     602      return rounding * base10;
     603    }
     604
     605    private double HumanRoundMax(double max) {
     606      double base10;
     607      if (max > 0) base10 = Math.Pow(10.0, Math.Floor(Math.Log10(max)));
     608      else base10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(-max)));
     609      double rounding = (max > 0) ? base10 : -base10;
     610      while (rounding < max) rounding += base10;
     611      return rounding;
     612    }
     613
     614    private ChartDashStyle ConvertLineStyle(DataRowVisualProperties.DataRowLineStyle dataRowLineStyle) {
     615      switch (dataRowLineStyle) {
     616        case DataRowVisualProperties.DataRowLineStyle.Dash:
     617          return ChartDashStyle.Dash;
     618        case DataRowVisualProperties.DataRowLineStyle.DashDot:
     619          return ChartDashStyle.DashDot;
     620        case DataRowVisualProperties.DataRowLineStyle.DashDotDot:
     621          return ChartDashStyle.DashDotDot;
     622        case DataRowVisualProperties.DataRowLineStyle.Dot:
     623          return ChartDashStyle.Dot;
     624        case DataRowVisualProperties.DataRowLineStyle.NotSet:
     625          return ChartDashStyle.NotSet;
     626        case DataRowVisualProperties.DataRowLineStyle.Solid:
     627          return ChartDashStyle.Solid;
     628        default:
     629          return ChartDashStyle.NotSet;
     630      }
     631    }
    463632
    464633    /// <summary>
     
    471640      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
    472641    }
     642    #endregion
    473643  }
    474644}
Note: See TracChangeset for help on using the changeset viewer.