/// <summary> /// IndependentCategoryAxisProperty property changed handler. /// </summary> /// <param name="d">ColumnSeries that changed its IndependentCategoryAxis.</param> /// <param name="e">Event arguments.</param> private static void OnIndependentCategoryAxisPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ColumnSeries source = (ColumnSeries)d; ICategoryAxis newValue = (ICategoryAxis)e.NewValue; source.OnIndependentCategoryAxisPropertyChanged(newValue); }
/// <summary> /// Gets a range in which to render a data point. /// </summary> /// <param name="category">The category to retrieve the range for. /// </param> /// <returns>The range in which to render a data point.</returns> protected Range <UnitValue> GetCategoryRange(object category) { ICategoryAxis categoryAxis = ActualIndependentAxis as CategoryAxis; if (categoryAxis != null) { return(categoryAxis.GetPlotAreaCoordinateRange(category)); } else { UnitValue?unitValue = ActualIndependentAxis.GetPlotAreaCoordinate(category); if (unitValue.HasValue && _dataPointlength.HasValue) { double halfLength = _dataPointlength.Value / 2.0; if (unitValue.HasValue) { return(new Range <UnitValue>( new UnitValue(unitValue.Value.Value - halfLength, unitValue.Value.Unit), new UnitValue(unitValue.Value.Value + halfLength, unitValue.Value.Unit))); } } return(new Range <UnitValue>()); } }
/// <summary> /// Returns a list of categories used by the series. /// </summary> /// <param name="categoryAxis">The axis for which to retrieve the categories. /// </param> /// <returns>A list of categories used by the series.</returns> IEnumerable <object> ICategoryAxisInformationProvider.GetCategories(ICategoryAxis categoryAxis) { IAxis axis = (IAxis)categoryAxis; if (axis == null) { throw new ArgumentNullException("categoryAxis"); } Func <DataPoint, object> selector = null; if (axis == InternalActualIndependentAxis) { if (IndependentValueBinding == null) { return(Enumerable.Range(1, ActiveDataPointCount).Cast <object>()); } selector = (dataPoint) => dataPoint.IndependentValue ?? dataPoint.DependentValue; } else if (axis == InternalActualDependentAxis) { selector = (dataPoint) => dataPoint.DependentValue; } return(ActiveDataPoints.Select(selector).Distinct()); }
/// <summary> /// Update axes when a data point's effective independent value changes. /// </summary> private void UpdateActualIndependentAxis() { if (InternalActualIndependentAxis != null) { ICategoryAxis categoryAxis = InternalActualIndependentAxis as ICategoryAxis; if (categoryAxis != null) { IDataProvider categoryInformationProvider = (IDataProvider)this; categoryAxis.DataChanged(categoryInformationProvider, categoryInformationProvider.GetData(categoryAxis)); } IRangeConsumer rangeAxis = InternalActualIndependentAxis as IRangeConsumer; if (rangeAxis != null) { IRangeProvider rangeInformationProvider = (IRangeProvider)this; rangeAxis.RangeChanged(rangeInformationProvider, rangeInformationProvider.GetRange(rangeAxis)); } } }
/// <summary> /// Update axes when a data point's effective independent value changes. /// </summary> private void UpdateActualIndependentAxis() { if (InternalActualIndependentAxis != null) { ICategoryAxis categoryAxis = InternalActualIndependentAxis as ICategoryAxis; if (categoryAxis != null) { ICategoryAxisInformationProvider categoryInformationProvider = (ICategoryAxisInformationProvider)this; categoryAxis.Update(categoryInformationProvider, categoryInformationProvider.GetCategories(categoryAxis)); } IRangeAxis rangeAxis = InternalActualIndependentAxis as IRangeAxis; if (rangeAxis != null) { IRangeAxisInformationProvider rangeInformationProvider = (IRangeAxisInformationProvider)this; rangeAxis.Update(rangeInformationProvider, rangeInformationProvider.GetActualRange(rangeAxis)); } } }
/// <summary> /// IndependentCategoryAxisProperty property changed handler. /// </summary> /// <param name="newValue">New value.</param> private void OnIndependentCategoryAxisPropertyChanged(ICategoryAxis newValue) { this.InternalIndependentAxis = (IAxis)newValue; }
/// <summary> /// Acquires a category axis. /// </summary> /// <param name="assignedAxis">The axis assigned to the exposed /// axis property.</param> /// <param name="firstDataPoint">A data point used to determine /// where a date or numeric axis is required.</param> /// <param name="orientation">The desired orientation of the axis. /// </param> /// <param name="axisInitializationAction">A function that initializes /// a newly created axis.</param> /// <param name="axisPropertyAccessor">A function that returns the /// current value of the property used to store the axis.</param> /// <param name="axisPropertySetter">A function that accepts an axis /// value and assigns it to the property intended to store a reference /// to it.</param> /// <param name="dataPointAxisValueGetter">A function that retrieves /// the value to plot on the axis from the data point.</param> protected void GetCategoryAxis( IAxis assignedAxis, DataPoint firstDataPoint, AxisOrientation orientation, Func <ICategoryAxis> axisInitializationAction, Func <ICategoryAxis> axisPropertyAccessor, Action <ICategoryAxis> axisPropertySetter, Func <DataPoint, object> dataPointAxisValueGetter) { object firstCategoryValue = dataPointAxisValueGetter(firstDataPoint); if (assignedAxis != null) { if (assignedAxis.Orientation == orientation) { ICategoryAxis assignedCategoryAxis = assignedAxis as CategoryAxis; if (assignedCategoryAxis != null) { if (assignedCategoryAxis.CanPlot(firstCategoryValue)) { axisPropertySetter(assignedCategoryAxis); if (!assignedAxis.IsObjectRegistered(this)) { assignedCategoryAxis.Invalidated += OnAxisInvalidated; this.SeriesHost.RegisterWithAxis(this, (IAxis)assignedCategoryAxis); } return; } else { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Properties.Resources.DataPointSeriesWithAxes_AxisCannotPlotValue, firstCategoryValue)); } } else { throw new InvalidOperationException(Properties.Resources.DataPointSeriesWithAxes_ExpectedAxesOfTypeICategoryAxis); } } else { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Properties.Resources.DataPointSeriesWithAxes_AxisIsIncorrectOrientation, orientation)); } } IAxis actualIndependentAxis = axisPropertyAccessor() as IAxis; // Only acquire new independent axis if necessary if (actualIndependentAxis == null || actualIndependentAxis.Orientation != orientation) { ICategoryAxis categoryAxis = SeriesHost .Axes.Where(currentAxis => currentAxis.Orientation == orientation) .OfType <ICategoryAxis>() .Where( currentCategoryAxis => currentCategoryAxis.CanPlot(firstCategoryValue) && currentCategoryAxis.CanRegister(this)) .FirstOrDefault(); if (categoryAxis == null) { categoryAxis = axisInitializationAction(); categoryAxis.Orientation = orientation; } // Unregister with current axis if it has one. if (axisPropertyAccessor() != null) { axisPropertyAccessor().Invalidated -= OnAxisInvalidated; ICategoryAxis oldCategoryAxis = axisPropertyAccessor() as ICategoryAxis; this.SeriesHost.UnregisterWithAxis(this, (IAxis)oldCategoryAxis); } // Set axis to be its independent axis axisPropertySetter(categoryAxis); if (!categoryAxis.IsObjectRegistered(this)) { categoryAxis.Invalidated += OnAxisInvalidated; // Register new axis with series host this.SeriesHost.RegisterWithAxis(this, (IAxis)categoryAxis); } } }
protected override void UpdateDataItemPlacement(IEnumerable <DefinitionSeries.DataItem> dataItems) { IAxis actualIndependentAxis = ActualIndependentAxis; if ((null != ActualDependentAxis) && (null != actualIndependentAxis)) { double plotAreaMaximumDependentCoordinate = ActualDependentAxis.GetPlotAreaCoordinate(ActualDependentRangeAxis.Range.Maximum).Value; double zeroCoordinate = ActualDependentAxis.GetPlotAreaCoordinate(ActualDependentRangeAxis.Origin ?? 0.0).Value; ICategoryAxis actualIndependentCategoryAxis = actualIndependentAxis as ICategoryAxis; double nonCategoryAxisRangeMargin = (null != actualIndependentCategoryAxis) ? 0 : GetMarginForNonCategoryAxis(actualIndependentAxis); foreach (IndependentValueGroup group in IndependentValueGroups) { Range <UnitValue> categoryRange = new Range <UnitValue>(); if (null != actualIndependentCategoryAxis) { categoryRange = actualIndependentCategoryAxis.GetPlotAreaCoordinateRange(group.IndependentValue); } else { UnitValue independentValueCoordinate = actualIndependentAxis.GetPlotAreaCoordinate(group.IndependentValue); if (ValueHelper.CanGraph(independentValueCoordinate.Value)) { categoryRange = new Range <UnitValue>(new UnitValue(independentValueCoordinate.Value - nonCategoryAxisRangeMargin, independentValueCoordinate.Unit), new UnitValue(independentValueCoordinate.Value + nonCategoryAxisRangeMargin, independentValueCoordinate.Unit)); } } if (categoryRange.HasData) { double categoryMinimumCoordinate = categoryRange.Minimum.Value; double categoryMaximumCoordinate = categoryRange.Maximum.Value; double padding = 0.1 * (categoryMaximumCoordinate - categoryMinimumCoordinate); categoryMinimumCoordinate += padding; categoryMaximumCoordinate -= padding; double sum = IsStacked100 ? group.DataItems.Sum(di => Math.Abs(ValueHelper.ToDouble(di.DataPoint.ActualDependentValue))) : 1; if (0 == sum) { sum = 1; } double ceiling = 0; double floor = 0; foreach (DataItem dataItem in group.DataItems) { DataPoint dataPoint = dataItem.DataPoint; double value = IsStacked100 ? (ValueHelper.ToDouble(dataPoint.ActualDependentValue) * (100 / sum)) : ValueHelper.ToDouble(dataPoint.ActualDependentValue); if (ValueHelper.CanGraph(value)) { double valueCoordinate = ActualDependentAxis.GetPlotAreaCoordinate(value).Value; double fillerCoordinate = (0 <= value) ? ceiling : floor; double topCoordinate = 0, leftCoordinate = 0, height = 0, width = 0, deltaCoordinate = 0; if (AxisOrientation.Y == ActualDependentAxis.Orientation) { topCoordinate = plotAreaMaximumDependentCoordinate - Math.Max(valueCoordinate + fillerCoordinate, zeroCoordinate + fillerCoordinate); double bottomCoordinate = plotAreaMaximumDependentCoordinate - Math.Min(valueCoordinate + fillerCoordinate, zeroCoordinate + fillerCoordinate); deltaCoordinate = bottomCoordinate - topCoordinate; height = (0 < deltaCoordinate) ? deltaCoordinate + 1 : 0; leftCoordinate = categoryMinimumCoordinate; width = categoryMaximumCoordinate - categoryMinimumCoordinate + 1; } else { leftCoordinate = Math.Min(valueCoordinate + fillerCoordinate, zeroCoordinate + fillerCoordinate); double rightCoordinate = Math.Max(valueCoordinate + fillerCoordinate, zeroCoordinate + fillerCoordinate); deltaCoordinate = rightCoordinate - leftCoordinate; width = (0 < deltaCoordinate) ? deltaCoordinate + 1 : 0; topCoordinate = categoryMinimumCoordinate; height = categoryMaximumCoordinate - categoryMinimumCoordinate + 1; } double roundedTopCoordinate = Math.Round(topCoordinate); Canvas.SetTop(dataItem.Container, roundedTopCoordinate); dataPoint.Height = Math.Round(topCoordinate + height - roundedTopCoordinate); double roundedLeftCoordinate = Math.Round(leftCoordinate); Canvas.SetLeft(dataItem.Container, roundedLeftCoordinate); dataPoint.Width = Math.Round(leftCoordinate + width - roundedLeftCoordinate); dataPoint.Visibility = Visibility.Visible; if (0 <= value) { ceiling += deltaCoordinate; } else { floor -= deltaCoordinate; } } else { dataPoint.Visibility = Visibility.Collapsed; } } } else { foreach (DataPoint dataPoint in group.DataItems.Select(di => di.DataPoint)) { dataPoint.Visibility = Visibility.Collapsed; } } } } }
/// <summary> /// Updates each point. /// </summary> /// <param name="dataPoint">The data point to update.</param> protected override void UpdateDataPoint(DataPoint dataPoint) { if (SeriesHost == null || plotArea == null) { return; } object category = dataPoint.ActualIndependentValue ?? (this.ActiveDataPoints.IndexOf(dataPoint) + 1); ICategoryAxis categoryAxis = ActualIndependentAxis as ScrollableCategoryAxis; Range <UnitValue> coordinateRange = categoryAxis.GetPlotAreaCoordinateRange(category); if (!coordinateRange.HasData) { return; } else if (coordinateRange.Maximum.Unit != Unit.Pixels || coordinateRange.Minimum.Unit != Unit.Pixels) { throw new InvalidOperationException("This series does not support radial axes."); } double minimum = (double)coordinateRange.Minimum.Value; double maximum = (double)coordinateRange.Maximum.Value; double plotAreaHeight = ActualDependentRangeAxis.GetPlotAreaCoordinate(ActualDependentRangeAxis.Range.Maximum).Value; IEnumerable <ColumnSeries> columnSeries = SeriesHost.Series.OfType <ColumnSeries>().Where(series => series.ActualIndependentAxis == ActualIndependentAxis); int numberOfSeries = columnSeries.Count(); double coordinateRangeWidth = (maximum - minimum); double segmentWidth = coordinateRangeWidth * 0.8; double columnWidth = segmentWidth / numberOfSeries; int seriesIndex = columnSeries.IndexOf(this); double dataPointY = ActualDependentRangeAxis.GetPlotAreaCoordinate(ValueHelper.ToDouble(dataPoint.ActualDependentValue)).Value; double zeroPointY = ActualDependentRangeAxis.GetPlotAreaCoordinate(ActualDependentRangeAxis.Origin).Value; double offset = seriesIndex * Math.Round(columnWidth) + coordinateRangeWidth * 0.1; double dataPointX = minimum + offset; if (GetIsDataPointGrouped(category)) { // Multiple DataPoints share this category; offset and overlap them appropriately IGrouping <object, DataPoint> categoryGrouping = GetDataPointGroup(category); int index = categoryGrouping.IndexOf(dataPoint); dataPointX += (index * (columnWidth * 0.2)) / (categoryGrouping.Count() - 1); columnWidth *= 0.8; Canvas.SetZIndex(dataPoint, -index); } if (ValueHelper.CanGraph(dataPointY) && ValueHelper.CanGraph(dataPointX) && ValueHelper.CanGraph(zeroPointY)) { dataPoint.Visibility = Visibility.Visible; double left = Math.Round(dataPointX); double width = Math.Round(columnWidth); double top = Math.Round(plotAreaHeight - Math.Max(dataPointY, zeroPointY) + 0.5); double bottom = Math.Round(plotAreaHeight - Math.Min(dataPointY, zeroPointY) + 0.5); double height = bottom - top + 1; Canvas.SetLeft(dataPoint, left); Canvas.SetTop(dataPoint, top); dataPoint.Width = width; dataPoint.Height = height; } else { dataPoint.Visibility = Visibility.Collapsed; } }