/// <summary> /// Return visual object for doughnut chart /// </summary> /// <param name="width">Width of the PlotArea</param> /// <param name="height">Height of the PlotArea</param> /// <param name="plotDetails">PlotDetails reference</param> /// <param name="seriesList">List of series list</param> /// <param name="chart">Chart reference</param> /// <param name="animationEnabled">Whether animation is enabled</param> /// <returns>Canvas</returns> internal static Canvas GetVisualObjectForDoughnutChart(Double widthOfPlotArea, Double height, PlotDetails plotDetails, List<DataSeries> seriesList, Chart chart, bool animationEnabled) { if (Double.IsNaN(widthOfPlotArea) || Double.IsNaN(height) || widthOfPlotArea <= 0 || height <= 0) return null; DataSeries currentDataSeries = null; Canvas visual = new Canvas(); visual.Width = widthOfPlotArea; visual.Height = height; DataSeries series = seriesList[0]; if (series.Enabled == false) return visual; // List<DataPoint> enabledDataPoints = (from datapoint in series.InternalDataPoints where datapoint.Enabled == true && datapoint.InternalYValue != 0 && !Double.IsNaN(datapoint.InternalYValue) select datapoint).ToList(); List<DataPoint> enabledDataPoints = (from datapoint in series.InternalDataPoints where datapoint.Enabled == true && !Double.IsNaN(datapoint.InternalYValue) select datapoint).ToList(); if ((from dp in enabledDataPoints select dp.InternalYValue).Sum() == 0) enabledDataPoints.Clear(); Double absoluteSum = plotDetails.GetAbsoluteSumOfDataPoints(enabledDataPoints); absoluteSum = (absoluteSum == 0) ? 1 : absoluteSum; Double centerX = widthOfPlotArea / 2; Double centerY = height / 2; Double offsetX = 0; Double offsetY = 0; Size pieCanvas = new Size(); Canvas labelCanvas = CreateAndPositionLabels(absoluteSum, enabledDataPoints, widthOfPlotArea, height, ((chart.View3D) ? 0.4 : 1), chart.View3D, ref pieCanvas); Double radius = Math.Min(pieCanvas.Width, pieCanvas.Height) / (chart.View3D ? 1 : 2); Double startAngle = series.InternalStartAngle; Double endAngle = 0; Double angle; Double meanAngle; Double absoluteYValue; Double radiusDiff = 0; var explodedDataPoints = (from datapoint in series.InternalDataPoints where datapoint.Exploded == true && datapoint.InternalYValue != 0 select datapoint); radiusDiff = (explodedDataPoints.Count() > 0) ? radius * 0.3 : 0; if (chart.View3D) { _elementPositionData = new List<ElementPositionData>(); } if (labelCanvas != null) { labelCanvas.SetValue(Canvas.ZIndexProperty, 50001); labelCanvas.IsHitTestVisible = false; } if (series.Storyboard == null) series.Storyboard = new Storyboard(); currentDataSeries = series; SectorChartShapeParams doughnutParams = null; Int32 labelStateCounter = 0; if (!chart.View3D) { foreach (DataPoint dataPoint in enabledDataPoints) { if (dataPoint.LabelStyle == LabelStyles.Inside || !(Boolean)dataPoint.LabelEnabled) labelStateCounter++; } } foreach (DataPoint dataPoint in enabledDataPoints) { if (Double.IsNaN(dataPoint.InternalYValue))// || dataPoint.InternalYValue == 0) continue; absoluteYValue = Math.Abs(dataPoint.InternalYValue); angle = (absoluteYValue / absoluteSum) * Math.PI * 2; endAngle = startAngle + angle; meanAngle = (startAngle + endAngle) / 2; doughnutParams = new SectorChartShapeParams(); dataPoint.VisualParams = doughnutParams; doughnutParams.AnimationEnabled = animationEnabled; doughnutParams.Storyboard = series.Storyboard; doughnutParams.ExplodeRatio = chart.View3D ? 0.2 : 0.1; doughnutParams.Center = new Point(centerX, centerY); doughnutParams.DataPoint = dataPoint; doughnutParams.InnerRadius = radius / 2; doughnutParams.OuterRadius = radius; if (chart.View3D) { doughnutParams.StartAngle = doughnutParams.FixAngle((startAngle) % (Math.PI * 2)); doughnutParams.StopAngle = doughnutParams.FixAngle((endAngle) % (Math.PI * 2)); } else { doughnutParams.StartAngle = startAngle; doughnutParams.StopAngle = endAngle; } doughnutParams.Lighting = (Boolean)dataPoint.LightingEnabled; doughnutParams.Bevel = series.Bevel; doughnutParams.IsLargerArc = (angle / (Math.PI)) > 1; doughnutParams.Background = dataPoint.Color; doughnutParams.Width = widthOfPlotArea; doughnutParams.Height = height; doughnutParams.TiltAngle = Math.Asin(0.4); doughnutParams.Depth = 20 / doughnutParams.YAxisScaling; doughnutParams.MeanAngle = meanAngle; doughnutParams.LabelLineEnabled = (Boolean)dataPoint.LabelLineEnabled; doughnutParams.LabelLineColor = dataPoint.LabelLineColor; doughnutParams.LabelLineThickness = (Double)dataPoint.LabelLineThickness; doughnutParams.LabelLineStyle = ExtendedGraphics.GetDashArray((LineStyles)dataPoint.LabelLineStyle); offsetX = radius * doughnutParams.ExplodeRatio * Math.Cos(meanAngle); offsetY = radius * doughnutParams.ExplodeRatio * Math.Sin(meanAngle); doughnutParams.OffsetX = offsetX; doughnutParams.OffsetY = offsetY * (chart.View3D ? doughnutParams.YAxisScaling : 1); if (dataPoint.LabelVisual != null) { if (dataPoint.LabelVisual.Visibility == Visibility.Collapsed) doughnutParams.LabelLineEnabled = false; Double left = (Double)dataPoint.LabelVisual.GetValue(Canvas.LeftProperty); if (left < widthOfPlotArea / 2) { doughnutParams.LabelLineTargetToRight = true; // pieParams.LabelPoint = new Point((Double)dataPoint.LabelVisual.GetValue(Canvas.LeftProperty) + dataPoint.LabelVisual.DesiredSize.Width, (Double)dataPoint.LabelVisual.GetValue(Canvas.TopProperty) + dataPoint.LabelVisual.DesiredSize.Height / 2); doughnutParams.LabelPoint = new Point(left + dataPoint.LabelVisual.Width + LabelPlacementHelper.LABEL_LINE_GAP, (Double)dataPoint.LabelVisual.GetValue(Canvas.TopProperty) + dataPoint.LabelVisual.Height / 2); } else { doughnutParams.LabelLineTargetToRight = false; doughnutParams.LabelPoint = new Point(left - LabelPlacementHelper.LABEL_LINE_GAP, (Double)dataPoint.LabelVisual.GetValue(Canvas.TopProperty) + dataPoint.LabelVisual.Height / 2); } //if ((Double)dataPoint.LabelVisual.GetValue(Canvas.LeftProperty) < width / 2) //{ // doughnutParams.LabelPoint = new Point((Double)dataPoint.LabelVisual.GetValue(Canvas.LeftProperty) + dataPoint.LabelVisual.Width + LABEL_LINE_GAP, (Double)dataPoint.LabelVisual.GetValue(Canvas.TopProperty) + dataPoint.LabelVisual.Height / 2); //} //else //{ // doughnutParams.LabelPoint = new Point((Double)dataPoint.LabelVisual.GetValue(Canvas.LeftProperty) - LABEL_LINE_GAP, (Double)dataPoint.LabelVisual.GetValue(Canvas.TopProperty) + dataPoint.LabelVisual.Height / 2); //} // apply animation to the labels if (animationEnabled) { series.Storyboard = CreateOpacityAnimation(currentDataSeries, doughnutParams.DataPoint, series.Storyboard, dataPoint.LabelVisual, 2, 1, 0.5); dataPoint.LabelVisual.Opacity = 0; } } if (dataPoint.LabelStyle == LabelStyles.Inside && dataPoint.InternalYValue == 0) doughnutParams.LabelLineEnabled = false; Faces faces = new Faces(); faces.Parts = new List<DependencyObject>(); doughnutParams.TagReference = dataPoint; if (chart.View3D) { PieDoughnut3DPoints unExplodedPoints = new PieDoughnut3DPoints(); PieDoughnut3DPoints explodedPoints = new PieDoughnut3DPoints(); List<Shape> doughnutFaces = GetDoughnut3D(currentDataSeries, ref faces, doughnutParams, ref unExplodedPoints, ref explodedPoints, ref dataPoint.LabelLine, enabledDataPoints); foreach (Shape path in doughnutFaces) { if (path != null) { visual.Children.Add(path); faces.VisualComponents.Add(path); faces.BorderElements.Add(path); path.RenderTransform = new TranslateTransform(); // apply animation to the 3D sections if (animationEnabled) { series.Storyboard = CreateOpacityAnimation(currentDataSeries, doughnutParams.DataPoint, series.Storyboard, path, 1.0 / (series.InternalDataPoints.Count) * (series.InternalDataPoints.IndexOf(dataPoint)), dataPoint.InternalOpacity, 0.5); path.Opacity = 0; } } } if (dataPoint.LabelLine != null && doughnutParams.LabelLineEnabled) { dataPoint.LabelLine.RenderTransform = new TranslateTransform(); visual.Children.Add(dataPoint.LabelLine); if (dataPoint.InternalYValue == 0) { Double yOffset = doughnutParams.YAxisScaling; Line zeroLine = new Line(); zeroLine.X1 = doughnutParams.Center.X + doughnutParams.InnerRadius * Math.Cos(doughnutParams.MeanAngle); zeroLine.Y1 = doughnutParams.Center.Y + doughnutParams.InnerRadius * Math.Sin(doughnutParams.MeanAngle); zeroLine.Y1 -= offsetY; zeroLine.Y1 += doughnutParams.Depth / 2 * doughnutParams.ZAxisScaling; zeroLine.X2 = unExplodedPoints.LabelLineStartPoint.X; zeroLine.Y2 = unExplodedPoints.LabelLineStartPoint.Y; zeroLine.Stroke = doughnutParams.LabelLineColor; zeroLine.StrokeThickness = 0.25; zeroLine.IsHitTestVisible = false; visual.Children.Add(zeroLine); if (animationEnabled) { series.Storyboard = CreateOpacityAnimation(currentDataSeries, doughnutParams.DataPoint, series.Storyboard, zeroLine, 2, zeroLine.Opacity, 0.5); zeroLine.Opacity = 0; } } faces.VisualComponents.Add(dataPoint.LabelLine); } faces.Visual = visual; UpdateExplodedPosition(doughnutParams, dataPoint, offsetX, unExplodedPoints, explodedPoints, widthOfPlotArea); ///------------------------ dataPoint.ExplodeAnimation = new Storyboard(); dataPoint.ExplodeAnimation = CreateExplodingOut3DAnimation(currentDataSeries, dataPoint, dataPoint.ExplodeAnimation, doughnutFaces, dataPoint.LabelVisual as Canvas, dataPoint.LabelLine, unExplodedPoints, explodedPoints, doughnutParams.OffsetX, doughnutParams.OffsetY); dataPoint.UnExplodeAnimation = new Storyboard(); dataPoint.UnExplodeAnimation = CreateExplodingIn3DAnimation(currentDataSeries, dataPoint, dataPoint.UnExplodeAnimation, doughnutFaces, dataPoint.LabelVisual as Canvas, dataPoint.LabelLine, unExplodedPoints, explodedPoints, doughnutParams.OffsetX, doughnutParams.OffsetY); } else { PieDoughnut2DPoints unExplodedPoints = new PieDoughnut2DPoints(); PieDoughnut2DPoints explodedPoints = new PieDoughnut2DPoints(); if (labelStateCounter == enabledDataPoints.Count) { doughnutParams.OuterRadius -= doughnutParams.OuterRadius * doughnutParams.ExplodeRatio; doughnutParams.InnerRadius = doughnutParams.OuterRadius / 2; } Canvas pieVisual = GetDoughnut2D(currentDataSeries, ref faces, doughnutParams, ref unExplodedPoints, ref explodedPoints, ref dataPoint.LabelLine, enabledDataPoints); UpdateExplodedPosition(doughnutParams, dataPoint, offsetX, unExplodedPoints, explodedPoints, widthOfPlotArea); TranslateTransform translateTransform = new TranslateTransform(); pieVisual.RenderTransform = translateTransform; dataPoint.ExplodeAnimation = new Storyboard(); dataPoint.ExplodeAnimation = CreateExplodingOut2DAnimation(currentDataSeries, dataPoint, dataPoint.ExplodeAnimation, pieVisual, dataPoint.LabelVisual as Canvas, dataPoint.LabelLine, translateTransform, unExplodedPoints, explodedPoints, offsetX, offsetY); dataPoint.UnExplodeAnimation = new Storyboard(); dataPoint.UnExplodeAnimation = CreateExplodingIn2DAnimation(currentDataSeries, dataPoint, dataPoint.UnExplodeAnimation, pieVisual, dataPoint.LabelVisual as Canvas, dataPoint.LabelLine, translateTransform, unExplodedPoints, explodedPoints, offsetX, offsetY); pieVisual.SetValue(Canvas.TopProperty, height / 2 - pieVisual.Height / 2); pieVisual.SetValue(Canvas.LeftProperty, widthOfPlotArea / 2 - pieVisual.Width / 2); visual.Children.Add(pieVisual); faces.VisualComponents.Add(pieVisual); faces.Visual = pieVisual; } dataPoint.Faces = faces; startAngle = endAngle; if (!chart.AnimationEnabled || chart.IsInDesignMode || !chart.ChartArea._isFirstTimeRender) { if (dataPoint.Faces != null) { foreach (Shape shape in dataPoint.Faces.BorderElements) { InteractivityHelper.ApplyBorderEffect(shape, (BorderStyles)dataPoint.BorderStyle, dataPoint.InternalBorderThickness.Left, dataPoint.BorderColor); } } } } if (chart.View3D) { Int32 zindex1, zindex2; _elementPositionData.Sort(ElementPositionData.CompareAngle); zindex1 = 1000; zindex2 = -1000; for (Int32 i = 0; i < _elementPositionData.Count; i++) { SetZIndex(_elementPositionData[i].Element, ref zindex1, ref zindex2, _elementPositionData[i].StartAngle); } } if (labelCanvas != null) visual.Children.Add(labelCanvas); RectangleGeometry clipRectangle = new RectangleGeometry(); clipRectangle.Rect = new Rect(0, 0, widthOfPlotArea, height); visual.Clip = clipRectangle; return visual; }
/// <summary> /// Return visual object for pie chart /// </summary> /// <param name="width">Width of the PlotArea</param> /// <param name="height">Height of the PlotArea</param> /// <param name="plotDetails">PlotDetails reference</param> /// <param name="seriesList">List of series list</param> /// <param name="chart">Chart reference</param> /// <param name="animationEnabled">Whether animation is enabled</param> /// <returns>Canvas</returns> internal static Canvas GetVisualObjectForPieChart(Double width, Double height, PlotDetails plotDetails, List<DataSeries> seriesList, Chart chart, bool isAnimationEnabled) { if (Double.IsNaN(width) || Double.IsNaN(height) || width <= 0 || height <= 0) return null; DataSeries currentDataSeries = null; // Debug.WriteLine("PieStart: " + DateTime.Now.ToLongTimeString()); Canvas visual = new Canvas() { Width = width, Height = height }; DataSeries series = seriesList[0]; if (series.Enabled == false) return visual; // List<DataPoint> enabledDataPoints = (from datapoint in series.InternalDataPoints where datapoint.Enabled == true && datapoint.InternalYValue != 0 && !Double.IsNaN(datapoint.InternalYValue) select datapoint).ToList(); List<DataPoint> enabledDataPoints = (from datapoint in series.InternalDataPoints where datapoint.Enabled == true && !Double.IsNaN(datapoint.InternalYValue) select datapoint).ToList(); if ((from dp in enabledDataPoints select dp.InternalYValue).Sum() == 0) enabledDataPoints.Clear(); Double absoluteSum = plotDetails.GetAbsoluteSumOfDataPoints(enabledDataPoints); absoluteSum = (absoluteSum == 0) ? 1 : absoluteSum; Double centerX = width / 2; Double centerY = height / 2; Double offsetX = 0; Double offsetY = 0; Boolean IsLabelEnabled; Size pieSize = new Size(); Canvas labelCanvas = CreateAndPositionLabels(absoluteSum, enabledDataPoints, width, height, ((chart.View3D) ? 0.4 : 1), chart.View3D, ref pieSize); Debug.WriteLine("Labels Positioning over: " + DateTime.Now.ToLongTimeString()); if (labelCanvas == null) IsLabelEnabled = false; else { IsLabelEnabled = true; labelCanvas.SetValue(Canvas.ZIndexProperty, 50001); labelCanvas.IsHitTestVisible = false; } Double radius = Math.Min(pieSize.Width, pieSize.Height) / (chart.View3D ? 1 : 2); Double startAngle = series.InternalStartAngle; Double endAngle = 0; Double angle; Double absoluteYValue; Double meanAngle = 0; Int32 zindex = 0; if (chart.View3D) _elementPositionData = new List<ElementPositionData>(); if (series.Storyboard == null) series.Storyboard = new Storyboard(); currentDataSeries = series; SectorChartShapeParams pieParams = null; Int32 labelStateCounter = 0; if (!chart.View3D) { foreach (DataPoint dataPoint in enabledDataPoints) { if (dataPoint.LabelStyle == LabelStyles.Inside || !(Boolean)dataPoint.LabelEnabled) labelStateCounter++; } } foreach (DataPoint dataPoint in enabledDataPoints) { if (Double.IsNaN(dataPoint.InternalYValue))// || dataPoint.InternalYValue == 0) continue; absoluteYValue = Math.Abs(dataPoint.InternalYValue); angle = (absoluteYValue / absoluteSum) * Math.PI * 2; endAngle = startAngle + angle; meanAngle = (startAngle + endAngle) / 2; pieParams = new SectorChartShapeParams(); dataPoint.VisualParams = pieParams; pieParams.Storyboard = series.Storyboard; pieParams.AnimationEnabled = isAnimationEnabled; pieParams.Center = new Point(centerX, centerY); pieParams.ExplodeRatio = chart.View3D ? 0.2 : 0.1; pieParams.InnerRadius = 0; pieParams.OuterRadius = radius; pieParams.DataPoint = dataPoint; if (chart.View3D) { pieParams.StartAngle = pieParams.FixAngle((startAngle) % (Math.PI * 2)); pieParams.StopAngle = pieParams.FixAngle((endAngle) % (Math.PI * 2)); } else { pieParams.StartAngle = startAngle; pieParams.StopAngle = endAngle; } pieParams.Lighting = (Boolean)dataPoint.LightingEnabled; pieParams.Bevel = series.Bevel; pieParams.IsLargerArc = (angle / (Math.PI)) > 1; pieParams.Background = dataPoint.Color; pieParams.Width = width; pieParams.Height = height; pieParams.TiltAngle = Math.Asin(0.4); pieParams.Depth = 20 / pieParams.YAxisScaling; pieParams.MeanAngle = meanAngle; pieParams.LabelLineEnabled = (Boolean)dataPoint.LabelLineEnabled; pieParams.LabelLineColor = dataPoint.LabelLineColor; pieParams.LabelLineThickness = (Double)dataPoint.LabelLineThickness; pieParams.LabelLineStyle = ExtendedGraphics.GetDashArray((LineStyles)dataPoint.LabelLineStyle); pieParams.IsZero = (dataPoint.InternalYValue == 0); offsetX = radius * pieParams.ExplodeRatio * Math.Cos(meanAngle); offsetY = radius * pieParams.ExplodeRatio * Math.Sin(meanAngle); pieParams.OffsetX = offsetX; pieParams.OffsetY = offsetY * (chart.View3D ? pieParams.YAxisScaling : 1); if (dataPoint.LabelVisual != null) { if (dataPoint.LabelVisual.Visibility == Visibility.Collapsed) pieParams.LabelLineEnabled = false; Double left = (Double)dataPoint.LabelVisual.GetValue(Canvas.LeftProperty); if (left < width / 2) { pieParams.LabelLineTargetToRight = true; // pieParams.LabelPoint = new Point((Double)dataPoint.LabelVisual.GetValue(Canvas.LeftProperty) + dataPoint.LabelVisual.DesiredSize.Width, (Double)dataPoint.LabelVisual.GetValue(Canvas.TopProperty) + dataPoint.LabelVisual.DesiredSize.Height / 2); pieParams.LabelPoint = new Point(left + dataPoint.LabelVisual.Width + LabelPlacementHelper.LABEL_LINE_GAP, (Double)dataPoint.LabelVisual.GetValue(Canvas.TopProperty) + dataPoint.LabelVisual.Height / 2); } else { pieParams.LabelLineTargetToRight = false; pieParams.LabelPoint = new Point(left - LabelPlacementHelper.LABEL_LINE_GAP, (Double)dataPoint.LabelVisual.GetValue(Canvas.TopProperty) + dataPoint.LabelVisual.Height / 2); } // apply animation to the labels if (isAnimationEnabled) { series.Storyboard = CreateOpacityAnimation(currentDataSeries, dataPoint, series.Storyboard, dataPoint.LabelVisual, 2, dataPoint.InternalOpacity * dataPoint.Parent.InternalOpacity, 0.5); dataPoint.LabelVisual.Opacity = 0; } } if (dataPoint.LabelStyle == LabelStyles.Inside && dataPoint.InternalYValue == 0) pieParams.LabelLineEnabled = false; Faces faces = new Faces(); if (chart.View3D) { Create3DPie(currentDataSeries, width, height, series, enabledDataPoints, dataPoint, ref visual, ref faces, ref pieParams, ref offsetX, ref zindex, isAnimationEnabled); } else { Create2DPie(currentDataSeries, width, height, series, enabledDataPoints, dataPoint, ref visual, ref faces, ref pieParams, ref offsetX, ref offsetY, ref zindex, isAnimationEnabled, labelStateCounter); } Debug.WriteLine("Datapoint" + enabledDataPoints.IndexOf(dataPoint) + ": " + DateTime.Now.ToLongTimeString()); dataPoint.Faces = faces; startAngle = endAngle; if (!chart.AnimationEnabled || chart.IsInDesignMode || !chart.ChartArea._isFirstTimeRender) { if (dataPoint.Faces != null) { foreach (Shape shape in dataPoint.Faces.BorderElements) { InteractivityHelper.ApplyBorderEffect(shape, (BorderStyles)dataPoint.BorderStyle, dataPoint.InternalBorderThickness.Left, dataPoint.BorderColor); } } } } if (chart.View3D) { Int32 zindex1, zindex2; _elementPositionData.Sort(ElementPositionData.CompareAngle); zindex1 = 1000; zindex2 = -1000; for (Int32 i = 0; i < _elementPositionData.Count; i++) { SetZIndex(_elementPositionData[i].Element, ref zindex1, ref zindex2, _elementPositionData[i].StartAngle); } } if (IsLabelEnabled && labelCanvas != null) visual.Children.Add(labelCanvas); RectangleGeometry clipRectangle = new RectangleGeometry(); clipRectangle.Rect = new Rect(0, 0, width, height); visual.Clip = clipRectangle; return visual; }