/*
Copyright (C) 2008 Webyog Softworks Private Limited
This file is a part of Visifire Charts.
Visifire is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
You should have received a copy of the GNU General Public License
along with Visifire Charts. If not, see .
If GPL is not suitable for your products or company, Webyog provides Visifire
under a flexible commercial license designed to meet your specific usage and
distribution requirements. If you have already obtained a commercial license
from Webyog, you can use this file under those license terms.
*/
#if WPF
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
#else
using System;
using System.Windows;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
#endif
using Visifire.Commons;
namespace Visifire.Charts
{
///
/// Visifire.Charts.PolygonalChartShapeParams class
///
internal class PolygonalChartShapeParams
{
///
/// Collection of points
///
public PointCollection Points
{
get;
set;
}
///
/// Background color of the polygon
///
public Brush Background
{
get;
set;
}
///
/// Border color of the polygon
///
public Brush BorderColor
{
get;
set;
}
///
/// Weather bevel effect is applied
///
public Boolean Bevel
{
get;
set;
}
///
/// Weather lighting effect is applied
///
public Boolean Lighting
{
get;
set;
}
///
/// Weather shadow effect is applied
///
public Boolean Shadow
{
get;
set;
}
///
/// Border style property
///
public DoubleCollection BorderStyle
{
get;
set;
}
///
/// Border thickness property
///
public Double BorderThickness
{
get;
set;
}
///
/// Whether used for positive DataPoint
///
public Boolean IsPositive
{
get;
set;
}
///
/// 3D depth of ploygon area
///
public Double Depth3D
{
get;
set;
}
///
/// Storyboard used for animation
///
public Storyboard Storyboard
{
get;
set;
}
///
/// Whether animation is enabled for control
///
public Boolean AnimationEnabled
{
get;
set;
}
///
/// Ploygon visual size
///
public Size Size
{
get;
set;
}
///
/// Tag reference for visual object
///
public FrameworkElement TagReference
{
get;
set;
}
}
///
/// Visifire.Charts.AreaChart class
///
internal class AreaChart
{
#region Public Methods
#endregion
#region Public Properties
#endregion
#region Public Events And Delegates
#endregion
#region Protected Methods
#endregion
#region Internal Properties
#endregion
#region Private Properties
#endregion
#region Private Delegates
#endregion
#region Private Methods
///
/// Get Stacked3D side faces
///
/// Faces
/// Area parameters
/// Canvas
private static Canvas GetStacked3DSideFaces(ref Faces faces, PolygonalChartShapeParams areaParams)
{
Point centroid;
Brush sideBrush = areaParams.Lighting ? Graphics.GetRightFaceBrush(areaParams.Background) : areaParams.Background;
Brush topBrush = areaParams.Lighting ? Graphics.GetTopFaceBrush(areaParams.Background) : areaParams.Background;
Int32 pointIndexLimit = areaParams.IsPositive ? areaParams.Points.Count - 1 : areaParams.Points.Count;
Canvas polygonSet = new Canvas();
Rect size = GetBounds(areaParams.Points);
polygonSet.Width = size.Width + areaParams.Depth3D;
polygonSet.Height = size.Height + areaParams.Depth3D;
polygonSet.SetValue(Canvas.TopProperty, size.Top - areaParams.Depth3D);
polygonSet.SetValue(Canvas.LeftProperty, size.Left);
for (Int32 i = 0; i < pointIndexLimit; i++)
{
Polygon sides = new Polygon() { Tag = new ElementData() { Element = areaParams.TagReference } };
PointCollection points = new PointCollection();
Int32 index1 = i % areaParams.Points.Count;
Int32 index2 = (i + 1) % areaParams.Points.Count;
points.Add(areaParams.Points[index1]);
points.Add(areaParams.Points[index2]);
points.Add(new Point(areaParams.Points[index2].X + areaParams.Depth3D, areaParams.Points[index2].Y - areaParams.Depth3D));
points.Add(new Point(areaParams.Points[index1].X + areaParams.Depth3D, areaParams.Points[index1].Y - areaParams.Depth3D));
sides.Points = points;
centroid = GetCentroid(points);
Int32 zindex = GetAreaZIndex(centroid.X, centroid.Y, areaParams.IsPositive);
sides.SetValue(Canvas.ZIndexProperty, zindex);
if (i == (areaParams.Points.Count - 2))
{
sides.Fill = sideBrush;
(sides.Tag as ElementData).VisualElementName = "Side";
}
else
{
sides.Fill = topBrush;
(sides.Tag as ElementData).VisualElementName = "Top";
}
sides.StrokeDashArray = areaParams.BorderStyle != null ? ExtendedGraphics.CloneCollection(areaParams.BorderStyle) : areaParams.BorderStyle;
sides.StrokeThickness = areaParams.BorderThickness;
if(sides.StrokeThickness > 0)
sides.Stroke = areaParams.BorderColor;
sides.StrokeMiterLimit = 1;
Rect sidesBounds = GetBounds(points);
sides.Stretch = Stretch.Fill;
sides.Width = sidesBounds.Width;
sides.Height = sidesBounds.Height;
sides.SetValue(Canvas.TopProperty, sidesBounds.Y - (size.Top - areaParams.Depth3D));
sides.SetValue(Canvas.LeftProperty, sidesBounds.X - size.X);
faces.Parts.Add(sides);
polygonSet.Children.Add(sides);
}
return polygonSet;
}
///
/// Get area Z-Index
///
/// Left position
/// Top position
/// Whether DataPoint Value is positive or negative
/// Zindex as Int32
private static Int32 GetAreaZIndex(Double left, Double top, Boolean isPositive)
{
Int32 Zi = 0;
Int32 ioffset = (Int32)left;
if (ioffset == 0)
ioffset++;
Zi = (isPositive) ? Zi + (Int32)(ioffset) : Zi + Int32.MinValue + (Int32)(ioffset);
return Zi;
}
///
/// Get Z-Index for StackedArea visual
///
/// Left position
/// Top position
/// Whether DataPoint value is negative or positive
/// Index
/// Zindex as Int32
private static Int32 GetStackedAreaZIndex(Double left, Double top, Boolean isPositive, Int32 index)
{
Int32 ioffset = (Int32)(left);
Int32 topOffset = (Int32)(index);
Int32 zindex = 0;
if (isPositive)
{
zindex = (Int32)(ioffset + topOffset);
}
else
{
if (ioffset == 0)
ioffset = 1;
zindex = Int32.MinValue + (Int32)(ioffset + topOffset);
}
return zindex;
}
///
/// Apply area chart animation
///
/// Area visual reference
/// Storyboard
/// Whether DataPoint is positive
/// Animation begin time
/// Storyboard
private static Storyboard ApplyAreaAnimation(DataSeries currentDataSeries, UIElement areaElement, Storyboard storyboard, bool isPositive, Double beginTime)
{
ScaleTransform scaleTransform = new ScaleTransform() { ScaleY = 0 };
areaElement.RenderTransform = scaleTransform;
if (isPositive)
{
areaElement.RenderTransformOrigin = new Point(0.5, 1);
}
else
{
areaElement.RenderTransformOrigin = new Point(0.5, 0);
}
DoubleCollection values = Graphics.GenerateDoubleCollection(0, 1);
DoubleCollection frameTimes = Graphics.GenerateDoubleCollection(0, 0.75);
List splines = AnimationHelper.GenerateKeySplineList
(
new Point(0, 0), new Point(1, 1),
new Point(0, 0), new Point(0.5, 1)
);
DoubleAnimationUsingKeyFrames growAnimation = AnimationHelper.CreateDoubleAnimation(currentDataSeries, scaleTransform, "(ScaleTransform.ScaleY)", beginTime + 0.5, frameTimes, values, splines);
storyboard.Children.Add(growAnimation);
return storyboard;
}
///
/// Apply animation for StackedArea chart
///
/// Area visual reference
/// Storyboard
/// Animation begin time
/// Animation duration
/// Storyboard
private static Storyboard ApplyStackedAreaAnimation(DataSeries currentDataSeries, FrameworkElement areaElement, Storyboard storyboard, Double beginTime, Double duration)
{
return AnimationHelper.ApplyOpacityAnimation(areaElement, currentDataSeries, storyboard, beginTime, duration, 1);
}
///
/// Creating opacity animation for bevel layer
///
/// Storyboard
/// Target bevel layer
/// Animation begin time
/// Target opacity
/// Animation duration
/// Storyboard
private static Storyboard CreateOpacityAnimation(DataSeries currentDataSeries, Storyboard storyboard, DependencyObject target, Double beginTime, Double opacity, Double duration)
{
DoubleCollection values = Graphics.GenerateDoubleCollection(0, opacity);
DoubleCollection frames = Graphics.GenerateDoubleCollection(0, duration);
List splines = AnimationHelper.GenerateKeySplineList(frames.Count);
DoubleAnimationUsingKeyFrames opacityAnimation = AnimationHelper.CreateDoubleAnimation(currentDataSeries, target, "(UIElement.Opacity)", beginTime + 0.5, frames, values, splines);
storyboard.Children.Add(opacityAnimation);
return storyboard;
}
///
/// Get area parameters
///
/// DataSeries
/// color
/// 3D depth
/// PolygonalChartShapeParams
private static PolygonalChartShapeParams GetAreaParms(DataSeries series, Brush colorBrush, Double depth3d)
{
PolygonalChartShapeParams areaParams = new PolygonalChartShapeParams();
areaParams.Background = colorBrush;
areaParams.Lighting = (Boolean)series.LightingEnabled;
areaParams.Shadow = series.ShadowEnabled;
areaParams.Bevel = series.Bevel;
areaParams.BorderColor = series.BorderColor;
areaParams.BorderStyle = ExtendedGraphics.GetDashArray(series.BorderStyle);
areaParams.BorderThickness = series.InternalBorderThickness.Left;
areaParams.Depth3D = depth3d;
areaParams.TagReference = series;
return areaParams;
}
#endregion
#region Internal Methods
///
/// Create new Marker
///
/// Chart
/// DataPoint
/// Marker Size
/// Label text
/// Marker
internal static Marker CreateNewMarker(Chart chart, DataPoint dataPoint, Size markerSize, String labelText)
{
Boolean markerBevel = false;
Marker marker = new Marker((MarkerTypes)dataPoint.MarkerType, (Double)dataPoint.MarkerScale, markerSize, markerBevel, dataPoint.MarkerColor, labelText);
marker.MarkerSize = markerSize;
marker.BorderColor = dataPoint.MarkerBorderColor;
marker.BorderThickness = ((Thickness)dataPoint.MarkerBorderThickness).Left;
marker.FontColor = Chart.CalculateDataPointLabelFontColor(chart, dataPoint, dataPoint.LabelFontColor, LabelStyles.OutSide);
marker.FontFamily = dataPoint.LabelFontFamily;
marker.FontSize = (Double)dataPoint.LabelFontSize;
marker.FontStyle = (FontStyle)dataPoint.LabelFontStyle;
marker.FontWeight = (FontWeight)dataPoint.LabelFontWeight;
marker.TextBackground = dataPoint.LabelBackground;
marker.MarkerFillColor = dataPoint.MarkerColor;
marker.Tag = new ElementData() { Element = dataPoint };
return marker;
}
///
/// Get Marker for DataPoint
///
/// Chart
/// DataPoint
/// position of the marker
/// Whether DataPoint Value is positive or negative
/// Marker
internal static Marker GetMarkerForDataPoint(Chart chart, Double height, Boolean isTopOfStack, DataPoint dataPoint, Double position, bool isPositive)
{
if ((Boolean)dataPoint.MarkerEnabled || (Boolean)dataPoint.LabelEnabled)
{
Size markerSize = (Boolean)dataPoint.MarkerEnabled ? new Size((Double)dataPoint.MarkerSize, (Double)dataPoint.MarkerSize) : new Size(0, 0);
String labelText = (Boolean)dataPoint.LabelEnabled ? dataPoint.TextParser(dataPoint.LabelText) : "";
dataPoint.Marker = CreateNewMarker(chart, dataPoint, markerSize, labelText);
if (true && !String.IsNullOrEmpty(labelText))
{
if (!Double.IsNaN(dataPoint.LabelAngle) && dataPoint.LabelAngle != 0)
{
dataPoint.Marker.LabelAngle = dataPoint.LabelAngle;
dataPoint.Marker.TextOrientation = Orientation.Vertical;
if (isPositive)
{
dataPoint.Marker.TextAlignmentX = AlignmentX.Center;
dataPoint.Marker.TextAlignmentY = AlignmentY.Top;
}
else
{
dataPoint.Marker.TextAlignmentX = AlignmentX.Center;
dataPoint.Marker.TextAlignmentY = AlignmentY.Bottom;
}
dataPoint.Marker.LabelStyle = (LabelStyles)dataPoint.LabelStyle;
}
dataPoint.Marker.CreateVisual();
if (Double.IsNaN(dataPoint.LabelAngle) || dataPoint.LabelAngle == 0)
{
dataPoint.Marker.TextAlignmentX = AlignmentX.Center;
if (isPositive)
{
if (dataPoint.LabelStyle == LabelStyles.OutSide && !dataPoint.IsLabelStyleSet && !dataPoint.Parent.IsLabelStyleSet)
{
if (!isTopOfStack)
{
if (position + dataPoint.Marker.TextBlockSize.Height > height)
dataPoint.Marker.TextAlignmentY = AlignmentY.Top;
else
dataPoint.Marker.TextAlignmentY = AlignmentY.Bottom;
}
else
{
//if (position < dataPoint.Marker.MarkerActualSize.Height || dataPoint.LabelStyle == LabelStyles.Inside)
if (position - dataPoint.Marker.MarkerActualSize.Height - dataPoint.Marker.MarkerSize.Height / 2 < 0 || dataPoint.LabelStyle == LabelStyles.Inside)
dataPoint.Marker.TextAlignmentY = AlignmentY.Bottom;
else
dataPoint.Marker.TextAlignmentY = AlignmentY.Top;
}
}
else if (dataPoint.LabelStyle == LabelStyles.OutSide)
dataPoint.Marker.TextAlignmentY = AlignmentY.Top;
else
dataPoint.Marker.TextAlignmentY = AlignmentY.Bottom;
}
else
{
if (dataPoint.LabelStyle == LabelStyles.OutSide && !dataPoint.IsLabelStyleSet && !dataPoint.Parent.IsLabelStyleSet)
{
if (!isTopOfStack)
dataPoint.Marker.TextAlignmentY = AlignmentY.Top;
else
{
if (position + dataPoint.Marker.MarkerActualSize.Height + dataPoint.Marker.MarkerSize.Height / 2 > chart.PlotArea.BorderElement.Height || dataPoint.LabelStyle == LabelStyles.Inside)
dataPoint.Marker.TextAlignmentY = AlignmentY.Top;
else
dataPoint.Marker.TextAlignmentY = AlignmentY.Bottom;
}
}
else if (dataPoint.LabelStyle == LabelStyles.OutSide)
dataPoint.Marker.TextAlignmentY = AlignmentY.Bottom;
else
dataPoint.Marker.TextAlignmentY = AlignmentY.Top;
}
}
}
dataPoint.Marker.CreateVisual();
return dataPoint.Marker;
}
return null;
}
///
/// Get visual object for area chart
///
/// Width of the PlotArea
/// Height of the PlotArea
/// PlotDetails
/// List of DataSeries with render as area chart
/// Chart
/// PlankDepth
/// Whether animation is enabled for chart
/// Area chart canvas
internal static Canvas GetVisualObjectForAreaChart(Double width, Double height, PlotDetails plotDetails, List seriesList, Chart chart, Double plankDepth, bool animationEnabled)
{
if (Double.IsNaN(width) || Double.IsNaN(height) || width <= 0 || height <= 0)
return null;
DataSeries currentDataSeries = null; // Current working DataSeries
Boolean plankDrawn = false;
Canvas visual = new Canvas() { Width = width, Height = height };
Canvas labelCanvas = new Canvas() { Width = width, Height = height };
Canvas areaCanvas = new Canvas() { Width = width, Height = height };
Double depth3d = plankDepth / plotDetails.Layer3DCount * (chart.View3D ? 1 : 0);
Double visualOffset = depth3d * (plotDetails.SeriesDrawingIndex[seriesList[0]] + 1);
areaCanvas.SetValue(Canvas.TopProperty, visualOffset);
areaCanvas.SetValue(Canvas.LeftProperty, -visualOffset);
labelCanvas.SetValue(Canvas.TopProperty, visualOffset);
labelCanvas.SetValue(Canvas.LeftProperty, -visualOffset);
Marker marker;
Double minimumXValue = Double.MaxValue;
Double maximumXValue = Double.MinValue;
foreach (DataSeries series in seriesList)
{
if (series.Enabled == false)
continue;
if (series.Storyboard == null)
series.Storyboard = new Storyboard();
currentDataSeries = series;
PlotGroup plotGroup = series.PlotGroup;
Brush areaBrush = series.Color;
Double limitingYValue = 0;
minimumXValue = Math.Min(minimumXValue, plotGroup.MinimumX);
maximumXValue = Math.Max(maximumXValue, plotGroup.MaximumX);
if (plotGroup.AxisY.InternalAxisMinimum > 0)
limitingYValue = (Double)plotGroup.AxisY.InternalAxisMinimum;
if (plotGroup.AxisY.InternalAxisMaximum < 0)
limitingYValue = (Double)plotGroup.AxisY.InternalAxisMaximum;
PolygonalChartShapeParams areaParams = GetAreaParms(series, areaBrush, depth3d);
areaParams.Storyboard = series.Storyboard;
areaParams.AnimationEnabled = animationEnabled;
areaParams.Size = new Size(width, height);
PointCollection points = new PointCollection();
List enabledDataPoints = (from datapoint in series.InternalDataPoints where datapoint.Enabled == true select datapoint).ToList();
if (enabledDataPoints.Count <= 0)
continue;
Faces faces = new Faces();
series.Faces = faces;
series.Faces.Parts = new List();
DataPoint currentDataPoint = enabledDataPoints[0];
DataPoint nextDataPoint;
Double xPosition = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, currentDataPoint.InternalXValue);
Double yPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, limitingYValue);
points.Add(new Point(xPosition, yPosition));
for (Int32 i = 0; i < enabledDataPoints.Count - 1; i++)
{
currentDataPoint = enabledDataPoints[i];
nextDataPoint = enabledDataPoints[i + 1];
if (Double.IsNaN(currentDataPoint.InternalYValue)) continue;
xPosition = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, currentDataPoint.InternalXValue);
yPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, currentDataPoint.InternalYValue);
points.Add(new Point(xPosition, yPosition));
marker = GetMarkerForDataPoint(chart, height, true, currentDataPoint, yPosition, currentDataPoint.InternalYValue > 0);
if (marker != null)
{
marker.AddToParent(labelCanvas, xPosition, yPosition, new Point(0.5, 0.5));
// Apply marker animation
if (animationEnabled)
{
if (currentDataPoint.Parent.Storyboard == null)
currentDataPoint.Parent.Storyboard = new Storyboard();
// Apply marker animation
currentDataPoint.Parent.Storyboard = AnimationHelper.ApplyOpacityAnimation(marker, currentDataSeries, currentDataPoint.Parent.Storyboard, 1, currentDataPoint.InternalOpacity * currentDataPoint.Parent.InternalOpacity);
}
}
if (Math.Sign(currentDataPoint.InternalYValue) != Math.Sign(nextDataPoint.InternalYValue))
{
Double xNextPosition = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, nextDataPoint.InternalXValue);
Double yNextPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, nextDataPoint.InternalYValue);
Double limitingYPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, limitingYValue);
Double xNew = Graphics.ConvertScale(yPosition, yNextPosition, limitingYPosition, xPosition, xNextPosition);
Double yNew = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, limitingYValue);
points.Add(new Point(xNew, yNew));
// get the faces
areaParams.Points = points;
areaParams.IsPositive = (currentDataPoint.InternalYValue > 0);
if (chart.View3D)
{
Canvas areaVisual3D = Get3DArea(currentDataSeries, ref faces, areaParams);
areaVisual3D.SetValue(Canvas.ZIndexProperty, GetAreaZIndex(xPosition, yPosition, areaParams.IsPositive));
areaCanvas.Children.Add(areaVisual3D);
series.Faces.VisualComponents.Add(areaVisual3D);
}
else
{
areaCanvas.Children.Add(Get2DArea(currentDataSeries, ref faces, areaParams));
series.Faces.VisualComponents.Add(areaCanvas);
}
points = new PointCollection();
points.Add(new Point(xNew, yNew));
}
}
DataPoint lastDataPoint = enabledDataPoints[enabledDataPoints.Count - 1];
xPosition = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, lastDataPoint.InternalXValue);
yPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, lastDataPoint.InternalYValue);
points.Add(new Point(xPosition, yPosition));
marker = GetMarkerForDataPoint(chart, height, true, lastDataPoint, yPosition, lastDataPoint.InternalYValue > 0);
if (marker != null)
{
marker.AddToParent(labelCanvas, xPosition, yPosition, new Point(0.5, 0.5));
// Apply marker animation
if (animationEnabled)
{
if (lastDataPoint.Parent.Storyboard == null)
lastDataPoint.Parent.Storyboard = new Storyboard();
// Apply marker animation
lastDataPoint.Parent.Storyboard = AnimationHelper.ApplyOpacityAnimation(marker, currentDataSeries, lastDataPoint.Parent.Storyboard, 1, lastDataPoint.InternalOpacity * lastDataPoint.Parent.InternalOpacity);
}
}
xPosition = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, lastDataPoint.InternalXValue);
yPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, limitingYValue);
points.Add(new Point(xPosition, yPosition));
// get the faces
areaParams.Points = points;
areaParams.IsPositive = (lastDataPoint.InternalYValue > 0);
if (chart.View3D)
{
Canvas areaVisual3D = Get3DArea(currentDataSeries, ref faces, areaParams);
areaVisual3D.SetValue(Canvas.ZIndexProperty, GetAreaZIndex(xPosition, yPosition, areaParams.IsPositive));
areaCanvas.Children.Add(areaVisual3D);
series.Faces.VisualComponents.Add(areaVisual3D);
}
else
{
areaCanvas.Children.Add(Get2DArea(currentDataSeries, ref faces, areaParams));
series.Faces.VisualComponents.Add(areaCanvas);
}
if (!plankDrawn && chart.View3D && plotGroup.AxisY.InternalAxisMinimum < 0 && plotGroup.AxisY.InternalAxisMaximum > 0)
{
RectangularChartShapeParams columnParams = new RectangularChartShapeParams();
columnParams.BackgroundBrush = new SolidColorBrush(Color.FromArgb((Byte)255, (Byte)127, (Byte)127, (Byte)127));
columnParams.Lighting = true;
columnParams.Size = new Size(width, 1);
columnParams.Depth = depth3d;
Faces zeroPlank = ColumnChart.Get3DColumn(columnParams);
Panel zeroPlankVisual = zeroPlank.Visual as Panel;
zeroPlankVisual.IsHitTestVisible = false;
Double top = height - Graphics.ValueToPixelPosition(0, height, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, 0);
zeroPlankVisual.SetValue(Canvas.LeftProperty, (Double)0);
zeroPlankVisual.SetValue(Canvas.TopProperty, top);
zeroPlankVisual.SetValue(Canvas.ZIndexProperty, 0);
zeroPlankVisual.Opacity = 0.7;
areaCanvas.Children.Add(zeroPlankVisual);
}
series.Faces.Visual = visual;
series.Faces.LabelCanvas = labelCanvas;
}
RectangleGeometry clipRectangle = new RectangleGeometry();
clipRectangle.Rect = new Rect(0, -depth3d, width + depth3d, height + depth3d + chart.ChartArea.PLANK_THICKNESS);
areaCanvas.Clip = clipRectangle;
visual.Children.Add(areaCanvas);
// Clip the label canvas
clipRectangle = new RectangleGeometry();
Double clipLeft = 0;
Double clipTop = -depth3d;
Double clipWidth = width + depth3d;
Double clipHeight = height + depth3d + chart.ChartArea.PLANK_THICKNESS + 6;
GetClipCoordinates(chart, ref clipLeft, ref clipTop, ref clipWidth, ref clipHeight, minimumXValue, maximumXValue);
clipRectangle.Rect = new Rect(clipLeft, clipTop, clipWidth, clipHeight);
labelCanvas.Clip = clipRectangle;
visual.Children.Add(labelCanvas);
return visual;
}
internal static void GetClipCoordinates(Chart chart, ref Double clipLeft, ref Double clipTop, ref Double clipWidth, ref Double clipHeight, Double minimumXValue, Double maximumXValue)
{
Double tickLengthOfAxisX = 0, tickLengthOfPrimaryAxisY = 0, tickLengthOfSecondaryAxisY = 0;
Axis.CalculateTotalTickLength(chart, ref tickLengthOfAxisX, ref tickLengthOfPrimaryAxisY, ref tickLengthOfSecondaryAxisY);
if (minimumXValue >= chart.ChartArea.AxisX.InternalAxisMinimum)
{
clipLeft -= tickLengthOfPrimaryAxisY;
clipWidth += tickLengthOfPrimaryAxisY;
}
if (maximumXValue <= chart.ChartArea.AxisX.InternalAxisMaximum)
{
clipWidth += tickLengthOfSecondaryAxisY;
}
}
///
/// Get visual object for stacked area chart
///
/// Width of the PlotArea
/// Height of the PlotArea
/// PlotDetails
/// List of DataSeries with render as StackedArea chart
/// Chart
/// PlankDepth
/// Whether animation is enabled for chart
/// StackedArea chart canvas
internal static Canvas GetVisualObjectForStackedAreaChart(Double width, Double height, PlotDetails plotDetails, List seriesList, Chart chart, Double plankDepth, bool animationEnabled)
{
if (Double.IsNaN(width) || Double.IsNaN(height) || width <= 0 || height <= 0)
return null;
DataSeries currentDataSeries = null; // Current working DataSeries
Boolean plankDrawn = false;
Double depth3d = plankDepth / plotDetails.Layer3DCount * (chart.View3D ? 1 : 0);
Double visualOffset = depth3d * (plotDetails.SeriesDrawingIndex[seriesList[0]] + 1);
if (Double.IsNaN(visualOffset) || Double.IsInfinity(visualOffset))
return null;
Canvas visual = new Canvas() { Width = width, Height = height };
Canvas labelCanvas = new Canvas() { Width = width, Height = height };
Canvas areaCanvas = new Canvas() { Width = width, Height = height };
visual.SetValue(Canvas.TopProperty, visualOffset);
visual.SetValue(Canvas.LeftProperty, -visualOffset);
var plotgroups = (from series in seriesList where series.PlotGroup != null select series.PlotGroup);
if (plotgroups.Count() == 0)
return visual;
PlotGroup plotGroup = plotgroups.First();
Dictionary> dataPointValuesInStackedOrder = plotDetails.GetDataPointValuesInStackedOrder(plotGroup);
Dictionary> dataPointInStackedOrder = plotDetails.GetDataPointInStackOrder(plotGroup);
Double[] xValues = dataPointValuesInStackedOrder.Keys.ToArray();
Double minimumXValue = plotGroup.MinimumX;
Double maximumXValue = plotGroup.MaximumX;
Double limitingYValue = 0;
if (plotGroup.AxisY.InternalAxisMinimum > 0)
limitingYValue = (Double)plotGroup.AxisY.InternalAxisMinimum;
if (plotGroup.AxisY.InternalAxisMaximum < 0)
limitingYValue = (Double)plotGroup.AxisY.InternalAxisMaximum;
foreach (DataSeries ds in seriesList)
{
ds.Faces = null;
}
Double limitingYPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, limitingYValue);
Marker marker;
List curYValues;
List nextYValues;
List curDataPoints;
List nextDataPoints;
for (Int32 i = 0; i < xValues.Length - 1; i++)
{
curYValues = dataPointValuesInStackedOrder[xValues[i]];
nextYValues = dataPointValuesInStackedOrder[xValues[i + 1]];
Double curBase = limitingYValue;
Double nextBase = limitingYValue;
curDataPoints = dataPointInStackedOrder[xValues[i]];
nextDataPoints = dataPointInStackedOrder[xValues[i + 1]];
for (Int32 index = 0; index < curYValues.Count; index++)
{
if (index >= nextYValues.Count || index >= curYValues.Count || curDataPoints[index] == null || nextDataPoints[index] == null)
continue;
Double curXPosition = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, xValues[i]);
Double nextXPosition = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, xValues[i + 1]);
Double curYPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, curBase + curYValues[index]);
Double nextYPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, nextBase + nextYValues[index]);
Double curYBase = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, curBase);
Double nextYBase = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, nextBase);
Point intersect = GetIntersection(new Point(curXPosition, curYBase), new Point(nextXPosition, nextYBase),
new Point(curXPosition, curYPosition), new Point(nextXPosition, nextYPosition));
Boolean isTopOfStack = false;
if (index == curYValues.Count - 1)
isTopOfStack = true;
marker = GetMarkerForDataPoint(chart, height, isTopOfStack, curDataPoints[index], curYPosition, curDataPoints[index].InternalYValue > 0);
if (marker != null)
{
if (curDataPoints[index].Parent.Storyboard == null)
curDataPoints[index].Parent.Storyboard = new Storyboard();
currentDataSeries = curDataPoints[index].Parent;
marker.AddToParent(labelCanvas, curXPosition, curYPosition, new Point(0.5, 0.5));
// Apply marker animation
if (animationEnabled)
curDataPoints[index].Parent.Storyboard = AnimationHelper.ApplyOpacityAnimation(marker, currentDataSeries, curDataPoints[index].Parent.Storyboard, 1, curDataPoints[index].InternalOpacity * curDataPoints[index].Parent.InternalOpacity);
}
if (i + 1 == xValues.Length - 1)
{
if (index == nextYValues.Count - 1)
isTopOfStack = true;
marker = GetMarkerForDataPoint(chart, height, isTopOfStack, nextDataPoints[index], nextYPosition, nextDataPoints[index].InternalYValue > 0);
if (marker != null)
{
if (nextDataPoints[index].Parent.Storyboard == null)
nextDataPoints[index].Parent.Storyboard = new Storyboard();
currentDataSeries = nextDataPoints[index].Parent;
marker.AddToParent(labelCanvas, nextXPosition, nextYPosition, new Point(0.5, 0.5));
// Apply marker animation
if (animationEnabled)
nextDataPoints[index].Parent.Storyboard = AnimationHelper.ApplyOpacityAnimation(marker, currentDataSeries, nextDataPoints[index].Parent.Storyboard, 1, nextDataPoints[index].InternalOpacity * nextDataPoints[index].Parent.InternalOpacity);
}
}
if (curDataPoints[index].Parent.Faces == null)
{
curDataPoints[index].Parent.Faces = new Faces();
}
List pointSet = null;
if ((!Double.IsNaN(intersect.X) && !Double.IsInfinity(intersect.X)) && (intersect.X >= curXPosition && intersect.X <= nextXPosition))
{
List set1 = GeneratePointsCollection(curXPosition, curYPosition, curYBase, intersect.X, intersect.Y, intersect.Y, limitingYPosition);
List set2 = GeneratePointsCollection(intersect.X, intersect.Y, intersect.Y, nextXPosition, nextYPosition, nextYBase, limitingYPosition);
pointSet = set1;
pointSet.InsertRange(pointSet.Count, set2);
}
else
{
pointSet = GeneratePointsCollection(curXPosition, curYPosition, curYBase, nextXPosition, nextYPosition, nextYBase, limitingYPosition);
}
DataSeries series = curDataPoints[index].Parent;
Brush areaBrush = series.Color;
currentDataSeries = series;
PolygonalChartShapeParams areaParams = GetAreaParms(series, areaBrush, depth3d);
foreach (PointCollection points in pointSet)
{
areaParams.Points = points;
Faces faces = curDataPoints[index].Parent.Faces;
if (faces.Parts == null)
faces.Parts = new List();
if (chart.View3D)
{
Point centroid = GetCentroid(points);
areaParams.IsPositive = centroid.Y < limitingYPosition;
Canvas frontface = GetStacked3DAreaFrontFace(ref faces, areaParams);
Canvas sideface = GetStacked3DSideFaces(ref faces, areaParams);
sideface.SetValue(Canvas.ZIndexProperty, GetStackedAreaZIndex(centroid.X, centroid.Y, areaParams.IsPositive, index));
frontface.SetValue(Canvas.ZIndexProperty, 50000);
areaCanvas.Children.Add(sideface);
areaCanvas.Children.Add(frontface);
curDataPoints[index].Parent.Faces.VisualComponents.Add(sideface);
curDataPoints[index].Parent.Faces.VisualComponents.Add(frontface);
// Apply Animation
if (animationEnabled)
{
if (curDataPoints[index].Parent.Storyboard == null)
curDataPoints[index].Parent.Storyboard = new Storyboard();
Storyboard storyboard = curDataPoints[index].Parent.Storyboard;
// apply animation to the various faces
storyboard = ApplyStackedAreaAnimation(currentDataSeries, sideface, storyboard, (1.0 / seriesList.Count) * (seriesList.IndexOf(curDataPoints[index].Parent)) + 0.05, 1.0 / seriesList.Count);
storyboard = ApplyStackedAreaAnimation(currentDataSeries, frontface, storyboard, (1.0 / seriesList.Count) * (seriesList.IndexOf(curDataPoints[index].Parent)), 1.0 / seriesList.Count);
}
}
else
{
Canvas area2d = GetStacked2DArea(ref faces, areaParams);
areaCanvas.Children.Add(area2d);
curDataPoints[index].Parent.Faces.VisualComponents.Add(area2d);
if (animationEnabled)
{
if (curDataPoints[index].Parent.Storyboard == null)
curDataPoints[index].Parent.Storyboard = new Storyboard();
Storyboard storyboard = curDataPoints[index].Parent.Storyboard;
// apply animation to the various faces
storyboard = ApplyStackedAreaAnimation(currentDataSeries, area2d, storyboard, (1.0 / seriesList.Count) * (seriesList.IndexOf(curDataPoints[index].Parent)), 1.0 / seriesList.Count);
}
}
curDataPoints[index].Parent.Faces.Visual = visual;
}
curBase += curYValues[index];
nextBase += nextYValues[index];
}
}
if (!plankDrawn && chart.View3D && plotGroup.AxisY.InternalAxisMinimum < 0 && plotGroup.AxisY.InternalAxisMaximum > 0)
{
RectangularChartShapeParams columnParams = new RectangularChartShapeParams();
columnParams.BackgroundBrush = new SolidColorBrush(Color.FromArgb((Byte)255, (Byte)255, (Byte)255, (Byte)255));
columnParams.Lighting = true;
columnParams.Size = new Size(width, 1);
columnParams.Depth = depth3d;
Faces zeroPlank = ColumnChart.Get3DColumn(columnParams);
Panel zeroPlankVisual = zeroPlank.Visual as Panel;
zeroPlankVisual.IsHitTestVisible = false;
Double top = height - Graphics.ValueToPixelPosition(0, height, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, 0);
zeroPlankVisual.SetValue(Canvas.LeftProperty, (Double)0);
zeroPlankVisual.SetValue(Canvas.TopProperty, top);
zeroPlankVisual.SetValue(Canvas.ZIndexProperty, 0);
zeroPlankVisual.Opacity = 0.7;
visual.Children.Add(zeroPlankVisual);
}
RectangleGeometry clipRectangle = new RectangleGeometry();
clipRectangle.Rect = new Rect(0, -depth3d, width + depth3d, height + depth3d + chart.ChartArea.PLANK_THICKNESS);
areaCanvas.Clip = clipRectangle;
visual.Children.Add(areaCanvas);
// Clip the label canvas
clipRectangle = new RectangleGeometry();
Double clipLeft = 0;
Double clipTop = -depth3d;
Double clipWidth = width + depth3d;
Double clipHeight = height + depth3d + chart.ChartArea.PLANK_THICKNESS + 6;
GetClipCoordinates(chart, ref clipLeft, ref clipTop, ref clipWidth, ref clipHeight, minimumXValue, maximumXValue);
clipRectangle.Rect = new Rect(clipLeft, clipTop, clipWidth, clipHeight);
labelCanvas.Clip = clipRectangle;
visual.Children.Add(labelCanvas);
return visual;
}
///
/// Get visual object for stacked area100 chart
///
/// Width of the PlotArea
/// Height of the PlotArea
/// PlotDetails
/// List of DataSeries with render as StackedArea100 chart
/// Chart
/// PlankDepth
/// Whether animation is enabled for chart
/// StackedArea100 chart canvas
internal static Canvas GetVisualObjectForStackedArea100Chart(Double width, Double height, PlotDetails plotDetails, List seriesList, Chart chart, Double plankDepth, bool animationEnabled)
{
if (Double.IsNaN(width) || Double.IsNaN(height) || width <= 0 || height <= 0)
return null;
DataSeries currentDataSeries = null; // Current working DataSeries
Boolean plankDrawn = false;
Double depth3d = plankDepth / plotDetails.Layer3DCount * (chart.View3D ? 1 : 0);
Double visualOffset = depth3d * (plotDetails.SeriesDrawingIndex[seriesList[0]] + 1);
if (Double.IsNaN(visualOffset) || Double.IsInfinity(visualOffset))
return null;
Canvas visual = new Canvas() { Width = width, Height = height };
Canvas labelCanvas = new Canvas() { Width = width, Height = height };
Canvas areaCanvas = new Canvas() { Width = width, Height = height };
visual.SetValue(Canvas.TopProperty, visualOffset);
visual.SetValue(Canvas.LeftProperty, -visualOffset);
var plotgroups = (from series in seriesList where series.PlotGroup != null select series.PlotGroup);
if (plotgroups.Count() == 0)
return visual;
PlotGroup plotGroup = plotgroups.First();
Dictionary> dataPointValuesInStackedOrder = plotDetails.GetDataPointValuesInStackedOrder(plotGroup);
Dictionary> dataPointInStackedOrder = plotDetails.GetDataPointInStackOrder(plotGroup);
Double[] xValues = dataPointValuesInStackedOrder.Keys.ToArray();
Double limitingYValue = 0;
Double minimumXValue = plotGroup.MinimumX;
Double maximumXValue = plotGroup.MaximumX;
if (plotGroup.AxisY.InternalAxisMinimum > 0)
limitingYValue = (Double)plotGroup.AxisY.InternalAxisMinimum;
if (plotGroup.AxisY.InternalAxisMaximum < 0)
limitingYValue = (Double)plotGroup.AxisY.InternalAxisMaximum;
foreach (DataSeries ds in seriesList)
{
ds.Faces = null;
}
Double limitingYPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, limitingYValue);
Marker marker;
List curYValues;
List nextYValues;
List curDataPoints;
List nextDataPoints;
for (Int32 i = 0; i < xValues.Length - 1; i++)
{
curYValues = dataPointValuesInStackedOrder[xValues[i]];
nextYValues = dataPointValuesInStackedOrder[xValues[i + 1]];
Double curBase = limitingYValue;
Double nextBase = limitingYValue;
Double curAbsoluteSum = plotGroup.XWiseStackedDataList[xValues[i]].AbsoluteYValueSum;
Double nextAbsoluteSum = plotGroup.XWiseStackedDataList[xValues[i + 1]].AbsoluteYValueSum;
curDataPoints = dataPointInStackedOrder[xValues[i]];
nextDataPoints = dataPointInStackedOrder[xValues[i + 1]];
if (Double.IsNaN(curAbsoluteSum))
curAbsoluteSum = 1;
if (Double.IsNaN(nextAbsoluteSum))
nextAbsoluteSum = 1;
for (Int32 index = 0; index < curYValues.Count; index++)
{
if (index >= nextYValues.Count || index >= curYValues.Count || curDataPoints[index] == null || nextDataPoints[index] == null)
continue;
Double curPercentageY = curYValues[index] / curAbsoluteSum * 100;
Double nextPercentageY = nextYValues[index] / nextAbsoluteSum * 100;
if (Double.IsNaN(nextPercentageY) || Double.IsNaN(curPercentageY))
continue;
Double curXPosition = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, xValues[i]);
Double nextXPosition = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, xValues[i + 1]);
Double curYPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, curBase + curPercentageY);
Double nextYPosition = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, nextBase + nextPercentageY);
Double curYBase = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, curBase);
Double nextYBase = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, nextBase);
Point intersect = GetIntersection(new Point(curXPosition, curYBase), new Point(nextXPosition, nextYBase),
new Point(curXPosition, curYPosition), new Point(nextXPosition, nextYPosition));
marker = GetMarkerForDataPoint(chart, height, false, curDataPoints[index], curYPosition, curDataPoints[index].InternalYValue > 0);
if (marker != null)
{
if (curDataPoints[index].Parent.Storyboard == null)
curDataPoints[index].Parent.Storyboard = new Storyboard();
currentDataSeries = curDataPoints[index].Parent;
marker.AddToParent(labelCanvas, curXPosition, curYPosition, new Point(0.5, 0.5));
// Apply marker animation
if (animationEnabled)
curDataPoints[index].Parent.Storyboard = AnimationHelper.ApplyOpacityAnimation(marker, currentDataSeries, curDataPoints[index].Parent.Storyboard, 1, curDataPoints[index].InternalOpacity * curDataPoints[index].Parent.InternalOpacity);
}
if (i + 1 == xValues.Length - 1)
{
marker = GetMarkerForDataPoint(chart, height, false, nextDataPoints[index], nextYPosition, nextDataPoints[index].InternalYValue > 0);
if (marker != null)
{
if (curDataPoints[index].Parent.Storyboard == null)
curDataPoints[index].Parent.Storyboard = new Storyboard();
currentDataSeries = curDataPoints[index].Parent;
marker.AddToParent(labelCanvas, nextXPosition, nextYPosition, new Point(0.5, 0.5));
// Apply marker animation
if (animationEnabled)
nextDataPoints[index].Parent.Storyboard = AnimationHelper.ApplyOpacityAnimation(marker, currentDataSeries, nextDataPoints[index].Parent.Storyboard, 1, nextDataPoints[index].InternalOpacity * nextDataPoints[index].Parent.InternalOpacity);
}
}
if (curDataPoints[index].Parent.Faces == null)
{
curDataPoints[index].Parent.Faces = new Faces();
}
List pointSet = null;
if ((!Double.IsNaN(intersect.X) && !Double.IsInfinity(intersect.X)) && (intersect.X >= curXPosition && intersect.X <= nextXPosition))
{
List set1 = GeneratePointsCollection(curXPosition, curYPosition, curYBase, intersect.X, intersect.Y, intersect.Y, limitingYPosition);
List set2 = GeneratePointsCollection(intersect.X, intersect.Y, intersect.Y, nextXPosition, nextYPosition, nextYBase, limitingYPosition);
pointSet = set1;
pointSet.InsertRange(pointSet.Count, set2);
}
else
{
pointSet = GeneratePointsCollection(curXPosition, curYPosition, curYBase, nextXPosition, nextYPosition, nextYBase, limitingYPosition);
}
DataSeries series = curDataPoints[index].Parent;
Brush areaBrush = series.Color;
currentDataSeries = series;
PolygonalChartShapeParams areaParams = GetAreaParms(series, areaBrush, depth3d);
Faces faces = curDataPoints[index].Parent.Faces;
if (faces.Parts == null)
faces.Parts = new List();
foreach (PointCollection points in pointSet)
{
areaParams.Points = points;
if (chart.View3D)
{
Point centroid = GetCentroid(points);
areaParams.IsPositive = centroid.Y < limitingYPosition;
Canvas frontface = GetStacked3DAreaFrontFace(ref faces, areaParams);
Canvas sideface = GetStacked3DSideFaces(ref faces, areaParams);
sideface.SetValue(Canvas.ZIndexProperty, GetStackedAreaZIndex(centroid.X, centroid.Y, areaParams.IsPositive, index));
frontface.SetValue(Canvas.ZIndexProperty, 50000);
areaCanvas.Children.Add(sideface);
areaCanvas.Children.Add(frontface);
curDataPoints[index].Parent.Faces.VisualComponents.Add(sideface);
curDataPoints[index].Parent.Faces.VisualComponents.Add(frontface);
// Apply Animation
if (animationEnabled)
{
if (curDataPoints[index].Parent.Storyboard == null)
curDataPoints[index].Parent.Storyboard = new Storyboard();
Storyboard storyboard = curDataPoints[index].Parent.Storyboard;
// apply animation to the various faces
storyboard = ApplyStackedAreaAnimation(currentDataSeries, sideface, storyboard, (1.0 / seriesList.Count) * (seriesList.IndexOf(curDataPoints[index].Parent)) + 0.05, 1.0 / seriesList.Count);
storyboard = ApplyStackedAreaAnimation(currentDataSeries, frontface, storyboard, (1.0 / seriesList.Count) * (seriesList.IndexOf(curDataPoints[index].Parent)), 1.0 / seriesList.Count);
}
}
else
{
Canvas area2d = Get2DArea(currentDataSeries, ref faces, areaParams);
areaCanvas.Children.Add(area2d);
curDataPoints[index].Parent.Faces.VisualComponents.Add(area2d);
if (animationEnabled)
{
if (curDataPoints[index].Parent.Storyboard == null)
curDataPoints[index].Parent.Storyboard = new Storyboard();
Storyboard storyboard = curDataPoints[index].Parent.Storyboard;
// apply animation to the various faces
storyboard = ApplyStackedAreaAnimation(currentDataSeries, area2d, storyboard, (1.0 / seriesList.Count) * (seriesList.IndexOf(curDataPoints[index].Parent)), 1.0 / seriesList.Count);
}
}
curDataPoints[index].Parent.Faces.Visual = visual;
}
curBase += curPercentageY;
nextBase += nextPercentageY;
}
}
if (!plankDrawn && chart.View3D && plotGroup.AxisY.InternalAxisMinimum < 0 && plotGroup.AxisY.InternalAxisMaximum > 0)
{
RectangularChartShapeParams columnParams = new RectangularChartShapeParams();
columnParams.BackgroundBrush = new SolidColorBrush(Color.FromArgb((Byte)255, (Byte)255, (Byte)255, (Byte)255));
columnParams.Lighting = true;
columnParams.Size = new Size(width, 1);
columnParams.Depth = depth3d;
Faces zeroPlank = ColumnChart.Get3DColumn(columnParams);
Panel zeroPlankVisual = zeroPlank.Visual as Panel;
zeroPlankVisual.IsHitTestVisible = false;
Double top = height - Graphics.ValueToPixelPosition(0, height, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, 0);
zeroPlankVisual.SetValue(Canvas.LeftProperty, (Double)0);
zeroPlankVisual.SetValue(Canvas.TopProperty, top);
zeroPlankVisual.SetValue(Canvas.ZIndexProperty, 0);
zeroPlankVisual.Opacity = 0.7;
visual.Children.Add(zeroPlankVisual);
}
RectangleGeometry clipRectangle = new RectangleGeometry();
clipRectangle.Rect = new Rect(0, -depth3d, width + depth3d, height + depth3d + chart.ChartArea.PLANK_THICKNESS);
areaCanvas.Clip = clipRectangle;
visual.Children.Add(areaCanvas);
// Clip the label canvas
clipRectangle = new RectangleGeometry();
Double clipLeft = 0;
Double clipTop = -depth3d;
Double clipWidth = width + depth3d;
Double clipHeight = height + depth3d + chart.ChartArea.PLANK_THICKNESS + 6;
GetClipCoordinates(chart, ref clipLeft, ref clipTop, ref clipWidth, ref clipHeight, minimumXValue, maximumXValue);
clipRectangle.Rect = new Rect(clipLeft, clipTop, clipWidth, clipHeight);
labelCanvas.Clip = clipRectangle;
visual.Children.Add(labelCanvas);
return visual;
}
///
/// Get centroid of some points
///
/// Point collection
/// Point
internal static Point GetCentroid(PointCollection points)
{
Double sumX = 0;
Double sumY = 0;
foreach (Point point in points)
{
sumX += point.X;
sumY += point.Y;
}
return new Point(sumX / points.Count, sumY / points.Count);
}
///
/// Generate points collection
///
/// Current X position
/// Current Y position
/// Current base position
/// Next X position
/// Next Y position
/// Next base position
/// Limiting Y position
/// List of point collection
internal static List GeneratePointsCollection(Double curX, Double curY, Double curBase, Double nextX, Double nextY, Double nextBase, Double limitingY)
{
List pointsSet = new List();
PointCollection points;
if (curY < limitingY && nextY < limitingY && curBase > limitingY && nextBase < limitingY)
{
points = new PointCollection();
points.Add(new Point(curX, limitingY));
points.Add(new Point(curX, curY));
points.Add(new Point(nextX, nextY));
points.Add(new Point(nextX, nextBase));
Double midX = Graphics.ConvertScale(curBase, nextBase, limitingY, curX, nextX);
points.Add(new Point(midX, limitingY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(curX, limitingY));
points.Add(new Point(midX, limitingY));
points.Add(new Point(curX, curBase));
pointsSet.Add(points);
}
else if (curY < limitingY && nextY > limitingY && curBase > limitingY && nextBase > limitingY)
{
points = new PointCollection();
points.Add(new Point(curX, limitingY));
points.Add(new Point(curX, curY));
Double midX = Graphics.ConvertScale(curY, nextY, limitingY, curX, nextX);
points.Add(new Point(midX, limitingY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(curX, curBase));
points.Add(new Point(curX, limitingY));
points.Add(new Point(midX, limitingY));
points.Add(new Point(nextX, nextY));
points.Add(new Point(nextX, nextBase));
pointsSet.Add(points);
}
else if (curY < limitingY && nextY < limitingY && curBase < limitingY && nextBase > limitingY)
{
points = new PointCollection();
Double midX = Graphics.ConvertScale(curBase, nextBase, limitingY, curX, nextX);
points.Add(new Point(midX, limitingY));
points.Add(new Point(curX, curBase));
points.Add(new Point(curX, curY));
points.Add(new Point(nextX, nextY));
points.Add(new Point(nextX, limitingY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(midX, limitingY));
points.Add(new Point(nextX, limitingY));
points.Add(new Point(nextX, nextBase));
pointsSet.Add(points);
}
else if (curY > limitingY && nextY < limitingY && curBase > limitingY && nextBase > limitingY)
{
points = new PointCollection();
Double midX = Graphics.ConvertScale(curY, nextY, limitingY, curX, nextX);
points.Add(new Point(midX, limitingY));
points.Add(new Point(nextX, nextY));
points.Add(new Point(nextX, limitingY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(curX, curBase));
points.Add(new Point(curX, curY));
points.Add(new Point(midX, limitingY));
points.Add(new Point(nextX, limitingY));
points.Add(new Point(nextX, nextY));
pointsSet.Add(points);
}
else if ((curY < limitingY && nextY < limitingY && curBase > limitingY && nextBase > limitingY) ||
(curY > limitingY && nextY > limitingY && curBase < limitingY && nextBase < limitingY))
{
points = new PointCollection();
points.Add(new Point(curX, limitingY));
points.Add(new Point(curX, curY));
points.Add(new Point(nextX, nextY));
points.Add(new Point(nextX, limitingY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(curX, curBase));
points.Add(new Point(curX, limitingY));
points.Add(new Point(nextX, limitingY));
points.Add(new Point(nextX, nextBase));
pointsSet.Add(points);
}
else if (curY < limitingY && nextY > limitingY && curBase < limitingY && nextBase > limitingY)
{
points = new PointCollection();
points.Add(new Point(curX, curBase));
points.Add(new Point(curX, curY));
Double midX1 = Graphics.ConvertScale(curY, nextY, limitingY, curX, nextX);
points.Add(new Point(midX1, limitingY));
Double midX2 = Graphics.ConvertScale(curBase, nextBase, limitingY, curX, nextX);
points.Add(new Point(midX2, limitingY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(midX2, limitingY));
points.Add(new Point(midX1, limitingY));
points.Add(new Point(nextX, nextY));
points.Add(new Point(nextX, nextBase));
pointsSet.Add(points);
}
else if (curY > limitingY && nextY < limitingY && curBase > limitingY && nextBase < limitingY)
{
points = new PointCollection();
points.Add(new Point(curX, curBase));
points.Add(new Point(curX, curY));
Double midX1 = Graphics.ConvertScale(curY, nextY, limitingY, curX, nextX);
points.Add(new Point(midX1, limitingY));
Double midX2 = Graphics.ConvertScale(curBase, nextBase, limitingY, curX, nextX);
points.Add(new Point(midX2, limitingY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(midX2, limitingY));
points.Add(new Point(midX1, limitingY));
points.Add(new Point(nextX, nextY));
points.Add(new Point(nextX, nextBase));
pointsSet.Add(points);
}
else if (curY > limitingY && nextY < limitingY && curBase < limitingY && nextBase < limitingY)
{
points = new PointCollection();
Double midX = Graphics.ConvertScale(curY, nextY, limitingY, curX, nextX);
points.Add(new Point(midX, limitingY));
points.Add(new Point(curX, limitingY));
points.Add(new Point(curX, curBase));
points.Add(new Point(nextX, nextBase));
points.Add(new Point(nextX, nextY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(curX, curY));
points.Add(new Point(curX, limitingY));
points.Add(new Point(midX, limitingY));
pointsSet.Add(points);
}
else if (curY > limitingY && nextY > limitingY && curBase < limitingY && nextBase > limitingY)
{
points = new PointCollection();
points.Add(new Point(curX, limitingY));
points.Add(new Point(curX, curBase));
Double midX = Graphics.ConvertScale(curBase, nextBase, limitingY, curX, nextX);
points.Add(new Point(midX, limitingY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(curX, curY));
points.Add(new Point(curX, limitingY));
points.Add(new Point(midX, limitingY));
points.Add(new Point(nextX, nextBase));
points.Add(new Point(nextX, nextY));
pointsSet.Add(points);
}
else if (curY < limitingY && nextY > limitingY && curBase < limitingY && nextBase < limitingY)
{
points = new PointCollection();
Double midX = Graphics.ConvertScale(curY, nextY, limitingY, curX, nextX);
points.Add(new Point(midX, limitingY));
points.Add(new Point(curX, curY));
points.Add(new Point(curX, curBase));
points.Add(new Point(nextX, nextBase));
points.Add(new Point(nextX, limitingY));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(midX, limitingY));
points.Add(new Point(nextX, limitingY));
points.Add(new Point(nextX, nextY));
pointsSet.Add(points);
}
else if (curY > limitingY && nextY > limitingY && curBase > limitingY && nextBase < limitingY)
{
points = new PointCollection();
Double midX = Graphics.ConvertScale(curBase, nextBase, limitingY, curX, nextX);
points.Add(new Point(curX, curY));
points.Add(new Point(curX, curBase));
points.Add(new Point(midX, limitingY));
points.Add(new Point(nextX, limitingY));
points.Add(new Point(nextX, nextBase));
pointsSet.Add(points);
points = new PointCollection();
points.Add(new Point(midX, limitingY));
points.Add(new Point(nextX, nextY));
points.Add(new Point(nextX, limitingY));
pointsSet.Add(points);
}
else if (curY > curBase && nextY > nextBase)
{
points = new PointCollection();
points.Add(new Point(curX, curY));
points.Add(new Point(curX, curBase));
points.Add(new Point(nextX, nextBase));
points.Add(new Point(nextX, nextY));
pointsSet.Add(points);
}
else
{
points = new PointCollection();
points.Add(new Point(curX, curBase));
points.Add(new Point(curX, curY));
points.Add(new Point(nextX, nextY));
points.Add(new Point(nextX, nextBase));
pointsSet.Add(points);
}
return pointsSet;
}
///
/// Get crossing point with smallestX value
///
/// Current X position
/// List of current YValues
/// Next X position
/// List of next YValues
/// Current base position
/// Next base position
/// Start index
/// Point
internal static Point GetCrossingPointWithSmallestX(Double curX, List curYValues, Double nextX, List nextYValues, Double curBase, Double nextBase, Int32 startIndex)
{
Point crossingPoint = new Point(Double.MaxValue, Double.MaxValue);
for (Int32 index = startIndex; index < curYValues.Count; index++)
{
Point newPoint = GetIntersection(new Point(curX, curBase), new Point(nextX, nextBase),
new Point(curX, curYValues[index]), new Point(nextX, nextYValues[index]));
if (newPoint.X < crossingPoint.X)
crossingPoint = newPoint;
}
if (crossingPoint.X == Double.MaxValue)
return new Point(Double.NaN, Double.NaN);
return crossingPoint;
}
///
/// Returns slope value
///
/// X1
/// Y1
/// X2
/// Y2
/// Double
internal static Double GetSlope(Double x1, Double y1, Double x2, Double y2)
{
return (y2 - y1) / (x2 - x1);
}
///
/// Returns intercept value
///
/// X1
/// Y1
/// X2
/// Y2
/// Double
internal static Double GetIntercept(Double x1, Double y1, Double x2, Double y2)
{
return y1 - x1 * GetSlope(x1, y1, x2, y2);
}
///
/// Get intersection point between two lines
///
/// Line 1 dateTime position
/// Line 1 end position
/// Line 2 stsrt position
/// Line 2 end position
/// Point
internal static Point GetIntersection(Point Line1Start, Point Line1End, Point Line2Start, Point Line2End)
{
Double line1Slope = GetSlope(Line1Start.X, Line1Start.Y, Line1End.X, Line1End.Y);
Double line2Slope = GetSlope(Line2Start.X, Line2Start.Y, Line2End.X, Line2End.Y);
Double line1Intercept = GetIntercept(Line1Start.X, Line1Start.Y, Line1End.X, Line1End.Y);
Double line2Intercept = GetIntercept(Line2Start.X, Line2Start.Y, Line2End.X, Line2End.Y);
Double Y = (line1Slope * line2Intercept - line2Slope * line1Intercept) / (line1Slope - line2Slope);
Double X = (line2Intercept - line1Intercept) / (line1Slope - line2Slope);
return new Point(X, Y);
}
///
/// Get bounds from point collection
///
/// Collection of points
/// Rect
internal static Rect GetBounds(PointCollection points)
{
Double minX = Double.MaxValue, minY = Double.MaxValue, maxX = Double.MinValue, maxY = Double.MinValue;
foreach (Point point in points)
{
minX = Math.Min(minX, point.X);
minY = Math.Min(minY, point.Y);
maxX = Math.Max(maxX, point.X);
maxY = Math.Max(maxY, point.Y);
}
return new Rect(minX, minY, Math.Abs(maxX - minX), Math.Abs(maxY - minY));
}
///
/// Returns visual for 2DArea
///
/// Faces
/// Area parameters
/// Canvas
internal static Canvas Get2DArea(DataSeries currentDataSeries, ref Faces faces, PolygonalChartShapeParams areaParams)
{
if (faces.Parts == null)
faces.Parts = new List();
Canvas visual = new Canvas();
visual.Width = areaParams.Size.Width;
visual.Height = areaParams.Size.Height;
Polygon polygon = new Polygon() { Tag = new ElementData() { Element = areaParams.TagReference, VisualElementName = "AreaBase" } };
faces.Parts.Add(polygon);
polygon.Fill = areaParams.Lighting ? Graphics.GetLightingEnabledBrush(areaParams.Background, "Linear", null) : areaParams.Background;
polygon.StrokeDashArray = areaParams.BorderStyle != null ? ExtendedGraphics.CloneCollection(areaParams.BorderStyle) : areaParams.BorderStyle;
polygon.StrokeThickness = areaParams.BorderThickness;
if(polygon.StrokeThickness > 0)
polygon.Stroke = areaParams.BorderColor;
polygon.StrokeMiterLimit = 1;
polygon.Points = areaParams.Points;
Rect polygonBounds = GetBounds(areaParams.Points);
polygon.Stretch = Stretch.Fill;
polygon.Width = polygonBounds.Width;
polygon.Height = polygonBounds.Height;
polygon.SetValue(Canvas.TopProperty, polygonBounds.Y);
polygon.SetValue(Canvas.LeftProperty, polygonBounds.X);
// apply area animation
if (areaParams.AnimationEnabled)
{
// apply animation to the polygon that was used to create the area
areaParams.Storyboard = ApplyAreaAnimation(currentDataSeries, polygon, areaParams.Storyboard, areaParams.IsPositive, 0);
}
visual.Children.Add(polygon);
if (areaParams.Bevel)
{
for (int i = 0; i < areaParams.Points.Count - 1; i++)
{
if (areaParams.Points[i].X == areaParams.Points[i + 1].X)
continue;
Double m = GetSlope(areaParams.Points[i].X, areaParams.Points[i].Y, areaParams.Points[i + 1].X, areaParams.Points[i + 1].Y);
Double c = GetIntercept(areaParams.Points[i].X, areaParams.Points[i].Y, areaParams.Points[i + 1].X, areaParams.Points[i + 1].Y);
c = c + (areaParams.IsPositive ? 1 : -1) * 4;
Point newPt1 = new Point(areaParams.Points[i].X, m * areaParams.Points[i].X + c);
Point newPt2 = new Point(areaParams.Points[i + 1].X, m * areaParams.Points[i + 1].X + c);
PointCollection points = new PointCollection();
points.Add(areaParams.Points[i]);
points.Add(areaParams.Points[i + 1]);
points.Add(newPt2);
points.Add(newPt1);
Polygon bevel = new Polygon() { Tag = new ElementData() { Element = areaParams.TagReference, VisualElementName = "Bevel" } };
bevel.Points = points;
bevel.Fill = Graphics.GetBevelTopBrush(areaParams.Background);
if (areaParams.AnimationEnabled)
{
areaParams.Storyboard = CreateOpacityAnimation(currentDataSeries, areaParams.Storyboard, bevel, 1, 1, 1);
bevel.Opacity = 0;
}
faces.Parts.Add(bevel);
visual.Children.Add(bevel);
}
}
//faces.VisualComponents.Add(visual);
return visual;
}
///
/// Get visual of Area 3D
///
/// Faces
/// AreaParams
/// Canvas
internal static Canvas Get3DArea(DataSeries currentDataSeries, ref Faces faces, PolygonalChartShapeParams areaParams)
{
Canvas visual = new Canvas();
visual.Width = areaParams.Size.Width;
visual.Height = areaParams.Size.Height;
Point centroid;
Brush sideBrush = areaParams.Lighting ? Graphics.GetRightFaceBrush(areaParams.Background) : areaParams.Background;
Brush topBrush = areaParams.Lighting ? Graphics.GetTopFaceBrush(areaParams.Background) : areaParams.Background;
Int32 pointIndexLimit = areaParams.IsPositive ? areaParams.Points.Count - 1 : areaParams.Points.Count;
Canvas polygonSet = new Canvas();
Rect size = GetBounds(areaParams.Points);
polygonSet.Width = size.Width + areaParams.Depth3D;
polygonSet.Height = size.Height + areaParams.Depth3D;
polygonSet.SetValue(Canvas.TopProperty, size.Top - areaParams.Depth3D);
polygonSet.SetValue(Canvas.LeftProperty, size.Left);
visual.Children.Add(polygonSet);
for (Int32 i = 0; i < pointIndexLimit; i++)
{
Polygon sides = new Polygon() { Tag = new ElementData() { Element = areaParams.TagReference }};
PointCollection points = new PointCollection();
Int32 index1 = i % areaParams.Points.Count;
Int32 index2 = (i + 1) % areaParams.Points.Count;
points.Add(areaParams.Points[index1]);
points.Add(areaParams.Points[index2]);
points.Add(new Point(areaParams.Points[index2].X + areaParams.Depth3D, areaParams.Points[index2].Y - areaParams.Depth3D));
points.Add(new Point(areaParams.Points[index1].X + areaParams.Depth3D, areaParams.Points[index1].Y - areaParams.Depth3D));
sides.Points = points;
centroid = GetCentroid(points);
Int32 zindex = GetAreaZIndex(centroid.X, centroid.Y, areaParams.IsPositive);
sides.SetValue(Canvas.ZIndexProperty, zindex);
if (i == (areaParams.Points.Count - 2))
{
sides.Fill = sideBrush;
(sides.Tag as ElementData).VisualElementName = "Side";
}
else
{
sides.Fill = topBrush;
(sides.Tag as ElementData).VisualElementName = "Top";
}
sides.StrokeDashArray = areaParams.BorderStyle != null ? ExtendedGraphics.CloneCollection(areaParams.BorderStyle) : areaParams.BorderStyle;
sides.StrokeThickness = areaParams.BorderThickness;
if(sides.StrokeThickness > 0)
sides.Stroke = areaParams.BorderColor;
sides.StrokeMiterLimit = 1;
Rect sidesBounds = GetBounds(points);
sides.Stretch = Stretch.Fill;
sides.Width = sidesBounds.Width;
sides.Height = sidesBounds.Height;
sides.SetValue(Canvas.TopProperty, sidesBounds.Y - (size.Top - areaParams.Depth3D));
sides.SetValue(Canvas.LeftProperty, sidesBounds.X - size.X);
faces.Parts.Add(sides);
polygonSet.Children.Add(sides);
}
Polygon polygon = new Polygon() { Tag = new ElementData() { Element = areaParams.TagReference, VisualElementName = "AreaBase" } };
faces.Parts.Add(polygon);
centroid = GetCentroid(areaParams.Points);
polygon.SetValue(Canvas.ZIndexProperty, (Int32)centroid.Y + 1000);
polygon.Fill = areaParams.Lighting ? Graphics.GetFrontFaceBrush(areaParams.Background) : areaParams.Background;
polygon.StrokeDashArray = areaParams.BorderStyle != null ? ExtendedGraphics.CloneCollection(areaParams.BorderStyle) : areaParams.BorderStyle;
polygon.StrokeThickness = areaParams.BorderThickness;
if(polygon.StrokeThickness > 0)
polygon.Stroke = areaParams.BorderColor;
polygon.StrokeMiterLimit = 1;
polygon.Points = areaParams.Points;
polygon.Stretch = Stretch.Fill;
polygon.Width = size.Width;
polygon.Height = size.Height;
polygon.SetValue(Canvas.TopProperty, areaParams.Depth3D);
polygon.SetValue(Canvas.LeftProperty, 0.0);
// apply area animation
if (areaParams.AnimationEnabled)
{
// apply animation to the entire canvas that was used to create the area
areaParams.Storyboard = ApplyAreaAnimation(currentDataSeries, polygonSet, areaParams.Storyboard, areaParams.IsPositive, 0);
}
polygonSet.Children.Add(polygon);
return visual;
}
///
/// Get visual for StackedArea 2D
///
/// Faces
/// Area parameters
/// Canvas
internal static Canvas GetStacked2DArea(ref Faces faces, PolygonalChartShapeParams areaParams)
{
if (faces.Parts == null)
faces.Parts = new List();
Canvas visual = new Canvas();
visual.Width = areaParams.Size.Width;
visual.Height = areaParams.Size.Height;
Polygon polygon = new Polygon() { Tag = new ElementData() { Element = areaParams.TagReference, VisualElementName = "AreaBase" } };
faces.Parts.Add(polygon);
polygon.Fill = areaParams.Lighting ? Graphics.GetLightingEnabledBrush(areaParams.Background, "Linear", null) : areaParams.Background;
polygon.StrokeDashArray = areaParams.BorderStyle != null ? ExtendedGraphics.CloneCollection(areaParams.BorderStyle) : areaParams.BorderStyle;
polygon.StrokeThickness = areaParams.BorderThickness;
if(polygon.StrokeThickness > 0)
polygon.Stroke = areaParams.BorderColor;
polygon.StrokeMiterLimit = 1;
polygon.Points = areaParams.Points;
Rect polygonBounds = GetBounds(areaParams.Points);
polygon.Stretch = Stretch.Fill;
polygon.Width = polygonBounds.Width;
polygon.Height = polygonBounds.Height;
polygon.SetValue(Canvas.TopProperty, polygonBounds.Y);
polygon.SetValue(Canvas.LeftProperty, polygonBounds.X);
visual.Children.Add(polygon);
if (areaParams.Bevel)
{
for (int i = 0; i < areaParams.Points.Count - 1; i++)
{
if (areaParams.Points[i].X == areaParams.Points[i + 1].X)
continue;
Double m = GetSlope(areaParams.Points[i].X, areaParams.Points[i].Y, areaParams.Points[i + 1].X, areaParams.Points[i + 1].Y);
Double c = GetIntercept(areaParams.Points[i].X, areaParams.Points[i].Y, areaParams.Points[i + 1].X, areaParams.Points[i + 1].Y);
c = c + (areaParams.IsPositive ? 1 : -1) * 4;
Point newPt1 = new Point(areaParams.Points[i].X, m * areaParams.Points[i].X + c);
Point newPt2 = new Point(areaParams.Points[i + 1].X, m * areaParams.Points[i + 1].X + c);
PointCollection points = new PointCollection();
points.Add(areaParams.Points[i]);
points.Add(areaParams.Points[i + 1]);
points.Add(newPt2);
points.Add(newPt1);
Polygon bevel = new Polygon() { Tag = new ElementData() { Element = areaParams.TagReference, VisualElementName = "Bevel" } };
bevel.Points = points;
bevel.Fill = Graphics.GetBevelTopBrush(areaParams.Background);
faces.Parts.Add(bevel);
visual.Children.Add(bevel);
}
}
return visual;
}
///
/// Get Stacked3DArea front face
///
/// Faces
/// Area parameters
/// Canvas
internal static Canvas GetStacked3DAreaFrontFace(ref Faces faces, PolygonalChartShapeParams areaParams)
{
Polygon polygon = new Polygon() { Tag = new ElementData() { Element = areaParams.TagReference, VisualElementName = "AreaBase" } };
faces.Parts.Add(polygon);
Point centroid = GetCentroid(areaParams.Points);
Rect size = GetBounds(areaParams.Points);
polygon.SetValue(Canvas.ZIndexProperty, (Int32)centroid.Y + 1000);
polygon.Fill = areaParams.Lighting ? Graphics.GetFrontFaceBrush(areaParams.Background) : areaParams.Background;
polygon.StrokeDashArray = areaParams.BorderStyle != null ? ExtendedGraphics.CloneCollection(areaParams.BorderStyle) : areaParams.BorderStyle;
polygon.StrokeThickness = areaParams.BorderThickness;
if(polygon.StrokeThickness > 0)
polygon.Stroke = areaParams.BorderColor;
polygon.StrokeMiterLimit = 1;
polygon.Points = areaParams.Points;
polygon.Stretch = Stretch.Fill;
polygon.Width = size.Width;
polygon.Height = size.Height;
polygon.SetValue(Canvas.TopProperty, areaParams.Depth3D);
polygon.SetValue(Canvas.LeftProperty, 0.0);
Canvas polygonSet = new Canvas() { Tag = new ElementData() { Element = areaParams.TagReference } };
polygonSet.Width = size.Width + areaParams.Depth3D;
polygonSet.Height = size.Height + areaParams.Depth3D;
polygonSet.SetValue(Canvas.TopProperty, size.Top - areaParams.Depth3D);
polygonSet.SetValue(Canvas.LeftProperty, size.Left);
polygonSet.Children.Add(polygon);
return polygonSet;
}
#endregion
#region Internal Events And Delegates
#endregion
#region Data
#endregion
}
}