public AreaRenderContext(AreaRendererBase renderer) { ChartSeries series = renderer.model.presenter as ChartSeries; this.StrokeThickness = renderer.strokeShape.Stroke == null ? 0 : renderer.strokeShape.StrokeThickness; this.StrokeThicknessOffset = (int)(this.StrokeThickness / 2); this.PreviousStackedPoints = series.chart.StackedSeriesContext.PreviousStackedArea; this.IsStacked = this.PreviousStackedPoints != null && this.PreviousStackedPoints.Count > 0; this.PlotArea = renderer.model.GetChartArea().PlotArea.layoutSlot; this.PlotArea.Width *= series.chart.zoomCache.Width; this.PlotArea.Height *= series.chart.zoomCache.Height; // calculate the plot line - consider plot origin double plotOrigin = renderer.model.GetTypedValue <double>(AxisModel.PlotOriginPropertyKey, 0d); this.PlotDirection = renderer.model.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); if (this.PlotDirection == AxisPlotDirection.Vertical) { this.PlotLine = this.PlotArea.Bottom - (int)((plotOrigin * this.PlotArea.Height) + 0.5); } else { this.PlotLine = this.PlotArea.X + (int)((plotOrigin * this.PlotArea.Width) + 0.5); } // if PlotDirection is Verticel, check the IsInverse property for the Horizontal axis and vice versa this.IsPlotInverse = renderer.model.GetIsPlotInverse(this.PlotDirection ^ AxisPlotDirection.Horizontal); }
protected override IEnumerable <Point> GetPoints(DataPointSegment segment) { AxisPlotDirection plotDirection = this.model.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); ReferenceDictionary <string, Delegate> valueExtractor = plotDirection == AxisPlotDirection.Vertical ? VerticalPlotValueExtractors : HorizontalPlotValueExtractors; foreach (Point point in StepSeriesHelper.GetPoints(segment, this.model as StepSeriesModel, this.renderPoints, valueExtractor)) { yield return(point); } }
internal override RadRect ArrangeOverride(RadRect plotAreaRect) { AxisPlotDirection plotDirection = this.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); if (plotDirection == AxisPlotDirection.Horizontal) { throw new NotSupportedException("Horizontal OHLC series are not supported."); } LinearAxisModel axisModel = this.firstAxis as LinearAxisModel; if (axisModel == null) { axisModel = this.secondAxis as LinearAxisModel; } if (axisModel != null && axisModel.IsInverse) { throw new NotSupportedException("Ohlc and Candlestick series do not support inverse numerical axis. Set the IsInverse property of the numerical axis to false."); } plotAreaRect = this.GetZoomedRect(plotAreaRect); double x = double.NaN, y = double.NaN; double width = 0, height = 0; foreach (OhlcDataPoint point in this.DataPoints) { if (point.categoricalPlot == null) { continue; } x = plotAreaRect.X + ((point.categoricalPlot.Position - point.categoricalPlot.Length / 2) * plotAreaRect.Width); width = point.categoricalPlot.Length * plotAreaRect.Width; if (point.numericalPlot != null) { height = Math.Abs(point.numericalPlot.NormalizedHigh - point.numericalPlot.NormalizedLow) * plotAreaRect.Height; y = plotAreaRect.Y + ((1 - point.numericalPlot.NormalizedHigh) * plotAreaRect.Height); // NOTE: We need to calculate pixel values here so we can later round the inner open/close elements. point.numericalPlot.PhysicalOpen = (int)((1 - point.numericalPlot.RelativeOpen) * height); point.numericalPlot.PhysicalClose = (int)((1 - point.numericalPlot.RelativeClose) * height); } point.Arrange(new RadRect(x, y, width, height)); x = double.NaN; y = double.NaN; width = 0; height = 0; } return(plotAreaRect); }
internal override void ApplyLayoutRounding() { RangeSeriesRoundLayoutContext info = new RangeSeriesRoundLayoutContext(this); double gapLength = CategoricalAxisModel.DefaultGapLength; ISupportGapLength axisModel = this.firstAxis as ISupportGapLength; if (axisModel == null) { axisModel = this.secondAxis as ISupportGapLength; } if (axisModel != null) { gapLength = axisModel.GapLength; } int count = this.DataPointsInternal.Count; AxisPlotDirection plotDirection = this.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); Dictionary <double, double> normalizedValueToY = new Dictionary <double, double>(); Dictionary <double, double> normalizedValueToX = new Dictionary <double, double>(); foreach (RangeDataPoint point in this.DataPointsInternal) { if (point.isEmpty) { continue; } info.SnapPointToGridLine(point); // Handles specific scenario where range bar items from non-combined series have the same high/low value (floating point number) i.e. // the presenters should be rendered on the same horizontal/vertical pixel row/column. if (plotDirection == AxisPlotDirection.Vertical) { RangeSeriesRoundLayoutContext.SnapNormalizedValueToPreviousY(point, normalizedValueToY); } else { RangeSeriesRoundLayoutContext.SnapNormalizedValueToPreviousX(point, normalizedValueToX); } if (gapLength == 0 && point.CollectionIndex < count - 1) { DataPoint nextPoint = this.DataPointsInternal[point.CollectionIndex + 1]; info.SnapToAdjacentPointInHistogramScenario(point, nextPoint); } } }
private void BuildCategories(AxisUpdateContext context) { if (context.Series == null) { return; } bool autoGroup = this.AutoGroup; Dictionary <object, AxisCategory> categoriesByKey = new Dictionary <object, AxisCategory>(8); AxisPlotDirection direction = this.type == AxisType.First ? AxisPlotDirection.Vertical : AxisPlotDirection.Horizontal; foreach (ChartSeriesModel series in context.Series) { // tell each series what is the plot direction series.SetValue(AxisModel.PlotDirectionPropertyKey, direction); if (!series.presenter.IsVisible) { continue; } foreach (DataPoint point in series.DataPointsInternal) { object value = this.GetCategoryValue(point); object categoryKey = this.GetCategoryKey(point, value); if (categoryKey == null) { continue; } AxisCategory category; if (autoGroup) { if (!categoriesByKey.TryGetValue(categoryKey, out category)) { category = this.CreateCategory(categoryKey, value); categoriesByKey[categoryKey] = category; } } else { category = this.CreateCategory(categoryKey, value); } category.Points.Add(point); } } }
public RangeSeriesRoundLayoutContext(RangeSeriesModel series) { CartesianChartAreaModel cartesianChartArea = series.GetChartArea() as CartesianChartAreaModel; if (cartesianChartArea == null) { Debug.Assert(false, "Invalid chart area."); return; } this.PlotDirection = series.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); this.PlotOrigin = series.GetTypedValue <double>(AxisModel.PlotOriginPropertyKey, 0d); this.PlotArea = cartesianChartArea.plotArea.layoutSlot; this.PlotArea.Width = (int)((this.PlotArea.Width * cartesianChartArea.view.ZoomWidth) + .5); this.PlotArea.Height = (int)((this.PlotArea.Height * cartesianChartArea.view.ZoomHeight) + .5); if (this.PlotDirection == AxisPlotDirection.Vertical) { if (this.PlotOrigin == 0) { this.PlotLine = this.PlotArea.Bottom; } else if (this.PlotOrigin == 1) { this.PlotLine = this.PlotArea.Y; } else { double roundError = (series.SecondAxis.majorTickCount % 2) == 0 ? 0.5 : 0; this.PlotLine = this.PlotArea.Bottom - (int)((this.PlotOrigin * this.PlotArea.Height) + roundError); } } else { if (this.PlotOrigin == 0) { this.PlotLine = this.PlotArea.X; } else if (this.PlotOrigin == 1) { this.PlotLine = this.PlotArea.Right; } else { double roundError = (series.FirstAxis.majorTickCount % 2) != 0 ? 0.5 : 0; this.PlotLine = this.PlotArea.X + (int)((this.PlotOrigin * this.PlotArea.Width) + roundError); } } }
protected override IEnumerable <Windows.Foundation.Point> GetTopPoints(DataPointSegment segment) { AxisPlotDirection plotDirection = this.model.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); ReferenceDictionary <string, Delegate> valueExtractor = plotDirection == AxisPlotDirection.Vertical ? VerticalRangePlotValueExtractors : HorizontalRangePlotValueExtractors; Func <DataPoint, Point> topPointGetter = (Func <DataPoint, Point>)valueExtractor[TopPointGetter]; int pointIndex = segment.StartIndex; while (pointIndex <= segment.EndIndex) { var currentPoint = this.renderPoints[pointIndex]; yield return(topPointGetter(currentPoint)); pointIndex++; } }
internal override RadRect ArrangeOverride(RadRect plotAreaRect) { plotAreaRect = this.GetZoomedRect(plotAreaRect); double x = double.NaN, y = double.NaN; double width = 0, height = 0; AxisPlotDirection plotDirection = this.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); foreach (CategoricalDataPoint point in this.DataPoints) { if (point.categoricalPlot == null) { continue; } if (plotDirection == AxisPlotDirection.Vertical) { // vertical bars x = plotAreaRect.X + ((point.categoricalPlot.Position - point.categoricalPlot.Length / 2) * plotAreaRect.Width); width = point.categoricalPlot.Length * plotAreaRect.Width; if (point.numericalPlot != null) { height = Math.Abs(point.numericalPlot.NormalizedValue - point.numericalPlot.PlotOriginOffset) * plotAreaRect.Height; y = plotAreaRect.Y + ((1 - Math.Max(point.numericalPlot.NormalizedValue, point.numericalPlot.PlotOriginOffset)) * plotAreaRect.Height); } } else { // horizontal bars if (point.numericalPlot != null) { x = plotAreaRect.X + (Math.Min(point.numericalPlot.NormalizedValue, point.numericalPlot.PlotOriginOffset) * plotAreaRect.Width); width = Math.Abs(point.numericalPlot.NormalizedValue - point.numericalPlot.PlotOriginOffset) * plotAreaRect.Width; } height = point.categoricalPlot.Length * plotAreaRect.Height; y = plotAreaRect.Bottom - (((point.categoricalPlot.Position - point.categoricalPlot.Length / 2) * plotAreaRect.Height) + height); } point.Arrange(new RadRect(x, y, width, height)); x = double.NaN; y = double.NaN; width = 0; height = 0; } return(plotAreaRect); }
internal static IEnumerable <Point> GetPoints(DataPointSegment segment, StepSeriesModel seriesModel, IList <DataPoint> renderPoints, ReferenceDictionary <string, Delegate> valueExtractor) { AxisPlotDirection plotDirection = seriesModel.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); AxisModel axisModel = plotDirection == AxisPlotDirection.Vertical ? seriesModel.firstAxis : seriesModel.secondAxis; var risersActualPosition = StepSeriesHelper.GetActualRisersPosition(seriesModel.RisersPosition, axisModel.ActualPlotMode); var isRisersPositionEqualToPlotMode = StepSeriesHelper.IsRisersPositionEqualToPlotMode(axisModel.ActualPlotMode, risersActualPosition); var view = seriesModel.GetChartArea().view; Size chartScale = new Size(view.ZoomWidth, view.ZoomHeight); double slotLength = StepSeriesHelper.GetSlotLength(seriesModel, plotDirection, chartScale); double halfSlotLength = slotLength / 2; Func <Point, Point, Point> riserPointGetter = (Func <Point, Point, Point>)valueExtractor[RiserPointGetter]; Func <Point, Point, double, Point> firstRiserPointGetter = (Func <Point, Point, double, Point>)valueExtractor[FirstRiserPointGetter]; Func <Point, Point, double, Point> secondRiserPointGetter = (Func <Point, Point, double, Point>)valueExtractor[SecondRiserPointGetter]; int pointIndex = segment.StartIndex; while (pointIndex <= segment.EndIndex) { var currentPoint = renderPoints[pointIndex].Center(); yield return(currentPoint); if (pointIndex == segment.EndIndex) { yield break; } var nextPoint = renderPoints[pointIndex + 1].Center(); if (isRisersPositionEqualToPlotMode || axisModel is DateTimeContinuousAxisModel) { yield return(riserPointGetter(currentPoint, nextPoint)); } else { yield return(firstRiserPointGetter(currentPoint, nextPoint, halfSlotLength)); yield return(secondRiserPointGetter(currentPoint, nextPoint, halfSlotLength)); } pointIndex++; } }
private static ChartSeriesLabelDefinition CreateDefaultLabelDefinition(AxisPlotDirection plotDirection) { if (plotDirection == AxisPlotDirection.Horizontal) { return(new ChartSeriesLabelDefinition() { Margin = new Thickness(10, 0, 0, 0), HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Center }); } return(new ChartSeriesLabelDefinition() { Margin = new Thickness(0, 0, 0, 10), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top }); }
protected override IList <Point> GetBottomPoints(AreaRenderContext context) { AxisPlotDirection plotDirection = this.model.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); ReferenceDictionary <string, Delegate> valueExtractor = plotDirection == AxisPlotDirection.Vertical ? VerticalRangePlotValueExtractors : HorizontalRangePlotValueExtractors; Func <DataPoint, Point> bottomPointGetter = (Func <DataPoint, Point>)valueExtractor[BottomPointGetter]; DataPointSegment currentSegment = context.CurrentSegment; List <Point> points = new List <Point>(); int pointIndex = currentSegment.StartIndex; while (pointIndex <= currentSegment.EndIndex) { var currentPoint = this.renderPoints[pointIndex]; points.Add(bottomPointGetter(currentPoint)); pointIndex++; } return(points); }
private void BuildValues(AxisUpdateContext context) { this.values.Clear(); if (context.Series == null) { return; } AxisPlotDirection direction = this.type == AxisType.First ? AxisPlotDirection.Vertical : AxisPlotDirection.Horizontal; foreach (ChartSeriesModel series in context.Series) { // tell each series what is the plot direction series.SetValue(AxisModel.PlotDirectionPropertyKey, direction); if (!series.presenter.IsVisible) { continue; } foreach (DataPoint point in series.DataPointsInternal) { object value = point.GetValueForAxis(this); DateTime date; if (!DateTimeHelper.TryGetDateTime(value, out date)) { continue; } DateTimePoint datePoint = new DateTimePoint() { Point = point, Date = date }; this.values.Add(datePoint); } } // sort all the values chronologically this.values.Sort(); }
internal virtual double GetDistanceToPoint(DataPoint dataPoint, Point tapLocation, ChartPointDistanceCalculationMode pointDistanceMode) { var dataPointLocation = dataPoint.Center(); if (pointDistanceMode == ChartPointDistanceCalculationMode.TwoDimensional) { ////TODO: Math.Sqrt could lead to potential performance issues with lost of points/series. return(RadMath.GetPointDistance(dataPointLocation.X, tapLocation.X, dataPointLocation.Y, tapLocation.Y)); } else { AxisPlotDirection plotDirection = this.Model.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); if (plotDirection == AxisPlotDirection.Vertical) { return(Math.Abs(tapLocation.X - dataPointLocation.X)); } else { return(Math.Abs(tapLocation.Y - dataPointLocation.Y)); } } }
internal override bool GetIsPlotInverse(AxisPlotDirection plotDirection) { var axisModel = ((plotDirection & AxisPlotDirection.Horizontal) == AxisPlotDirection.Horizontal) ? this.FirstAxis : this.SecondAxis; return(axisModel != null ? axisModel.IsInverse : false); }
internal static double GetSlotLength(CategoricalStrokedSeriesModel stepLineSeriesModel, AxisPlotDirection plotDirection, Size chartScale) { double slotLength; int slotsCount; AxisModel axisModel = plotDirection == AxisPlotDirection.Vertical ? stepLineSeriesModel.firstAxis : stepLineSeriesModel.secondAxis; double axisLength = plotDirection == AxisPlotDirection.Vertical ? axisModel.layoutSlot.Width : axisModel.layoutSlot.Height; double zoomScale = plotDirection == AxisPlotDirection.Vertical ? chartScale.Width : chartScale.Height; axisLength = axisLength * zoomScale; DateTimeContinuousAxisModel dateTimeContinuousAxisModel = axisModel as DateTimeContinuousAxisModel; if (dateTimeContinuousAxisModel != null) { return(0); } CategoricalAxisModel categoricalAxisModel = (CategoricalAxisModel)axisModel; slotsCount = categoricalAxisModel.ActualPlotMode == AxisPlotMode.OnTicks ? categoricalAxisModel.categories.Count - 1 : categoricalAxisModel.categories.Count; slotsCount = slotsCount * categoricalAxisModel.GetMajorTickInterval(); slotsCount = Math.Max(1, slotsCount); slotLength = axisLength / slotsCount; return(slotLength); }
internal override RadRect ArrangeOverride(RadRect rect) { RadRect zoomedRect = this.GetZoomedRect(rect); bool zoomed = zoomedRect != rect; this.renderablePoints.Clear(); double x = double.NaN, y = double.NaN; AxisPlotDirection plotDirection = this.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); RadRect plotRect = this.GetChartArea().view.PlotAreaClip; DataPoint prevPoint = null; foreach (CategoricalDataPoint point in this.DataPoints) { if (point.categoricalPlot == null) { continue; } if (plotDirection == AxisPlotDirection.Vertical) { x = point.categoricalPlot.CenterX(zoomedRect); if (point.numericalPlot != null) { y = point.numericalPlot.CenterY(zoomedRect); } // points are sorted along the horizontal axis and renderable points are all the points, falling within the X-range of the plot area clip if (zoomed && (x >= plotRect.X && x <= plotRect.Right)) { if (prevPoint != null && this.renderablePoints.Count == 0) { this.renderablePoints.Add(prevPoint); } this.renderablePoints.Add(point); } } else { if (point.numericalPlot != null) { x = point.numericalPlot.CenterX(zoomedRect); } y = point.categoricalPlot.CenterY(zoomedRect); // points are sorted along the vertical axis and renderable points are all the points, falling within the Y-range of the plot area clip if (zoomed && (y >= plotRect.Y && y <= plotRect.Bottom)) { if (prevPoint != null && this.renderablePoints.Count == 0) { this.renderablePoints.Add(prevPoint); } this.renderablePoints.Add(point); } } RadSize pointSize = point.Measure(); point.Arrange(new RadRect(x - (pointSize.Width / 2), y - (pointSize.Height / 2), pointSize.Width, pointSize.Height), false); prevPoint = point; x = double.NaN; y = double.NaN; } // add the point after the last renderable point if (this.renderablePoints.Count > 0) { int lastIndex = this.renderablePoints[this.renderablePoints.Count - 1].Index; if (lastIndex < this.DataPoints.Count - 1) { this.renderablePoints.Add(this.DataPoints[lastIndex + 1]); } } return(zoomedRect); }
internal override RadRect ArrangeOverride(RadRect plotAreaRect) { LinearAxisModel numericalAxis = this.firstAxis as LinearAxisModel; if (numericalAxis == null) { numericalAxis = this.secondAxis as LinearAxisModel; } if (numericalAxis != null && numericalAxis.IsInverse) { throw new NotSupportedException("Range series do not support inverse numerical axis. Set the IsInverse property of the numerical axis to false."); } RadRect zoomedRect = this.GetZoomedRect(plotAreaRect); bool zoomed = zoomedRect != plotAreaRect; this.renderablePoints.Clear(); double normalizedLow = double.NaN, normalizedHigh = double.NaN; double x = double.NaN, y = double.NaN; double width = 0, height = 0; AxisPlotDirection plotDirection = this.GetTypedValue <AxisPlotDirection>(AxisModel.PlotDirectionPropertyKey, AxisPlotDirection.Vertical); RadRect plotRect = this.GetChartArea().view.PlotAreaClip; DataPoint prevPoint = null; foreach (RangeDataPoint point in this.DataPoints) { if (point.categoricalPlot == null) { continue; } if (plotDirection == AxisPlotDirection.Vertical) { if (point.numericalPlot != null) { normalizedLow = Math.Min(point.numericalPlot.NormalizedLow, point.numericalPlot.NormalizedHigh); normalizedHigh = Math.Max(point.numericalPlot.NormalizedLow, point.numericalPlot.NormalizedHigh); y = plotAreaRect.Y + ((1 - normalizedHigh) * zoomedRect.Height); height = (normalizedHigh - normalizedLow) * zoomedRect.Height; } width = point.categoricalPlot.Length * zoomedRect.Width; x = zoomedRect.X + ((point.categoricalPlot.Position - point.categoricalPlot.Length / 2) * zoomedRect.Width); // points are sorted along the horizontal axis and renderable points are all the points, falling within the X-range of the plot area clip if (zoomed && (x >= plotRect.X && x <= plotRect.Right)) { if (prevPoint != null && this.renderablePoints.Count == 0) { this.renderablePoints.Add(prevPoint); } this.renderablePoints.Add(point); } } else { if (point.numericalPlot != null) { normalizedLow = Math.Min(point.numericalPlot.NormalizedLow, point.numericalPlot.NormalizedHigh); normalizedHigh = Math.Max(point.numericalPlot.NormalizedLow, point.numericalPlot.NormalizedHigh); x = plotAreaRect.X + (normalizedLow * zoomedRect.Width); width = (normalizedHigh - normalizedLow) * zoomedRect.Width; } height = point.categoricalPlot.Length * zoomedRect.Height; y = plotAreaRect.Bottom - (((point.categoricalPlot.Position - point.categoricalPlot.Length / 2) * zoomedRect.Height) + height); // points are sorted along the vertical axis and renderable points are all the points, falling within the Y-range of the plot area clip if (zoomed && (y >= plotRect.Y && y <= plotRect.Bottom)) { if (prevPoint != null && this.renderablePoints.Count == 0) { this.renderablePoints.Add(prevPoint); } this.renderablePoints.Add(point); } } RadSize pointSize = point.Measure(); point.Arrange(new RadRect(x, y, width, height), this.ShouldRoundLayout); prevPoint = point; normalizedLow = double.NaN; normalizedHigh = double.NaN; x = double.NaN; y = double.NaN; width = 0; height = 0; } // add the point after the last renderable point if (this.renderablePoints.Count > 0) { int lastIndex = this.renderablePoints[this.renderablePoints.Count - 1].Index; if (lastIndex < this.DataPoints.Count - 1) { this.renderablePoints.Add(this.DataPoints[lastIndex + 1]); } } return(zoomedRect); }
internal virtual bool GetIsPlotInverse(AxisPlotDirection plotDirection) { return(false); }