Beispiel #1
0
        /// <summary>
        /// Raises the <see cref="ChartElement.Updated"/> event.
        /// </summary>
        /// <remarks>
        /// <strong>Notes to Inheritors:</strong> When overriding <see cref="OnUpdate"/> in a
        /// derived class, be sure to call the base class's <see cref="OnUpdate"/> method so that
        /// registered delegates receive the event.
        /// </remarks>
        protected override void OnUpdate()
        {
            double xValue = X;

            if (Numeric.IsFinite(xValue))
            {
                Axis      xAxis     = XAxis;
                Axis      yAxis     = YAxis;
                AxisScale xScale    = xAxis.Scale;
                AxisScale yScale    = yAxis.Scale;
                double    yMin      = yAxis.GetPosition(yScale.Min);
                double    yMax      = yAxis.GetPosition(yScale.Max);
                double    xPosition = xAxis.GetPosition(xValue);

                if (_line != null)
                {
                    _line.X1         = xPosition;
                    _line.X2         = xPosition;
                    _line.Y1         = yMin;
                    _line.Y2         = yMax;
                    _line.Visibility = (xScale.Min <= xValue && xValue <= xScale.Max)
                                       ? Visibility.Visible
                                       : Visibility.Collapsed;
                }
            }
            else
            {
                if (_line != null)
                {
                    _line.Visibility = Visibility.Collapsed;
                }
            }

            base.OnUpdate();
        }
Beispiel #2
0
        private static IList <TextLabel> GetLabels(Axis axis)
        {
            AxisScale         scale     = axis.Scale;
            IList <TextLabel> labels    = null;
            TextScale         textScale = scale as TextScale;

            if (textScale != null)
            {
                labels = (textScale).Labels;
            }

            return(labels);
        }
Beispiel #3
0
        private static void EnsureScaleIncludesZero(AxisScale scale)
        {
            double min = scale.Min;
            double max = scale.Max;

            if (min > 0 && max > 0)
            {
                scale.Range = new DoubleRange(0, max);
            }
            else if (min < 0 && max < 0)
            {
                scale.Range = new DoubleRange(min, 0);
            }
        }
Beispiel #4
0
        private void UpdateMinorGridLines()
        {
            Axis xAxis = XAxis;
            Axis yAxis = YAxis;

            if (xAxis != null && yAxis != null)
            {
                AxisScale xScale = xAxis.Scale;
                AxisScale yScale = yAxis.Scale;
                if (xScale != null && yScale != null)
                {
                    double xMin = xAxis.GetPosition(xScale.Min);
                    double xMax = xAxis.GetPosition(xScale.Max);
                    double yMin = yAxis.GetPosition(yScale.Min);
                    double yMax = yAxis.GetPosition(yScale.Max);

                    // Add vertical minor lines
                    if (_verticalMinorLinesRenderer != null && VerticalMinorLineStyle != null)
                    {
                        using (var renderContext = _verticalMinorLinesRenderer.Open())
                        {
                            for (int i = 0; i < xAxis.MinorTicks.Length; ++i)
                            {
                                double x = xAxis.GetPosition(xAxis.MinorTicks[i]);
                                renderContext.DrawLine(new Point(x, yMin), new Point(x, yMax));
                            }
                        }
                    }

                    // Add horizontal minor lines
                    if (_horizontalMinorLinesRenderer != null && HorizontalMinorLineStyle != null)
                    {
                        using (var renderContext = _horizontalMinorLinesRenderer.Open())
                        {
                            for (int i = 0; i < yAxis.MinorTicks.Length; ++i)
                            {
                                double y = yAxis.GetPosition(yAxis.MinorTicks[i]);
                                renderContext.DrawLine(new Point(xMin, y), new Point(xMax, y));
                            }
                        }
                    }
                }
            }
        }
Beispiel #5
0
        /// <inheritdoc/>
        protected override AxisScale OnSuggestYScale()
        {
            if (Data == null || Data.Count == 0)
            {
                return(null);
            }

            if (EffectiveOrientation == Orientation.Vertical)
            {
                // Make sure that scale contains 0.
                AxisScale scale = base.OnSuggestYScale();
                EnsureScaleIncludesZero(scale);
                return(scale);
            }
            else
            {
                return(SuggestBaseScale());
            }
        }
Beispiel #6
0
        /// <summary>
        /// Sets the <see cref="Min"/> and <see cref="Max"/> properties to be just large enough to
        /// encompass the specified scale.
        /// </summary>
        /// <param name="scale">The scale.</param>
        public void Add(AxisScale scale)
        {
            if (scale == null)
            {
                return;
            }

            double min = Range.Min;
            double max = Range.Max;

            if (scale.Min < min)
            {
                min = scale.Min;
            }

            if (scale.Max > max)
            {
                max = scale.Max;
            }

            Range = new DoubleRange(min, max);
        }
Beispiel #7
0
        /// <summary>
        /// Called by <see cref="SuggestYScale"/> to suggest a scale for the y-axis
        /// </summary>
        /// <inheritdoc cref="SuggestYScale"/>
        protected virtual AxisScale OnSuggestYScale()
        {
            AxisScale scale = null;

            foreach (var chart in Charts)
            {
                var suggestedScale = chart.SuggestYScale();
                if (suggestedScale != null)
                {
                    if (scale == null)
                    {
                        scale = suggestedScale;
                    }
                    else
                    {
                        scale.Add(suggestedScale);
                    }
                }
            }

            return(scale);
        }
Beispiel #8
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);
            }
        }
Beispiel #9
0
        private void OnScaleChanged(AxisScale scale)
        {
            // Unsubscribe from previous scale.
            if (_scaleSubscription != null)
            {
                _scaleSubscription.Dispose();
                _scaleSubscription = null;
            }

            // Subscribe to scale using weak event pattern.
            if (scale != null)
            {
                _scaleSubscription =
                    WeakEventHandler<PropertyChangedEventHandler, PropertyChangedEventArgs>.Register(
                        scale,
                        this,
                        handler => new PropertyChangedEventHandler(handler),
                        (sender, handler) => sender.PropertyChanged += handler,
                        (sender, handler) => sender.PropertyChanged -= handler,
                        (listener, sender, eventArgs) => listener.Invalidate());
            }

            Invalidate();
        }
Beispiel #10
0
        /// <summary>
        /// Updates (recalculates) the axis.
        /// </summary>
        /// <param name="constraintSize">The size constraint.</param>
        private void Update(Size constraintSize)
        {
            if (_isValid)
                return;

            ApplyTemplate();

            if (AutoScale)
                AutoGenerateScale();

            // Cache values of dependency properties for performance.
            _isXAxis = (Orientation == Orientation.Horizontal);
            _scale = Scale;
            _originX = OriginX;
            _originY = OriginY;
            _length = Length;
            _startPosition = GetComponent(new Point(_originX, _originY));
            _endPosition = _isXAxis ? (_startPosition + _length) : (_startPosition - _length);


            if (!Numeric.IsZeroOrPositiveFinite(_length)
                || !Numeric.IsZeroOrPositiveFinite(_originX)
                || !Numeric.IsZeroOrPositiveFinite(_originY)
                || _scale == null)
            {
                // Invalid values.
                // (Set IsValid to true. IsValid will be automatically cleared when a property changes.)
                _isValid = true;
                return;
            }

            // Compute tick values.
            double[] labelValues, majorTicks, minorTicks;
            _scale.ComputeTicks(_length, MinTickDistance, out labelValues, out majorTicks, out minorTicks);
            LabelValues = labelValues;
            MajorTicks = majorTicks;
            MinorTicks = minorTicks;
            _isValid = true;

            double perpendicularLength = 0;
            if (_canvas != null && Visibility != Visibility.Collapsed)
            {
                // Add child elements to canvas.
                UpdateAxis();
                UpdateTicks(constraintSize);
                UpdateTitle();

                // Update invisible rectangle which is used for hit testing.
                _hitRectangle.Width = _hitRectangleBounds.Width;
                _hitRectangle.Height = _hitRectangleBounds.Height;
                Canvas.SetLeft(_hitRectangle, _hitRectangleBounds.Left);
                Canvas.SetTop(_hitRectangle, _hitRectangleBounds.Top);

                // ----- Compute the optimal size.
                // In the axis direction the ideal size is the axis length.
                // In the other direction the ideal size depends on the tick size, label size and offsets.

                // Length normal (perpendicular) to the axis.
                perpendicularLength = _titleSize.Height + _effectiveTitleOffset;
                perpendicularLength = Math.Max(perpendicularLength, 0);
            }

            // Compute optimal size
            OptimalSize = (IsXAxis) ? new Size(_length, perpendicularLength)
                                    : new Size(perpendicularLength, _length);

            OnUpdate();
        }
Beispiel #11
0
        /// <summary>
        /// Sets the <see cref="Min"/> and <see cref="Max"/> properties to be just large enough to
        /// encompass the specified scale.
        /// </summary>
        /// <param name="scale">The scale.</param>
        public void Add(AxisScale scale)
        {
            if (scale == null)
                return;

            double min = Range.Min;
            double max = Range.Max;

            if (scale.Min < min)
                min = scale.Min;

            if (scale.Max > max)
                max = scale.Max;

            Range = new DoubleRange(min, max);
        }
Beispiel #12
0
 private static void EnsureScaleIncludesZero(AxisScale scale)
 {
     double min = scale.Min;
     double max = scale.Max;
     if (min > 0 && max > 0)
         scale.Range = new DoubleRange(0, max);
     else if (min < 0 && max < 0)
         scale.Range = new DoubleRange(min, 0);
 }