Example #1
0
        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
                    };
                }
            }
        }
Example #2
0
        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);
        }
Example #3
0
        /// <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)));
        }
Example #4
0
        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;
        }
Example #5
0
        /// <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
                    };
                }
            }
        }
Example #7
0
        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
                    };
                }
            }
        }