private void GetBrushesFromPalette(double currentValue, double nextValue, out Brush strokeBrush, out Brush fillBrush) { // Set default values. strokeBrush = BorderBrush; fillBrush = Background; Palette fillPalette = EffectiveFillPalette; Palette strokePalette = EffectiveStrokePalette; if (FillMode == BarFillMode.Solid) { // Solid: // Get a solid color brush for fill and stroke. if (fillPalette != null && fillPalette.Count > 0) { fillBrush = new SolidColorBrush(fillPalette.GetColor(currentValue)); } if (strokePalette != null && strokePalette.Count > 0) { strokeBrush = new SolidColorBrush(strokePalette.GetColor(nextValue)); } } else { // Gradient: // Define end point for gradient direction. Point startPoint = new Point(0, 0); Point endPoint = new Point(1, 0); Axis xAxis = XAxis; if (xAxis.Scale.Reversed) { ChartHelper.Swap(ref startPoint, ref endPoint); } // Get brush for fill and stroke. if (fillPalette != null && fillPalette.Count > 0) { fillBrush = new LinearGradientBrush { GradientStops = fillPalette.GetGradient(currentValue, nextValue), StartPoint = startPoint, EndPoint = endPoint, ColorInterpolationMode = fillPalette.ColorInterpolationMode }; } if (strokePalette != null && strokePalette.Count > 0) { strokeBrush = new LinearGradientBrush { GradientStops = strokePalette.GetGradient(currentValue, nextValue), StartPoint = startPoint, EndPoint = endPoint, ColorInterpolationMode = strokePalette.ColorInterpolationMode }; } } }
/// <summary> /// Returns the data value of a position (given in device-independent pixels) on the axis. /// </summary> /// <param name="position">The position on the axis.</param> /// <param name="startPosition">The start position (origin) of the axis.</param> /// <param name="endPosition">The end position of the axis.</param> /// <returns>The data value of the given position.</returns> /// <remarks> /// An <see cref="Axis"/> is one-dimensional, so one component of a 2d position is /// neglected. If this scale belongs to an x-axis, then the positions are x-positions; /// otherwise the positions are y-positions. /// </remarks> public virtual double GetValue(double position, double startPosition, double endPosition) { if (_reversed) { ChartHelper.Swap(ref startPosition, ref endPosition); } return(Min + (position - startPosition) / (endPosition - startPosition) * (Max - Min)); }
/// <summary> /// Gets the position on the axis for a specified data value. /// </summary> /// <param name="value">The data value.</param> /// <param name="startPosition">The start position (origin) of the axis.</param> /// <param name="endPosition">The end position of the axis.</param> /// <returns>The position of the data value on the axis.</returns> public virtual double GetPosition(double value, double startPosition, double endPosition) { if (_reversed) { ChartHelper.Swap(ref startPosition, ref endPosition); } return(startPosition + (value - Min) / (Max - Min) * (endPosition - startPosition)); }
public override double GetValue(double position, double startPosition, double endPosition) { if (Min >= Max) { throw new ChartException("AxisScale.Min must be less than AxisScale.Max."); } if (Reversed) { ChartHelper.Swap(ref startPosition, ref endPosition); } double v = (position - startPosition) / (endPosition - startPosition); double value = Min * Math.Pow(Max / Min, v); return(value); }
/// <summary> /// Gets the position on the axis for a specified data value. /// </summary> /// <param name="value">The data value.</param> /// <param name="startPosition">The start position (origin) of the axis.</param> /// <param name="endPosition">The end position of the axis.</param> /// <returns>The position of the data value on the axis.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="value"/> is negative. /// </exception> /// <exception cref="ChartException"> /// Invalid scale. <see cref="AxisScale.Min"/> is greater than or equal to /// <see cref="AxisScale.Max"/>. /// </exception> public override double GetPosition(double value, double startPosition, double endPosition) { if (Min >= Max) { throw new ChartException("Scale.Min must be less than Scale.Max."); } if (value < 0.0f) { throw new ArgumentOutOfRangeException("value", "Cannot have negative values for data using a logarithmic scale."); } if (Reversed) { ChartHelper.Swap(ref startPosition, ref endPosition); } double logValue = Math.Log10(value); double logMin = Math.Log10(Min); double logMax = Math.Log10(Max); return((float)(startPosition + (logValue - logMin) / (logMax - logMin) * (endPosition - startPosition))); }
private void Update() { if (_isValid) { return; } _sectorGeometry.Clear(); _leaderLineGeometry.Clear(); // Fetch dependency properties. (Accessing dependency properties is expensive.) double centerX = CenterX; double centerY = CenterY; double innerRadius = InnerRadius; double outerRadius = OuterRadius; double offset = Offset; double startAngle = StartAngle; double endAngle = EndAngle; // Correct invalid values. if (innerRadius < 0) { innerRadius = 0; } if (outerRadius < 0) { outerRadius = 0; } if (innerRadius > outerRadius) { innerRadius = outerRadius; } if (startAngle > endAngle) { ChartHelper.Swap(ref startAngle, ref endAngle); } // The sector angle. double angle = endAngle - startAngle; // The thickness of the ring. double width = outerRadius - innerRadius; // The direction vector pointing from the center to the start of the sector. double startX, startY; GetDirection(startAngle, out startX, out startY); // The direction vector pointing from the center to the end of the sector. double endX, endY; GetDirection(endAngle, out endX, out endY); // The direction vector pointing from the center to the middle of the sector. double midX, midY; GetDirection((startAngle + endAngle) / 2, out midX, out midY); // Exploded pie charts: Translate the center of the pie chart. centerX += offset * midX; centerY += offset * midY; if (angle < 2 * Math.PI) { // ---- Draw sector. Point p0 = new Point(centerX + innerRadius * startX, centerY + innerRadius * startY); Point p1 = new Point(centerX + outerRadius * startX, centerY + outerRadius * startY); Point p2 = new Point(centerX + outerRadius * endX, centerY + outerRadius * endY); Point p3 = new Point(centerX + innerRadius * endX, centerY + innerRadius * endY); var figure = new PathFigure { StartPoint = p0 }; figure.Segments.Add(new LineSegment { Point = p1 }); figure.Segments.Add(new ArcSegment { Point = p2, Size = new Size(outerRadius, outerRadius), IsLargeArc = angle > Math.PI, SweepDirection = SweepDirection.Clockwise }); figure.Segments.Add(new LineSegment { Point = p3 }); figure.Segments.Add(new ArcSegment { Point = p0, Size = new Size(innerRadius, innerRadius), IsLargeArc = angle > Math.PI, SweepDirection = SweepDirection.Counterclockwise }); _sectorGeometry.Figures.Add(figure); } else { if (innerRadius > 0) { // ----- Draw full ring. Point p0 = new Point(centerX, centerY - outerRadius); Point p1 = new Point(centerX, centerY + outerRadius); Point p2 = new Point(centerX, centerY - innerRadius); Point p3 = new Point(centerX, centerY + innerRadius); // Outer circle (= two half-circles). var figure = new PathFigure { StartPoint = p0 }; figure.Segments.Add(new ArcSegment { Point = p1, Size = new Size(outerRadius, outerRadius), SweepDirection = SweepDirection.Clockwise }); figure.Segments.Add(new ArcSegment { Point = p0, Size = new Size(outerRadius, outerRadius), SweepDirection = SweepDirection.Clockwise }); _sectorGeometry.Figures.Add(figure); // Inner circle (= two half-circles). figure = new PathFigure { StartPoint = p2 }; figure.Segments.Add(new ArcSegment { Point = p3, Size = new Size(innerRadius, innerRadius), SweepDirection = SweepDirection.Clockwise }); figure.Segments.Add(new ArcSegment { Point = p2, Size = new Size(innerRadius, innerRadius), SweepDirection = SweepDirection.Clockwise }); _sectorGeometry.Figures.Add(figure); } else { // ----- Draw full disc. Point p0 = new Point(centerX, centerY - outerRadius); Point p1 = new Point(centerX, centerY + outerRadius); // Outer circle (= two half-circles). var figure = new PathFigure { StartPoint = p0 }; figure.Segments.Add(new ArcSegment { Point = p1, Size = new Size(outerRadius, outerRadius), SweepDirection = SweepDirection.Clockwise }); figure.Segments.Add(new ArcSegment { Point = p0, Size = new Size(outerRadius, outerRadius), SweepDirection = SweepDirection.Clockwise }); _sectorGeometry.Figures.Add(figure); } } // ----- Draw inner label. if (InnerLabel != null && angle > InnerLabelClipAngle) { _innerLabel.Visibility = Visibility.Visible; _innerLabel.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); Size size = _innerLabel.DesiredSize; if (size.Width > 0 && size.Height > 0) { double x = centerX + innerRadius * midX + 0.6 * width * midX; double y = centerY + innerRadius * midY + 0.6 * width * midY; x -= size.Width / 2; y -= size.Height / 2; Canvas.SetLeft(_innerLabel, x); Canvas.SetTop(_innerLabel, y); } } else { _innerLabel.Visibility = Visibility.Collapsed; } // ----- Draw outer label. if (OuterLabel != null && angle > OuterLabelClipAngle) { _outerLabel.Visibility = Visibility.Visible; _outerLabel.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); Size size = _outerLabel.DesiredSize; if (size.Width > 0 && size.Height > 0) { // Draw leader line. double outerLabelDistance = LeaderLineLength; double l1 = 0.667 * outerLabelDistance; // Segment normal to circle. double l2 = 0.333 * outerLabelDistance; // Horizontal segment. double d = 0.5 * l2; // Distance between line and label. Point p0 = new Point(centerX + outerRadius * midX, centerY + outerRadius * midY); Point p1 = new Point(centerX + (outerRadius + l1) * midX, centerY + (outerRadius + l1) * midY); Point p2 = new Point(p1.X + l2 * Math.Sign(midX), p1.Y); var line = new PathFigure { StartPoint = p0 }; line.Segments.Add(new LineSegment { Point = p1 }); line.Segments.Add(new LineSegment { Point = p2 }); _leaderLineGeometry.Figures.Add(line); if (midX >= 0) { // Label on the right. Canvas.SetLeft(_outerLabel, p2.X + d); Canvas.SetTop(_outerLabel, p2.Y - size.Height / 2); } else { // Label on the left. Canvas.SetLeft(_outerLabel, p2.X - d - size.Width); Canvas.SetTop(_outerLabel, p2.Y - size.Height / 2); } } } else { _outerLabel.Visibility = Visibility.Collapsed; } _isValid = true; }
/// <inheritdoc/> protected override void OnUpdate() { base.OnUpdate(); Debug.Assert(Canvas.Children.Count == 0, "Canvas should be cleared in base class."); if (Data == null || Data.Count == 0 || DataPointTemplate == null) { // A relevant property is not set. return; } // Fetch dependency properties. (Accessing dependency properties is expensive.) Axis xAxis = XAxis; Axis yAxis = YAxis; AxisScale xScale = xAxis.Scale; AxisScale yScale = yAxis.Scale; double centerX = CenterX; double centerY = CenterY; double hole = Hole; double outerRadius = Radius; Thickness padding = Padding; if (hole < 0 || hole > 1) { throw new ChartException("Pie chart has invalid hole size. The hole size is relative to the outer radius and must be in the range [0, 1]."); } if (outerRadius < 0) { throw new ChartException("Pie chart has invalid radius. The radius must be a equal to or greater than 0."); } // Determine available space. double left = xAxis.GetPosition(xScale.Min); double right = xAxis.GetPosition(xScale.Max); if (left > right) { // Scale is reversed. ChartHelper.Swap(ref left, ref right); } double top = yAxis.GetPosition(yScale.Max); double bottom = yAxis.GetPosition(yScale.Min); if (top > bottom) { // Scale is reversed. ChartHelper.Swap(ref top, ref bottom); } // Apply padding. left += padding.Left; right -= padding.Right; top += padding.Top; bottom -= padding.Bottom; if (Numeric.IsNaN(centerX)) { // Center pie chart horizontally. centerX = (left + right) / 2; } else { centerX = xAxis.OriginX + centerX * xAxis.Length; } if (Numeric.IsNaN(centerY)) { // Center pie chart vertically. centerY = (top + bottom) / 2; } else { centerY = yAxis.OriginY - (1.0 - centerY) * yAxis.Length; } if (Numeric.IsNaN(outerRadius)) { // Fit pie chart into available space. double radiusLeft = centerX - left; double radiusRight = right - centerX; double radiusTop = centerY - top; double radiusBottom = bottom - centerY; outerRadius = radiusLeft; if (outerRadius > radiusRight) { outerRadius = radiusRight; } if (outerRadius > radiusTop) { outerRadius = radiusTop; } if (outerRadius > radiusBottom) { outerRadius = radiusBottom; } } if (Numeric.IsNaN(hole)) { hole = 0; } double innerRadius = hole * outerRadius; ActualHoleRadius = innerRadius; // Draw pie chart inside chart panel. DrawPieChart(Canvas, centerX, centerY, innerRadius, outerRadius, BrushSelector, false); // Update legend symbols inside legends. // Use a fixed innerRadius innerRadius = (Hole > 0) ? 2 : 0; foreach (var legendSymbol in _legendSymbols) { DrawPieChart(legendSymbol, 8, 8, innerRadius, 8, BrushSelector, true); } }
private void GetBrushes(double paletteIndex, out Brush strokeBrush, out Brush fillBrush) { Axis xAxis = XAxis; Axis yAxis = YAxis; strokeBrush = null; fillBrush = null; if (FillMode == BarFillMode.Solid) { // Solid: // Get a solid color brush for fill and stroke. if (FillPalette != null && FillPalette.Count > 0) { fillBrush = new SolidColorBrush(FillPalette.GetColor(paletteIndex)); } if (StrokePalette != null && StrokePalette.Count > 0) { strokeBrush = new SolidColorBrush(StrokePalette.GetColor(paletteIndex)); } } else { // Gradient: // We draw from 0 upwards or from a negative value upwards to 0. double lower = Math.Min(0, paletteIndex); double higher = Math.Max(0, paletteIndex); // Define end point for gradient direction. Point startPoint; Point endPoint; if (PaletteIndex == PaletteIndex.XValue) { // Horizontal startPoint = new Point(0, 0); endPoint = new Point(1, 0); if (xAxis != null && xAxis.Scale != null && xAxis.Scale.Reversed) { ChartHelper.Swap(ref startPoint, ref endPoint); } } else { // Vertical startPoint = new Point(0, 1); endPoint = new Point(0, 0); if (yAxis != null && yAxis.Scale != null && yAxis.Scale.Reversed) { ChartHelper.Swap(ref startPoint, ref endPoint); } } // Get brush for fill and stroke. if (FillPalette != null && FillPalette.Count > 0) { fillBrush = new LinearGradientBrush { GradientStops = FillPalette.GetGradient(lower, higher), StartPoint = startPoint, EndPoint = endPoint, ColorInterpolationMode = FillPalette.ColorInterpolationMode }; } if (StrokePalette != null && StrokePalette.Count > 0) { strokeBrush = new LinearGradientBrush { GradientStops = StrokePalette.GetGradient(lower, higher), StartPoint = startPoint, EndPoint = endPoint, ColorInterpolationMode = StrokePalette.ColorInterpolationMode }; } } }
protected override Size ArrangeOverride(Size finalSize) { // Ensure that all axes are up to date. foreach (Axis axis in _monitoredAxes) { axis.Update(); } UIElementCollection children = Children; for (int i = 0; i < children.Count; ++i) { UIElement child = children[i]; if (child == null) { continue; } // Get the child or one of its descendants that needs to be positioned. DependencyObject elementThatRequiresArrange = GetElementThatRequiresArrange(child); if (elementThatRequiresArrange == null) { // This child ignores the attached properties (X1, Y1, X2, Y2). Rect childBounds = new Rect(new Point(), finalSize); // Arrange element, child.Arrange(childBounds); // Clip to chart area. if (GetClipToChartArea(child)) { ClipElementToChartArea(child, childBounds); } } else { // Determine alignment. HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left; VerticalAlignment verticalAlignment = VerticalAlignment.Top; if (elementThatRequiresArrange is FrameworkElement) { FrameworkElement frameworkElement = (FrameworkElement)elementThatRequiresArrange; horizontalAlignment = frameworkElement.HorizontalAlignment; verticalAlignment = frameworkElement.VerticalAlignment; } // Get associated axes. Axis xAxis = GetXAxis(elementThatRequiresArrange); Axis yAxis = GetYAxis(elementThatRequiresArrange); // Check whether we have to position the element relative to a point (X1, Y1) // or inside a region (X1, Y1) - (X2, Y2). // Convert positions given in data values to pixel positions. double x1 = xAxis.GetPosition(GetX1(elementThatRequiresArrange)); double y1 = yAxis.GetPosition(GetY1(elementThatRequiresArrange)); double x2 = xAxis.GetPosition(GetX2(elementThatRequiresArrange)); double y2 = yAxis.GetPosition(GetY2(elementThatRequiresArrange)); bool isX1Valid = Numeric.IsFinite(x1); bool isY1Valid = Numeric.IsFinite(y1); bool isX2Valid = Numeric.IsFinite(x2); bool isY2Valid = Numeric.IsFinite(y2); double availableWidth = Double.PositiveInfinity; double availableHeight = Double.PositiveInfinity; if (!isX1Valid && !isX2Valid) { // No coordinates set. Use 0 and 'left' alignment. x1 = 0; x2 = Double.NaN; horizontalAlignment = HorizontalAlignment.Left; } else if (!isX1Valid) { // Only X2 set. Use X2 as position. x1 = x2; x2 = Double.NaN; } else if (isX2Valid) { // X1 and X2 are set. int result = Numeric.Compare(x1, x2); if (result < 0) { // X1 < X2: Horizontal region. availableWidth = x2 - x1; } else if (result == 0) { // X1 == X2: Use only X1. x2 = Double.NaN; } else { // X2 > X1: Horizontal region, but swapped. ChartHelper.Swap(ref x1, ref x2); availableWidth = x2 - x1; } } if (!isY1Valid && !isY2Valid) { // No coordinates set. Use 0 and 'top' alignment. y1 = 0; y2 = Double.NaN; verticalAlignment = VerticalAlignment.Top; } else if (!isY1Valid) { // Only Y2 set. Use Y2 as position. y1 = y2; y2 = Double.NaN; } else if (isY2Valid) { // Y1 and Y2 are set. int result = Numeric.Compare(y1, y2); if (result < 0) { // Y1 < Y2: Horizontal region. availableHeight = y2 - y1; } else if (result == 0) { // Y1 == Y2: Use only Y1. y2 = Double.NaN; } else { // Y2 > Y1: Horizontal region, but swapped. ChartHelper.Swap(ref y1, ref y2); availableHeight = y2 - y1; } } // Get size of child. double elementWidth = child.DesiredSize.Width; double elementHeight = child.DesiredSize.Height; if (elementWidth == 0.0 && elementHeight == 0.0 && child is FrameworkElement) { // Fix for Silverlight. FrameworkElement frameworkElement = (FrameworkElement)child; elementWidth = frameworkElement.ActualWidth; elementHeight = frameworkElement.ActualHeight; } // Compute bounds of the child element. Rect childBounds = new Rect(); // Position child horizontally. if (Numeric.IsNaN(x2)) { // Position child relative to point. switch (horizontalAlignment) { case HorizontalAlignment.Left: case HorizontalAlignment.Stretch: childBounds.X = x1; childBounds.Width = elementWidth; break; case HorizontalAlignment.Center: childBounds.X = x1 - elementWidth / 2.0; childBounds.Width = elementWidth; break; case HorizontalAlignment.Right: childBounds.X = x1 - elementWidth; childBounds.Width = elementWidth; break; } } else { // Position child inside horizontal region. switch (horizontalAlignment) { case HorizontalAlignment.Left: childBounds.X = x1; childBounds.Width = elementWidth; break; case HorizontalAlignment.Center: childBounds.X = x1 + availableWidth / 2.0 - elementWidth / 2.0; childBounds.Width = elementWidth; break; case HorizontalAlignment.Right: childBounds.X = x2 - elementWidth; childBounds.Width = elementWidth; break; case HorizontalAlignment.Stretch: childBounds.X = x1; childBounds.Width = availableWidth; break; } } // Position child vertically. if (Numeric.IsNaN(y2)) { // Position child relative to point. switch (verticalAlignment) { case VerticalAlignment.Top: case VerticalAlignment.Stretch: childBounds.Y = y1; childBounds.Height = elementHeight; break; case VerticalAlignment.Center: childBounds.Y = y1 - elementHeight / 2.0; childBounds.Height = elementHeight; break; case VerticalAlignment.Bottom: childBounds.Y = y1 - elementHeight; childBounds.Height = elementHeight; break; } } else { // Position child inside vertical region. switch (verticalAlignment) { case VerticalAlignment.Top: childBounds.Y = y1; childBounds.Height = elementHeight; break; case VerticalAlignment.Center: childBounds.Y = y1 + availableHeight / 2.0 - elementHeight / 2.0; childBounds.Height = elementHeight; break; case VerticalAlignment.Bottom: childBounds.Y = y2 - elementHeight; childBounds.Height = elementHeight; break; case VerticalAlignment.Stretch: childBounds.Y = y1; childBounds.Height = availableHeight; break; } } // Arrange element. child.Arrange(childBounds); // Clip to chart area. if (elementThatRequiresArrange is UIElement && GetClipToChartArea(elementThatRequiresArrange)) { UIElement element = (UIElement)elementThatRequiresArrange; ClipElementToChartArea(element, childBounds); } } } return(finalSize); }
protected virtual void OnGetStrokeAndFillForLegendSymbol(double paletteIndex, out Brush stroke, out Brush fill) { Axis xAxis = XAxis; Axis yAxis = YAxis; // Check coloring parameters. if (PaletteIndex == PaletteIndex.Index && FillMode == AreaFillMode.GradientVertical || PaletteIndex == PaletteIndex.XValue && FillMode == AreaFillMode.GradientVertical) { throw new NotSupportedException("Vertical gradients are only supported if the palette is indexed by y values."); } // Set default values for stroke and fill brush. stroke = null; fill = null; // Try to find colors in palette. // We draw from 0 upwards or from a negative value upwards to 0. double lower = Math.Min(0, paletteIndex); double higher = Math.Max(0, paletteIndex); //if (FillMode == AreaFillMode.Solid) //{ // // Fill legend symbol with single color. // lower = higher; //} // Define gradient direction. Point startPoint; Point endPoint; if (PaletteIndex == PaletteIndex.Index || PaletteIndex == PaletteIndex.XValue || FillMode == AreaFillMode.GradientHorizontal || FillMode == AreaFillMode.Solid) { startPoint = new Point(0, 0); endPoint = new Point(1, 0); if (xAxis != null && xAxis.Scale != null && xAxis.Scale.Reversed) { ChartHelper.Swap(ref startPoint, ref endPoint); } } else { startPoint = new Point(0, 1); endPoint = new Point(0, 0); if (yAxis != null && yAxis.Scale != null && yAxis.Scale.Reversed) { ChartHelper.Swap(ref startPoint, ref endPoint); } } // Get brush for fill and stroke. if (FillPalette != null && FillPalette.Count > 0) { fill = new LinearGradientBrush { GradientStops = FillPalette.GetGradient(lower, higher), StartPoint = startPoint, EndPoint = endPoint, ColorInterpolationMode = FillPalette.ColorInterpolationMode }; } if (StrokePalette != null && StrokePalette.Count > 0) { stroke = new LinearGradientBrush { GradientStops = StrokePalette.GetGradient(lower, higher), StartPoint = startPoint, EndPoint = endPoint, ColorInterpolationMode = StrokePalette.ColorInterpolationMode }; } }
protected virtual void OnGetStrokeAndFillForSegment(int index, out Brush stroke, out Brush fill) { Axis xAxis = XAxis; Axis yAxis = YAxis; // Check coloring parameters. if (PaletteIndex == PaletteIndex.Index && FillMode == AreaFillMode.GradientVertical || PaletteIndex == PaletteIndex.XValue && FillMode == AreaFillMode.GradientVertical) { throw new NotSupportedException("Vertical gradients are only supported if the palette is indexed by y values."); } // Find palette index. double paletteIndex = 0; switch (PaletteIndex) { case PaletteIndex.Index: paletteIndex = index; break; case PaletteIndex.XValue: paletteIndex = Data[index].X; break; case PaletteIndex.YValue: paletteIndex = Data[index].Y; break; default: throw new NotSupportedException("PaletteIndex type is not supported."); } // Set default values for stroke and fill brush. stroke = null; fill = null; // Try to find colors in palette. if (FillMode == AreaFillMode.Solid) { // Solid: // Get a solid color fill for fill and stroke. if (FillPalette != null && FillPalette.Count > 0) { fill = new SolidColorBrush(FillPalette.GetColor(paletteIndex)); } if (StrokePalette != null && StrokePalette.Count > 0) { stroke = new SolidColorBrush(StrokePalette.GetColor(paletteIndex)); } } else { // Get data values. DataPoint data = Data[index]; DataPoint dataBase = new DataPoint(data.X, 0, null); // The base is currently always y = 0. DataPoint previousData = (index > 0) ? Data[index - 1] : data; DataPoint previousDataBase = new DataPoint(previousData.X, 0, null); // The base is currently always y = 0. DataPoint nextData = (index < Data.Count - 1) ? Data[index + 1] : data; DataPoint nextDataBase = new DataPoint(nextData.X, 0, null); // The base is currently always y = 0. // Gradient: double fillStart; double fillEnd; double strokeStart; double strokeEnd; // Define palette index values. ChartInterpolation interpolation = EffectiveInterpolation; if (PaletteIndex == PaletteIndex.Index) { // Index-based if (interpolation == ChartInterpolation.CenteredSteps) { fillStart = strokeStart = Math.Max(index - 0.5, 0); fillEnd = strokeEnd = Math.Min(index + 0.5, Data.Count - 1); } else if (interpolation == ChartInterpolation.LeftSteps) { fillStart = strokeStart = Math.Max(index - 1, 0); fillEnd = strokeEnd = index; } else { fillStart = strokeStart = index; fillEnd = strokeEnd = index + 1; } } else if (PaletteIndex == PaletteIndex.XValue) { // x value based if (interpolation == ChartInterpolation.CenteredSteps) { fillStart = strokeStart = (previousData.X + data.X) / 2; fillEnd = strokeEnd = (data.X + nextData.X) / 2; } else if (interpolation == ChartInterpolation.LeftSteps) { fillStart = strokeStart = previousData.X; fillEnd = strokeEnd = data.X; } else { fillStart = strokeStart = data.X; fillEnd = strokeEnd = nextData.X; } } else { // y value based if (FillMode == AreaFillMode.GradientHorizontal) { if (interpolation == ChartInterpolation.CenteredSteps) { fillStart = strokeStart = (previousData.Y + data.Y) / 2; fillEnd = strokeEnd = (data.Y + nextData.Y) / 2; } else if (interpolation == ChartInterpolation.LeftSteps) { fillStart = strokeStart = previousData.Y; fillEnd = strokeEnd = data.Y; } else { fillStart = strokeStart = data.Y; fillEnd = strokeEnd = nextData.Y; } } else { fillStart = Math.Min(0, Math.Min(data.Y, dataBase.Y)); fillEnd = Math.Max(0, Math.Max(data.Y, dataBase.Y)); if (interpolation == ChartInterpolation.Linear) { fillStart = Math.Min(fillStart, Math.Min(nextData.Y, nextDataBase.Y)); fillEnd = Math.Max(fillEnd, Math.Max(nextData.Y, nextDataBase.Y)); } // This is the only case where the stroke has a different start and end value than the fill. // (Because the fill starts at y=0, but the line starts at the data point.) strokeStart = data.Y; strokeEnd = nextData.Y; if (strokeStart > strokeEnd) { ChartHelper.Swap(ref strokeStart, ref strokeEnd); } } } // Define gradient direction. Point startPoint; Point endPoint; if (PaletteIndex == PaletteIndex.Index || PaletteIndex == PaletteIndex.XValue || FillMode == AreaFillMode.GradientHorizontal) { startPoint = new Point(0, 0); endPoint = new Point(1, 0); if (xAxis != null && xAxis.Scale != null && xAxis.Scale.Reversed) { ChartHelper.Swap(ref startPoint, ref endPoint); } } else { startPoint = new Point(0, 1); endPoint = new Point(0, 0); if (yAxis != null && yAxis.Scale != null && yAxis.Scale.Reversed) { ChartHelper.Swap(ref startPoint, ref endPoint); } } // Get brush for fill and stroke. if (FillPalette != null && FillPalette.Count > 0) { fill = new LinearGradientBrush { GradientStops = FillPalette.GetGradient(fillStart, fillEnd), StartPoint = startPoint, EndPoint = endPoint, ColorInterpolationMode = FillPalette.ColorInterpolationMode }; } if (StrokePalette != null && StrokePalette.Count > 0) { stroke = new LinearGradientBrush { GradientStops = StrokePalette.GetGradient(strokeStart, strokeEnd), StartPoint = startPoint, EndPoint = endPoint, ColorInterpolationMode = StrokePalette.ColorInterpolationMode }; } } }