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)); } } } } } }
protected virtual void OnUpdateLines(int startIndex, int endIndexExclusive, double[] xPositions, double[] basePositions, double[] yPositions) { if (Data.Count == 0) { return; } bool reversed = XAxis.Scale.Reversed; bool horizontalStepLineVisible = HorizontalStepLineVisible; bool verticalStepLineVisible = VerticalStepLineVisible; bool filled = Filled; var interpolation = EffectiveInterpolation; #if !SILVERLIGHT // Perform the large data optimization (see below) if the line chart contains vertical lines. bool largeDataOptimization = interpolation == ChartInterpolation.Linear || interpolation == ChartInterpolation.CenteredSteps && verticalStepLineVisible || interpolation == ChartInterpolation.LeftSteps && verticalStepLineVisible || interpolation == ChartInterpolation.RightSteps && verticalStepLineVisible; double pixelSize = WindowsHelper.GetPixelSize(this).Width; #endif using (var lineRenderContext = _lineRenderer.Open()) using (var areaRenderContext = _areaRenderer.Open()) { int numberOfDataPoints = Data.Count; // Lines are drawn from index i to i+1. startIndex = Math.Max(0, startIndex - 1); // For centered steps one additional data point needs to be rendered. if (interpolation == ChartInterpolation.CenteredSteps) { endIndexExclusive = Math.Min(numberOfDataPoints, endIndexExclusive + 1); } for (int i = startIndex; i < endIndexExclusive; i++) { if (Numeric.IsNaN(xPositions[i]) || Numeric.IsNaN(yPositions[i])) { continue; } #if !SILVERLIGHT if (largeDataOptimization) { // Draw a single vertical line for all data points that lie on the same pixel column. double xPixel = WindowsHelper.RoundToDevicePixelsCenter(xPositions[i], pixelSize); double yMin = yPositions[i]; double yMax = yPositions[i]; int overlap = 0; for (int j = i + 1; j < endIndexExclusive; j++) { // ReSharper disable once CompareOfFloatsByEqualityOperator if (Numeric.IsNaN(xPositions[j]) || Numeric.IsNaN(yPositions[j]) || xPixel != WindowsHelper.RoundToDevicePixelsCenter(xPositions[j], pixelSize)) { break; } overlap++; if (yPositions[j] < yMin) // Safe for NaN. { yMin = yPositions[j]; } else if (yPositions[j] > yMax) // Safe for NaN. { yMax = yPositions[j]; } } if (overlap > 1) { lineRenderContext.DrawLine(new Point(xPixel, yMin), new Point(xPixel, yMax)); // i ............. index of first point in overlap. // i + overlap ... index of last point in overlap. if (filled && !Numeric.IsNaN(basePositions[i]) && !Numeric.IsNaN(basePositions[i + overlap])) { areaRenderContext.DrawPolygon( new Point(xPositions[i], yMin), new Point(xPositions[i + overlap], yMin), new Point(xPositions[i + overlap], basePositions[i + overlap]), new Point(xPositions[i], basePositions[i])); } // Jump ahead to last point in overlap. i += overlap; if (Numeric.IsNaN(yPositions[i])) { continue; } } } #endif Point previousPoint; //, previousPointBase; Point point, pointBase; Point nextPoint, nextPointBase; if (i - 1 >= 0) { previousPoint = new Point(xPositions[i - 1], yPositions[i - 1]); //previousPointBase = new Point(xPositions[i - 1], basePositions[i - 1]); } else { previousPoint = new Point(double.NaN, double.NaN); //previousPointBase = new Point(double.NaN, double.NaN); } point = new Point(xPositions[i], yPositions[i]); pointBase = new Point(xPositions[i], basePositions[i]); if (i + 1 < numberOfDataPoints) { nextPoint = new Point(xPositions[i + 1], yPositions[i + 1]); nextPointBase = new Point(xPositions[i + 1], basePositions[i + 1]); } else { nextPoint = new Point(double.NaN, double.NaN); nextPointBase = new Point(double.NaN, double.NaN); } // Draw lines and area from i to i+1. if (interpolation == ChartInterpolation.Linear) { // Linear interpolation if (!Numeric.IsNaN(nextPoint.X) && !Numeric.IsNaN(nextPoint.Y)) { lineRenderContext.DrawLine(point, nextPoint); if (filled && !Numeric.IsNaN(pointBase.Y) && !Numeric.IsNaN(nextPointBase.Y)) { areaRenderContext.DrawPolygon( point, nextPoint, nextPointBase, pointBase); } } } else { if (interpolation == ChartInterpolation.CenteredSteps) { // Centered steps double centerBefore, centerAfter; GetCenteredStep(previousPoint, point, nextPoint, out centerBefore, out centerAfter); if (horizontalStepLineVisible) { lineRenderContext.DrawLine(new Point(centerBefore, point.Y), new Point(centerAfter, point.Y)); } if (verticalStepLineVisible && !Numeric.IsNaN(nextPoint.X) && !Numeric.IsNaN(nextPoint.Y)) { lineRenderContext.DrawLine(new Point(centerAfter, point.Y), new Point(centerAfter, nextPoint.Y)); } if (filled && !Numeric.IsNaN(pointBase.Y)) { areaRenderContext.DrawPolygon( new Point(centerBefore, point.Y), new Point(centerAfter, point.Y), new Point(centerAfter, pointBase.Y), new Point(centerBefore, pointBase.Y)); } } else { if (interpolation == ChartInterpolation.LeftSteps && !reversed || interpolation == ChartInterpolation.RightSteps && reversed) { // LeftSteps or Reversed RightSteps if (!Numeric.IsNaN(nextPoint.X) && !Numeric.IsNaN(nextPoint.Y)) { if (verticalStepLineVisible) { lineRenderContext.DrawLine(point, new Point(point.X, nextPoint.Y)); } if (horizontalStepLineVisible) { lineRenderContext.DrawLine(new Point(point.X, nextPoint.Y), nextPoint); } if (filled && !Numeric.IsNaN(nextPointBase.Y)) { areaRenderContext.DrawPolygon( new Point(point.X, nextPoint.Y), nextPoint, nextPointBase, new Point(point.X, nextPointBase.Y)); } } } else { // RightSteps or Reversed LeftSteps if (!Numeric.IsNaN(nextPoint.X) && !Numeric.IsNaN(nextPoint.Y)) { if (horizontalStepLineVisible) { lineRenderContext.DrawLine(point, new Point(nextPoint.X, point.Y)); } if (verticalStepLineVisible) { lineRenderContext.DrawLine(new Point(nextPoint.X, point.Y), nextPoint); } if (filled && !Numeric.IsNaN(pointBase.Y) && !Numeric.IsNaN(nextPointBase.Y)) { areaRenderContext.DrawPolygon( point, new Point(nextPoint.X, point.Y), new Point(nextPointBase.X, pointBase.Y), pointBase); } } } } } } } if (_linePath != null) { _linePath.Clip = LineClipGeometry; } if (_areaPath != null) { _areaPath.Clip = AreaClipGeometry; } // Bugfix: // Sometimes the first line of a Path is not drawn. // We need to explicitly call InvalidateMeasure() on the canvas. Canvas.InvalidateMeasure(); }