xaml-sdk/ChartView/WPF/Animations/ChartAnimationUtilities.cs

896 строки
34 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Telerik.Charting;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.ChartView;
namespace Animations
{
public static class ChartAnimationUtilities
{
public static readonly DependencyProperty CartesianAnimationProperty = DependencyProperty.RegisterAttached(
"CartesianAnimation",
typeof(CartesianAnimation),
typeof(ChartAnimationUtilities),
new PropertyMetadata(CartesianAnimation.None, CartesianAnimationChanged));
public static readonly DependencyProperty PieAnimationProperty = DependencyProperty.RegisterAttached(
"PieAnimation",
typeof(PieAnimation),
typeof(ChartAnimationUtilities),
new PropertyMetadata(PieAnimation.None, PieAnimationChanged));
private static readonly DependencyProperty RunningAnimationsCountProperty = DependencyProperty.RegisterAttached(
"RunningAnimationsCount",
typeof(int),
typeof(ChartAnimationUtilities),
new PropertyMetadata(0));
private static readonly DependencyProperty StartAngleProperty = DependencyProperty.RegisterAttached(
"StartAngle",
typeof(double),
typeof(ChartAnimationUtilities),
new PropertyMetadata(double.NaN, StartAngleChanged));
private static readonly DependencyProperty SweepAngleProperty = DependencyProperty.RegisterAttached(
"SweepAngle",
typeof(double),
typeof(ChartAnimationUtilities),
new PropertyMetadata(double.NaN, SweepAngleChanged));
private static readonly DependencyProperty SeriesScaleTransformXProperty = DependencyProperty.RegisterAttached(
"SeriesScaleTransformX",
typeof(double),
typeof(ChartAnimationUtilities),
new PropertyMetadata(double.NaN, SeriesScaleTransformXChanged));
private static readonly DependencyProperty SeriesScaleTransformYProperty = DependencyProperty.RegisterAttached(
"SeriesScaleTransformY",
typeof(double),
typeof(ChartAnimationUtilities),
new PropertyMetadata(double.NaN, SeriesScaleTransformYChanged));
private static readonly DependencyProperty BarScaleTransformXProperty = DependencyProperty.RegisterAttached(
"BarScaleTransformX",
typeof(double),
typeof(ChartAnimationUtilities),
new PropertyMetadata(double.NaN, BarScaleTransformXChanged));
private static readonly DependencyProperty BarScaleTransformYProperty = DependencyProperty.RegisterAttached(
"BarScaleTransformY",
typeof(double),
typeof(ChartAnimationUtilities),
new PropertyMetadata(double.NaN, BarScaleTransformYChanged));
private static readonly DependencyProperty SliceScaleTransformXYProperty = DependencyProperty.RegisterAttached(
"SliceScaleTransformXY",
typeof(double),
typeof(ChartAnimationUtilities),
new PropertyMetadata(double.NaN, SliceScaleTransformXYChanged));
private static readonly DependencyProperty SeriesTranslateTransformYProperty = DependencyProperty.RegisterAttached(
"SeriesTranslateTransformY",
typeof(double),
typeof(ChartAnimationUtilities),
new PropertyMetadata(double.NaN, SeriesTranslateTransformYChanged));
private const int DelayInMilliseconds = 1000;
private const int PieDelayInMilliseconds = 300;
private const int BarDelayInMilliseconds = 200;
private static Duration AnimationDuration = new Duration(TimeSpan.FromMilliseconds(1500));
private static Duration PieSliceAnimationDuration = new Duration(TimeSpan.FromMilliseconds(500));
private static Duration BarAnimationDuration = new Duration(TimeSpan.FromMilliseconds(500));
private static object locker = new object();
public static CartesianAnimation GetCartesianAnimation(DependencyObject obj)
{
return (CartesianAnimation)obj.GetValue(CartesianAnimationProperty);
}
public static void SetCartesianAnimation(DependencyObject obj, CartesianAnimation value)
{
obj.SetValue(CartesianAnimationProperty, value);
}
public static PieAnimation GetPieAnimation(DependencyObject obj)
{
return (PieAnimation)obj.GetValue(PieAnimationProperty);
}
public static void SetPieAnimation(DependencyObject obj, PieAnimation value)
{
obj.SetValue(PieAnimationProperty, value);
}
public static void DispatchRunAnimations(RadChartBase chart)
{
IEnumerable<ChartSeries> series = null;
RadCartesianChart cartesianChart = chart as RadCartesianChart;
if (cartesianChart != null)
{
series = cartesianChart.Series;
}
RadPieChart pieChart = chart as RadPieChart;
if (pieChart != null)
{
series = pieChart.Series;
}
if (series.Any(s => (int)s.GetValue(ChartAnimationUtilities.RunningAnimationsCountProperty) > 0))
{
return;
}
foreach (ChartSeries s in series)
{
DispatchRunSeriesAnimations(s);
}
}
private static void CartesianAnimationChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
CartesianSeries series = (CartesianSeries)target;
if ((CartesianAnimation)args.NewValue == CartesianAnimation.None)
{
series.Loaded -= ChartSeries_Loaded;
series.DataBindingComplete -= ChartSeries_DataBindingComplete;
}
if ((CartesianAnimation)args.OldValue == CartesianAnimation.None)
{
series.Loaded += ChartSeries_Loaded;
series.DataBindingComplete += ChartSeries_DataBindingComplete;
}
}
private static void PieAnimationChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
PieSeries series = (PieSeries)target;
if ((PieAnimation)args.NewValue == PieAnimation.None)
{
series.Loaded -= ChartSeries_Loaded;
series.DataBindingComplete -= ChartSeries_DataBindingComplete;
}
if ((PieAnimation)args.OldValue == PieAnimation.None)
{
series.Loaded += ChartSeries_Loaded;
series.DataBindingComplete += ChartSeries_DataBindingComplete;
}
}
private static void StartAngleChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
PieSeries series = (PieSeries)target;
double startAngle = (double)args.NewValue;
if (double.IsNaN(startAngle) || series.AngleRange.StartAngle == startAngle)
{
return;
}
series.AngleRange = new AngleRange(startAngle, series.AngleRange.SweepAngle, series.AngleRange.SweepDirection);
}
private static void SweepAngleChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
PieSeries series = (PieSeries)target;
double sweepAngle = (double)args.NewValue;
if (double.IsNaN(sweepAngle) || series.AngleRange.SweepAngle == sweepAngle)
{
return;
}
series.AngleRange = new AngleRange(series.AngleRange.StartAngle, sweepAngle, series.AngleRange.SweepDirection);
}
private static void SeriesScaleTransformXChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
ChartSeries series = (ChartSeries)target;
double scaleX = (double)args.NewValue;
if (!double.IsNaN(scaleX))
{
ScaleTransform transform = (ScaleTransform)series.RenderTransform;
transform.ScaleX = scaleX;
}
}
private static void SeriesScaleTransformYChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
ChartSeries series = (ChartSeries)target;
double scaleY = (double)args.NewValue;
if (!double.IsNaN(scaleY))
{
ScaleTransform transform = (ScaleTransform)series.RenderTransform;
transform.ScaleY = (double)args.NewValue;
}
}
private static void BarScaleTransformXChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
FrameworkElement bar = (FrameworkElement)target;
double scaleX = (double)args.NewValue;
if (!double.IsNaN(scaleX))
{
ScaleTransform transform = (ScaleTransform)bar.RenderTransform;
transform.ScaleX = scaleX;
}
}
private static void BarScaleTransformYChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
FrameworkElement bar = (FrameworkElement)target;
double scaleY = (double)args.NewValue;
if (!double.IsNaN(scaleY))
{
ScaleTransform transform = (ScaleTransform)bar.RenderTransform;
transform.ScaleY = (double)args.NewValue;
}
}
private static void SliceScaleTransformXYChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
Path slice = (Path)target;
double scale = (double)args.NewValue;
if (!double.IsNaN(scale))
{
ScaleTransform transform = (ScaleTransform)slice.RenderTransform;
transform.ScaleX = scale;
transform.ScaleY = scale;
}
}
private static void SeriesTranslateTransformYChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
ChartSeries series = (ChartSeries)target;
double transformY = (double)args.NewValue;
if (!double.IsNaN(transformY))
{
TranslateTransform transform = (TranslateTransform)series.RenderTransform;
transform.Y = (double)args.NewValue;
}
}
private static void ChartSeries_Loaded(object sender, RoutedEventArgs e)
{
RunOrDispatchAnimations((ChartSeries)sender);
}
private static void ChartSeries_DataBindingComplete(object sender, EventArgs e)
{
DispatchRunSeriesAnimations((ChartSeries)sender);
}
private static void RunOrDispatchAnimations(ChartSeries series)
{
bool started = TryRunSeriesAnimation(series);
if (!started)
{
DispatchRunSeriesAnimations(series);
}
}
private static void DispatchRunSeriesAnimations(ChartSeries series)
{
series.Dispatcher.BeginInvoke((Action)(() => TryRunSeriesAnimation(series)));
}
private static bool HasDataPointsInPlotRange(ChartSeries series)
{
IList<DataPoint> dataPoints = GetDataPoints(series);
foreach (DataPoint dp in dataPoints)
{
if (dp.IsInPlotRange)
{
return true;
}
}
return false;
}
private static bool TryRunSeriesAnimation(ChartSeries series)
{
if (!HasDataPointsInPlotRange(series))
{
return false;
}
int count = (int)series.GetValue(ChartAnimationUtilities.RunningAnimationsCountProperty);
if (count > 0)
{
return false;
}
bool started = false;
CartesianSeries cartesianSeries = series as CartesianSeries;
if (cartesianSeries != null)
{
CartesianAnimation animation = GetCartesianAnimation(cartesianSeries);
if (animation == CartesianAnimation.Drop || animation == CartesianAnimation.DropWithDelay)
{
bool useDelay = animation == CartesianAnimation.DropWithDelay;
started |= TryRunDropAnimtation(cartesianSeries, useDelay);
}
if (animation == CartesianAnimation.Rise || animation == CartesianAnimation.RiseWithDelay)
{
bool useDelay = animation == CartesianAnimation.RiseWithDelay;
started |= TryRunRiseAnimtation(cartesianSeries, useDelay);
}
if (animation == CartesianAnimation.Stretch)
{
started |= TryRunStretchAnimtation(cartesianSeries);
}
if (animation == CartesianAnimation.StackedBars)
{
started |= TryRunStackedBarsAnimtation(cartesianSeries);
}
}
PieSeries pieSeries = series as PieSeries;
if (pieSeries != null)
{
PieAnimation animation = GetPieAnimation(pieSeries);
if (animation.HasFlag(PieAnimation.RadiusFactor))
{
started |= TryRunRadiusFactorAnimtation(pieSeries);
}
if (animation.HasFlag(PieAnimation.Slice))
{
started |= TryRunSliceAnimtation(pieSeries);
}
if (animation.HasFlag(PieAnimation.StartAngle))
{
started |= TryRunStartAngleAnimtation(pieSeries);
}
if (animation.HasFlag(PieAnimation.SweepAngle))
{
started |= TryRunSweepAngleAnimtation(pieSeries);
}
}
return started;
}
private static bool TryRunRadiusFactorAnimtation(PieSeries series)
{
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0.0;
animation.Duration = AnimationDuration;
animation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut, };
Storyboard.SetTargetProperty(animation, new PropertyPath(PieSeries.RadiusFactorProperty));
Storyboard.SetTarget(animation, series);
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
return Run(storyboard, series);
}
private static bool TryRunSliceAnimtation(PieSeries series)
{
Canvas renderSurface = Telerik.Windows.Controls.ChildrenOfTypeExtensions.FindChildByType<Canvas>(series);
List<Path> slices = new List<Path>();
foreach (UIElement uiElement in renderSurface.Children)
{
Path slice = uiElement as Path;
if (slice != null && slice.DataContext is PieDataPoint)
{
slices.Add(slice);
}
}
Storyboard storyboard = new Storyboard();
Point center = new Point(series.Chart.ActualWidth / 2, series.Chart.ActualHeight / 2);
TimeSpan? beginTime = null;
for (int i = 0; i < slices.Count; i++)
{
var animation = BuildSliceAnimation(slices[i], beginTime, PieSliceAnimationDuration, center, series);
storyboard.Children.Add(animation);
beginTime = new TimeSpan(0, 0, 0, 0, PieDelayInMilliseconds * (i + 1) / slices.Count);
}
bool showLabels = series.ShowLabels;
series.ShowLabels = false;
Action completed = () => series.ShowLabels = showLabels;
bool started = Run(storyboard, series, completed);
if (!started)
{
completed();
}
return started;
}
private static bool TryRunStartAngleAnimtation(PieSeries series)
{
double startAngle = (double)series.GetAnimationBaseValue(ChartAnimationUtilities.StartAngleProperty);
if (double.IsNaN(startAngle))
{
series.SetValue(ChartAnimationUtilities.StartAngleProperty, series.AngleRange.StartAngle);
startAngle = series.AngleRange.SweepAngle;
}
DoubleAnimation animation = new DoubleAnimation();
animation.From = startAngle - 90;
animation.To = startAngle;
animation.Duration = AnimationDuration;
animation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut, };
Storyboard.SetTargetProperty(animation, new PropertyPath(ChartAnimationUtilities.StartAngleProperty));
Storyboard.SetTarget(animation, series);
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
return Run(storyboard, series);
}
private static bool TryRunSweepAngleAnimtation(PieSeries series)
{
double sweepAngle = (double)series.GetAnimationBaseValue(ChartAnimationUtilities.SweepAngleProperty);
if (double.IsNaN(sweepAngle))
{
series.SetValue(ChartAnimationUtilities.SweepAngleProperty, series.AngleRange.SweepAngle);
sweepAngle = series.AngleRange.SweepAngle;
}
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0.0;
animation.To = sweepAngle;
animation.Duration = AnimationDuration;
animation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut, };
Storyboard.SetTargetProperty(animation, new PropertyPath(ChartAnimationUtilities.SweepAngleProperty));
Storyboard.SetTarget(animation, series);
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
return Run(storyboard, series);
}
private static bool TryRunRiseAnimtation(CartesianSeries series, bool useDelay)
{
RadRect plotAreClip = series.Chart.PlotAreaClip;
bool isHorizontalBar = !IsSeriesHorizontal(series);
bool isInverse = IsNumericalAxisInverse(series);
double centerX = 0;
double centerY = 0;
if (isHorizontalBar)
{
centerX = isInverse ? plotAreClip.Right : plotAreClip.X;
}
else
{
centerY = isInverse ? plotAreClip.Y : plotAreClip.Bottom;
}
var scaleTransform = new ScaleTransform();
scaleTransform.ScaleX = isHorizontalBar ? 0 : 1;
scaleTransform.ScaleY = isHorizontalBar ? 1 : 0;
scaleTransform.CenterX = centerX;
scaleTransform.CenterY = centerY;
series.RenderTransform = scaleTransform;
TimeSpan? beginTime = useDelay ? CalculateBeginTime(series) : null;
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0;
animation.To = 1;
animation.Duration = AnimationDuration;
if (beginTime != null)
{
animation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut, };
}
else
{
animation.EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseOut, };
}
Storyboard.SetTarget(animation, series);
if (isHorizontalBar)
{
Storyboard.SetTargetProperty(animation, new PropertyPath(ChartAnimationUtilities.SeriesScaleTransformXProperty));
}
else
{
Storyboard.SetTargetProperty(animation, new PropertyPath(ChartAnimationUtilities.SeriesScaleTransformYProperty));
}
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
if (beginTime != null)
{
storyboard.BeginTime = beginTime;
}
return Run(storyboard, series);
}
private static bool TryRunStretchAnimtation(CartesianSeries series)
{
RadRect plotAreClip = series.Chart.PlotAreaClip;
bool isHorizontal = IsSeriesHorizontal(series);
ScaleTransform transform = new ScaleTransform();
transform.ScaleX = isHorizontal ? 1 : 0;
transform.ScaleY = isHorizontal ? 0 : 1;
transform.CenterX = isHorizontal ? 0 : CalculateHorizontalSeriesMiddle(series);
transform.CenterY = isHorizontal ? CalculateVerticalSeriesMiddle(series) : 0;
if (!IsValidNumber(transform.CenterX) || !IsValidNumber(transform.CenterY))
{
return false;
}
series.RenderTransform = transform;
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0;
animation.To = 1;
animation.Duration = AnimationDuration;
animation.EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseOut, };
DependencyProperty prop = isHorizontal ? ChartAnimationUtilities.SeriesScaleTransformYProperty : ChartAnimationUtilities.SeriesScaleTransformXProperty;
Storyboard.SetTargetProperty(animation, new PropertyPath(prop));
Storyboard.SetTarget(animation, series);
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
return Run(storyboard, series);
}
private static bool TryRunDropAnimtation(CartesianSeries series, bool useDelay)
{
IList<DataPoint> dataPoints = GetDataPoints(series);
bool isInverse = IsNumericalAxisInverse(series);
double offsetY = isInverse ? double.PositiveInfinity : double.NegativeInfinity;
foreach (DataPoint dp in dataPoints)
{
if (isInverse && dp.IsInPlotRange && dp.LayoutSlot.Center.Y < offsetY)
{
offsetY = dp.LayoutSlot.Center.Y;
}
else if (!isInverse && dp.IsInPlotRange && offsetY < dp.LayoutSlot.Center.Y)
{
offsetY = dp.LayoutSlot.Center.Y;
}
}
if (!IsValidNumber(offsetY))
{
return false;
}
RadRect plotAreClip = series.Chart.PlotAreaClip;
offsetY = (isInverse ? 1 : -1) * (plotAreClip.Height / 2);
TranslateTransform transform = new TranslateTransform();
transform.Y = offsetY;
series.RenderTransform = transform;
TimeSpan? beginTime = useDelay ? CalculateBeginTime(series) : null;
series.Opacity = 0;
DoubleAnimation transformAnimation = new DoubleAnimation();
transformAnimation.From = offsetY;
transformAnimation.To = 0;
transformAnimation.Duration = AnimationDuration;
transformAnimation.EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseOut, };
Storyboard.SetTargetProperty(transformAnimation, new PropertyPath(ChartAnimationUtilities.SeriesTranslateTransformYProperty));
Storyboard.SetTarget(transformAnimation, series);
DoubleAnimation opacityAnimation = new DoubleAnimation();
opacityAnimation.From = 0;
opacityAnimation.To = 1;
opacityAnimation.Duration = AnimationDuration;
opacityAnimation.EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseOut, };
Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(ChartSeries.OpacityProperty));
Storyboard.SetTarget(opacityAnimation, series);
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(transformAnimation);
storyboard.Children.Add(opacityAnimation);
if (beginTime != null)
{
storyboard.BeginTime = beginTime;
}
Action completed = () => series.Opacity = 1;
bool started = Run(storyboard, series, completed);
if (!started)
{
completed();
}
return started;
}
private static bool TryRunStackedBarsAnimtation(CartesianSeries series)
{
Canvas renderSurface = Telerik.Windows.Controls.ChildrenOfTypeExtensions.FindChildByType<Canvas>(series);
List<FrameworkElement> bars = new List<FrameworkElement>();
foreach (FrameworkElement uiElement in renderSurface.Children)
{
Border bar = uiElement as Border;
ContentPresenter cp = uiElement as ContentPresenter;
if ((bar != null && (bar.DataContext is CategoricalDataPoint)) ||
(cp != null && cp.Content is CategoricalDataPoint))
{
bars.Add(uiElement);
}
}
Storyboard storyboard = new Storyboard();
RadCartesianChart chart = (RadCartesianChart)series.Chart;
int initialDelay = (int)(BarAnimationDuration.TimeSpan.Milliseconds * chart.Series.IndexOf(series));
TimeSpan? beginTime = TimeSpan.FromMilliseconds(initialDelay);
for (int i = 0; i < bars.Count; i++)
{
var animation = BuildStackedBarAnimation(bars[i], beginTime, BarAnimationDuration, series);
storyboard.Children.Add(animation);
beginTime = new TimeSpan(0, 0, 0, 0, initialDelay + (BarDelayInMilliseconds * (i + 1)));
}
return Run(storyboard, series);
}
private static bool Run(Storyboard storyboard, ChartSeries series, Action completed = null)
{
if (storyboard.Children.Count == 0)
{
return false;
}
storyboard.Completed += (s, e) =>
{
storyboard.Stop();
lock (locker)
{
int count = (int)series.GetValue(ChartAnimationUtilities.RunningAnimationsCountProperty);
count--;
series.SetValue(ChartAnimationUtilities.RunningAnimationsCountProperty, count);
}
if (completed != null)
{
completed();
}
};
storyboard.Begin();
lock (locker)
{
int count = (int)series.GetValue(ChartAnimationUtilities.RunningAnimationsCountProperty);
count++;
series.SetValue(ChartAnimationUtilities.RunningAnimationsCountProperty, count);
}
return true;
}
private static DoubleAnimation BuildSliceAnimation(Path path, TimeSpan? beginTime, Duration duration, Point center, PieSeries series)
{
var scaleTransform = new ScaleTransform();
scaleTransform.ScaleX = 0;
scaleTransform.ScaleY = 0;
scaleTransform.CenterX = center.X;
scaleTransform.CenterY = center.Y;
path.RenderTransform = scaleTransform;
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0;
animation.To = 1;
animation.Duration = duration;
animation.EasingFunction = new BackEase() { EasingMode = EasingMode.EaseOut, Amplitude = 0.4 };
if (beginTime != null)
{
animation.BeginTime = beginTime;
}
Storyboard.SetTarget(animation, path);
Storyboard.SetTargetProperty(animation, new PropertyPath(ChartAnimationUtilities.SliceScaleTransformXYProperty));
return animation;
}
private static DoubleAnimation BuildStackedBarAnimation(FrameworkElement bar, TimeSpan? beginTime, Duration duration, CartesianSeries series)
{
bool isHorizontalBar = !IsSeriesHorizontal(series);
bool isInverse = IsNumericalAxisInverse(series);
double centerX = 0;
double centerY = 0;
DataPoint dp = bar.DataContext as DataPoint;
if (dp == null)
{
dp = (DataPoint)((bar as ContentPresenter).Content);
}
if (isHorizontalBar)
{
centerX = isInverse ? dp.LayoutSlot.Width : 0;
}
else
{
centerY = isInverse ? 0 : dp.LayoutSlot.Height;
}
var scaleTransform = new ScaleTransform();
scaleTransform.ScaleX = isHorizontalBar ? 0 : 1;
scaleTransform.ScaleY = isHorizontalBar ? 1 : 0;
scaleTransform.CenterX = centerX;
scaleTransform.CenterY = centerY;
bar.RenderTransform = scaleTransform;
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0;
animation.To = 1;
animation.Duration = duration;
if (beginTime != null)
{
animation.BeginTime = beginTime;
}
Storyboard.SetTarget(animation, bar);
if (isHorizontalBar)
{
Storyboard.SetTargetProperty(animation, new PropertyPath(ChartAnimationUtilities.BarScaleTransformXProperty));
}
else
{
Storyboard.SetTargetProperty(animation, new PropertyPath(ChartAnimationUtilities.BarScaleTransformYProperty));
}
return animation;
}
private static TimeSpan? CalculateBeginTime(CartesianSeries series)
{
RadCartesianChart chart = (RadCartesianChart)series.Chart;
if (chart.Series.Count == 1)
{
return null;
}
int delay = DelayInMilliseconds * chart.Series.IndexOf(series) / chart.Series.Count;
return new TimeSpan(0, 0, 0, 0, delay);
}
private static IList<DataPoint> GetDataPoints(ChartSeries series)
{
PieSeries pieSeries = series as PieSeries;
if (pieSeries != null)
{
return (IList<DataPoint>)pieSeries.DataPoints;
}
CategoricalSeries categoricalSeries = series as CategoricalSeries;
if (categoricalSeries != null)
{
return categoricalSeries.DataPoints;
}
RangeSeries rangeSeries = series as RangeSeries;
if (rangeSeries != null)
{
return rangeSeries.DataPoints;
}
OhlcSeries ohlcSeries = series as OhlcSeries;
if (ohlcSeries != null)
{
return ohlcSeries.DataPoints;
}
ScatterPointSeries scatterPointSeries = (ScatterPointSeries)series;
return scatterPointSeries.DataPoints;
}
private static bool IsNumericalAxisInverse(CartesianSeries series)
{
NumericalAxis axis = series.VerticalAxis as NumericalAxis;
if (axis != null)
{
return axis.IsInverse;
}
axis = ((RadCartesianChart)series.Chart).VerticalAxis as NumericalAxis;
if (axis != null)
{
return axis.IsInverse;
}
axis = series.HorizontalAxis as NumericalAxis;
if (axis != null)
{
return axis.IsInverse;
}
axis = ((RadCartesianChart)series.Chart).HorizontalAxis as NumericalAxis;
if (axis != null)
{
return axis.IsInverse;
}
return false;
}
private static bool IsSeriesHorizontal(CartesianSeries series)
{
NumericalAxis axis = series.VerticalAxis as NumericalAxis;
if (axis != null)
{
return true;
}
axis = ((RadCartesianChart)series.Chart).VerticalAxis as NumericalAxis;
if (axis != null)
{
return true;
}
return false;
}
private static double CalculateHorizontalSeriesMiddle(CartesianSeries series)
{
return CalculateSeriesMiddle(series, dp => dp.LayoutSlot.Center.X);
}
private static double CalculateVerticalSeriesMiddle(CartesianSeries series)
{
return CalculateSeriesMiddle(series, dp => dp.LayoutSlot.Center.Y);
}
private static double CalculateSeriesMiddle(CartesianSeries series, Func<DataPoint, double> position)
{
double min = double.PositiveInfinity;
double max = double.NegativeInfinity;
IList<DataPoint> dataPoints = GetDataPoints(series);
foreach (DataPoint dp in dataPoints)
{
if (dp.IsInPlotRange)
{
double pos = position(dp);
if (pos < min)
{
min = pos;
}
if (max < pos)
{
max = pos;
}
}
}
return (min + max) / 2;
}
private static bool IsValidNumber(double value)
{
return double.MinValue <= value && value <= double.MaxValue;
}
}
}