/// <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(); }
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); }
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); } }
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)); } } } } } }
/// <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()); } }
/// <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); }
/// <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); }
/// <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 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(); }
/// <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(); }
/// <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); }
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); }