#if WPF
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
#else
using System;
using System.Windows;
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.ChartGrid class. It contains grids of axis.
///
public class ChartGrid : ObservableObject
{
#region Public Methods
///
/// Initializes a new instance of the Visifire.Charts.ChartGrid class
///
public ChartGrid()
{
// Apply default style from generic
#if WPF
if (!_defaultStyleKeyApplied)
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ChartGrid), new FrameworkPropertyMetadata(typeof(ChartGrid)));
_defaultStyleKeyApplied = true;
}
#else
DefaultStyleKey = typeof(ChartGrid);
#endif
}
#endregion
#region Public Properties
///
/// Identifies the Visifire.Charts.ChartGrid.Interval dependency property.
///
///
/// The identifier for the Visifire.Charts.ChartGrid.Interval dependency property.
///
public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register
("Interval",
typeof(Nullable),
typeof(ChartGrid),
new PropertyMetadata(OnIntervalPropertyChanged));
///
/// Identifies the Visifire.Charts.ChartGrid.Enabled dependency property.
///
///
/// The identifier for the Visifire.Charts.ChartGrid.Enabled dependency property.
///
public static readonly DependencyProperty EnabledProperty = DependencyProperty.Register
("Enabled",
typeof(Nullable),
typeof(ChartGrid),
new PropertyMetadata(OnEnabledPropertyChanged));
///
/// Identifies the Visifire.Charts.ChartGrid.LineColor dependency property.
///
///
/// The identifier for the Visifire.Charts.ChartGrid.LineColor dependency property.
///
public static readonly DependencyProperty LineColorProperty = DependencyProperty.Register
("LineColor",
typeof(Brush),
typeof(ChartGrid),
new PropertyMetadata(OnLineColorPropertyChanged));
///
/// Identifies the Visifire.Charts.ChartGrid.LineStyle dependency property.
///
///
/// The identifier for the Visifire.Charts.ChartGrid.LineStyle dependency property.
///
public static readonly DependencyProperty LineStyleProperty = DependencyProperty.Register
("LineStyle",
typeof(LineStyles),
typeof(ChartGrid),
new PropertyMetadata(OnLineStylePropertyChanged));
///
/// Identifies the Visifire.Charts.ChartGrid.LineThickness dependency property.
///
///
/// The identifier for the Visifire.Charts.ChartGrid.LineThickness dependency property.
///
public static readonly DependencyProperty LineThicknessProperty = DependencyProperty.Register
("LineThickness",
typeof(Double),
typeof(ChartGrid),
new PropertyMetadata(0.25, OnLineThicknessPropertyChanged));
///
/// Identifies the Visifire.Charts.ChartGrid.InterlacedColor dependency property.
///
///
/// The identifier for the Visifire.Charts.ChartGrid.InterlacedColor dependency property.
///
public static readonly DependencyProperty InterlacedColorProperty = DependencyProperty.Register(
"InterlacedColor",
typeof(Brush),
typeof(ChartGrid),
new PropertyMetadata(OnInterlacedColorPropertyChanged));
///
/// Get or set the grid interval
///
#if SL
[System.ComponentModel.TypeConverter(typeof(Converters.NullableDoubleConverter))]
#endif
public Nullable Interval
{
get
{
if ((Nullable)GetValue(IntervalProperty) == null && ParentAxis != null)
return ParentAxis.InternalInterval;
else
return (Nullable)GetValue(IntervalProperty);
}
set
{
SetValue(IntervalProperty, value);
}
}
///
/// ToolTipText property
/// ( NotImplemented )
///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public override String ToolTipText
{
get
{
throw new NotImplementedException("ToolTipText property for ChartGrid is not implemented");
}
set
{
throw new NotImplementedException("ToolTipText property for ChartGrid is not implemented");
}
}
///
/// Get or set the grid line style
///
public LineStyles LineStyle
{
get
{
return (LineStyles)GetValue(LineStyleProperty);
}
set
{
SetValue(LineStyleProperty, value);
}
}
///
/// Get or set the grid interlaced color
///
public Brush InterlacedColor
{
get { return (Brush)GetValue(InterlacedColorProperty); }
set { SetValue(InterlacedColorProperty, value); }
}
///
/// Get or set the grid line thickness
///
public Double LineThickness
{
get
{
return (Double)GetValue(LineThicknessProperty);
}
set
{
SetValue(LineThicknessProperty, value);
}
}
///
/// Enables or disables grid lines
///
[System.ComponentModel.TypeConverter(typeof(NullableBoolConverter))]
public Nullable Enabled
{
get
{
if ((Nullable)GetValue(EnabledProperty) == null)
return true;
else
return (Nullable)GetValue(EnabledProperty);
}
set
{
SetValue(EnabledProperty, value);
}
}
///
/// Get or set the grid line color
///
public Brush LineColor
{
get
{
return (GetValue(LineColorProperty) != null) ? (Brush)GetValue(LineColorProperty) : new SolidColorBrush(Colors.Gray);
}
set
{
SetValue(LineColorProperty, value);
}
}
#endregion
#region Public Events
#endregion
#region Protected Methods
#endregion
#region Internal Properties
///
/// Visual element for grid
///
internal Canvas Visual
{
get;
private set;
}
///
/// Actual minimum value of the axis
///
internal Double Minimum
{
get;
set;
}
///
/// Actual maximum value of the axis
///
internal Double Maximum
{
get;
set;
}
///
/// Minimum data value for the axis
///
internal Double DataMinimum
{
get;
set;
}
///
/// Maximum data value for the axis
///
internal Double DataMaximum
{
get;
set;
}
///
/// Get or set the width of the grid canvas, will be used only with the Horizontal axis
///
internal new Double Width
{
get
{
return _width;
}
set
{
_width = value;
}
}
///
/// Get or set the height of the grid canvas, will be used ony with the vertical axis
///
internal new Double Height
{
get
{
return _height;
}
set
{
_height = value;
}
}
///
/// Placement decides how the grids have to be positioned
///
internal PlacementTypes Placement
{
get;
set;
}
///
/// Parent axis reference
///
internal Axis ParentAxis
{
get;
set;
}
///
/// Chart grid storyboard
///
internal Storyboard Storyboard
{
get;
set;
}
#endregion
#region Private Delegates
#endregion
#region Private Methods
///
/// Creates grids and also position them appropriately
///
/// Whether animation is enabled
/// Animation duration
private void CreateAndPositionChartGrid(bool animationEnabled, Double animationDuration)
{
Double interval = (Double)Interval; // Interval for the chart grid
Decimal index =0;// = (Decimal)Minimum; // starting point for the loop that generates grids
Decimal minVal = (Decimal)Minimum; // smallest value from where the grid must be drawn
Decimal maxVal = (Decimal)Maximum; // largest value from where the grid must be drawn
// gap between two intervals
Decimal gap = (Decimal)interval;// +(((Nullable)GetValue(IntervalProperty) == null) ? ParentAxis.SkipOffset : 0);
//Int32 count = 0; // counts the number of lines required for alternate colored bands
Int32 countRectangles = 0; // counts the number of color bands for animating them alternately in opposite direction
Double position = 0; // value of the line position for the running loop cycle
Double prevPosition = 0; // value of the line position for the previous position
// if axisX and the first data point is in a gap between the prescribed interval, the index must dateTime from the
// datapoint rather than the axis minimum
// if ((DataMinimum - interval) < Minimum && ParentAxis.AxisRepresentation == AxisRepresentations.AxisX)
// index = (Decimal)DataMinimum;
if (ParentAxis.AxisRepresentation == AxisRepresentations.AxisX)
{
if (Double.IsNaN((Double)ParentAxis.AxisMinimumNumeric))
{
if (ParentAxis.XValueType != ChartValueTypes.Numeric)
{
minVal = (Decimal)ParentAxis.FirstLabelPosition;
}
else
{
if ((DataMinimum - Minimum) / interval >= 1)
minVal = (Decimal)(DataMinimum - Math.Floor((DataMinimum - Minimum) / interval) * interval);
else
minVal = (Decimal)DataMinimum;
}
}
}
//index = minval;
// maxVal = maxVal + gap / 1000;
#if WPF
if (Storyboard != null && Storyboard.GetValue(Storyboard.TargetProperty) != null)
Storyboard.Stop();
#else
if (Storyboard != null)
Storyboard.Stop();
#endif
InterlacedRectangles = new List();
InterlacedLines = new List();
if (minVal != maxVal)
{
InterlacedRectangles = new List();
Decimal xValue;
for (xValue = minVal; xValue <= maxVal; )
{
Line line = new Line();
InterlacedLines.Add(line);
line.Stroke = LineColor;
line.StrokeThickness = LineThickness;
line.StrokeDashArray = ExtendedGraphics.GetDashArray(LineStyle);
line.Width = Width;
line.Height = Height;
switch (Placement)
{
case PlacementTypes.Top:
case PlacementTypes.Bottom:
position = Graphics.ValueToPixelPosition(0, Width, Minimum, Maximum, (Double)xValue);
line.X1 = position;
line.X2 = position;
line.Y1 = 0;
line.Y2 = Height;
if (index % 2 == 1)
{
Rectangle rectangle = new Rectangle();
if (animationEnabled)
{
ScaleTransform scaleTransform;
if (countRectangles % 2 == 0)
{
scaleTransform = new ScaleTransform() { ScaleX = 1, ScaleY = 0 };
rectangle.RenderTransformOrigin = new Point(0.5, 1);
Storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "(ScaleTransform.ScaleY)", 0, 1, 0.5, animationDuration));
}
else
{
scaleTransform = new ScaleTransform() { ScaleX = 1, ScaleY = 0 };
rectangle.RenderTransformOrigin = new Point(0.5, 0);
Storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "(ScaleTransform.ScaleY)", 0, 1, 0.5, animationDuration));
}
rectangle.RenderTransform = scaleTransform;
}
countRectangles++;
rectangle.Width = Math.Abs(position - prevPosition);
rectangle.Height = Height;
rectangle.Fill = InterlacedColor;
rectangle.SetValue(Canvas.LeftProperty, prevPosition);
rectangle.SetValue(Canvas.TopProperty, (Double)0);
rectangle.SetValue(Canvas.ZIndexProperty, (Int32)(-countRectangles));
Visual.Children.Add(rectangle);
InterlacedRectangles.Add(rectangle);
}
break;
case PlacementTypes.Left:
case PlacementTypes.Right:
position = Graphics.ValueToPixelPosition(Height, 0, Minimum, Maximum, (Double)xValue);
if (position == 0)
position += this.LineThickness;
line.X1 = 0;
line.X2 = Width;
line.Y1 = position;
line.Y2 = position;
if (index % 2 == 1)
{
Rectangle rectangle = new Rectangle();
if (animationEnabled)
{
ScaleTransform scaleTransform;
if (countRectangles % 2 == 0)
{
scaleTransform = new ScaleTransform() { ScaleX = 0, ScaleY = 1 };
rectangle.RenderTransformOrigin = new Point(0, 0.5);
Storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "(ScaleTransform.ScaleX)", 0, 1, 0.5, animationDuration));
}
else
{
scaleTransform = new ScaleTransform() { ScaleX = 0, ScaleY = 1 };
rectangle.RenderTransformOrigin = new Point(1, 0.5);
Storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "(ScaleTransform.ScaleX)", 0, 1, 0.5, animationDuration));
}
rectangle.RenderTransform = scaleTransform;
}
countRectangles++;
rectangle.Width = Width;
rectangle.Height = Math.Abs(position - prevPosition);
rectangle.Fill = InterlacedColor;
rectangle.SetValue(Canvas.LeftProperty, (Double)0);
rectangle.SetValue(Canvas.TopProperty, position);
rectangle.SetValue(Canvas.ZIndexProperty, (Int32)(-countRectangles));
Visual.Children.Add(rectangle);
InterlacedRectangles.Add(rectangle);
}
break;
}
Visual.Children.Add(line);
prevPosition = position;
index += (ParentAxis.SkipOffset + 1);
if (ParentAxis.IsDateTimeAxis)
{
DateTime dt = DateTimeHelper.UpdateDate(ParentAxis.FirstLabelDate, (Double)(index * gap), ParentAxis.InternalIntervalType);
Decimal oneUnit = (Decimal)DateTimeHelper.DateDiff(dt, ParentAxis.FirstLabelDate, ParentAxis.MinDateRange, ParentAxis.MaxDateRange, ParentAxis.InternalIntervalType, ParentAxis.XValueType);
xValue = minVal + oneUnit;
}
else
{
xValue = minVal + index * gap;
}
}
if (index % 2 == 1)
{
Rectangle rectangle = new Rectangle();
ScaleTransform scaleTransform = null;
switch (Placement)
{
case PlacementTypes.Top:
case PlacementTypes.Bottom:
rectangle.Width = Math.Abs(Width - position);
rectangle.Height = Height;
if (animationEnabled)
{
if (countRectangles % 2 == 0)
{
scaleTransform = new ScaleTransform() { ScaleX = 1, ScaleY = 0 };
rectangle.RenderTransformOrigin = new Point(0.5, 1);
Storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "(ScaleTransform.ScaleY)", 0, 1, 0.5, animationDuration));
}
else
{
scaleTransform = new ScaleTransform() { ScaleX = 1, ScaleY = 0 };
rectangle.RenderTransformOrigin = new Point(0.5, 0);
Storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "(ScaleTransform.ScaleY)", 0, 1, 0.5, animationDuration));
}
}
rectangle.SetValue(Canvas.LeftProperty, position);
rectangle.SetValue(Canvas.TopProperty, (Double)0);
break;
case PlacementTypes.Left:
case PlacementTypes.Right:
rectangle.Width = Width;
rectangle.Height = Math.Abs(position);
if (animationEnabled)
{
if (countRectangles % 2 == 0)
{
scaleTransform = new ScaleTransform() { ScaleX = 0, ScaleY = 1 };
rectangle.RenderTransformOrigin = new Point(0, 0.5);
Storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "(ScaleTransform.ScaleX)", 0, 1, 0.5, animationDuration));
}
else
{
scaleTransform = new ScaleTransform() { ScaleX = 0, ScaleY = 1 };
rectangle.RenderTransformOrigin = new Point(1, 0.5);
Storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "(ScaleTransform.ScaleX)", 0, 1, 0.5, animationDuration));
}
}
rectangle.SetValue(Canvas.LeftProperty, (Double)0);
rectangle.SetValue(Canvas.TopProperty, (Double)0);
break;
}
rectangle.RenderTransform = scaleTransform;
rectangle.Fill = InterlacedColor;
rectangle.SetValue(Canvas.ZIndexProperty, (Int32)(-countRectangles));
Visual.Children.Add(rectangle);
InterlacedRectangles.Add(rectangle);
}
}
Visual.Width = Width;
Visual.Height = Height;
}
///
/// Generates a Double animation sequence with fixed parameters
///
/// Animation target object
/// Animation target property
/// Start value
/// End value
/// Animation begin time
/// Animation duration
/// DoubleAnimationUsingKeyFrames
private DoubleAnimationUsingKeyFrames CreateDoubleAnimation(DependencyObject target, String property, Double from, Double to, Double begin, Double duration)
{
DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames();
da.BeginTime = TimeSpan.FromSeconds(begin);
#if WPF
target.SetValue(NameProperty, target.GetType().Name + Guid.NewGuid().ToString().Replace('-', '_'));
Storyboard.SetTargetName(da, target.GetValue(NameProperty).ToString());
Chart._rootElement.RegisterName((string)target.GetValue(NameProperty), target);
#else
Storyboard.SetTarget(da, target);
#endif
Storyboard.SetTargetProperty(da, new PropertyPath(property));
SplineDoubleKeyFrame keyFrame = new SplineDoubleKeyFrame();
keyFrame.KeySpline = new KeySpline() { ControlPoint1 = new Point(0, 0), ControlPoint2 = new Point(1, 1) };
keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0));
keyFrame.Value = from;
da.KeyFrames.Add(keyFrame);
keyFrame = new SplineDoubleKeyFrame();
keyFrame.KeySpline = new KeySpline() { ControlPoint1 = new Point(0.5, 0), ControlPoint2 = new Point(0.5, 1) };
keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(duration));
keyFrame.Value = to;
da.KeyFrames.Add(keyFrame);
return da;
}
///
/// IntervalProperty changed call back function
///
/// DependencyObject
/// DependencyPropertyChangedEventArgs
private static void OnIntervalPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ChartGrid chartGrid = d as ChartGrid;
chartGrid.FirePropertyChanged("Interval");
}
///
/// EnabledProperty changed call back function
///
/// DependencyObject
/// DependencyPropertyChangedEventArgs
private static void OnEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ChartGrid chartGrid = d as ChartGrid;
chartGrid.FirePropertyChanged("Enabled");
}
///
/// LineColorProperty changed call back function
///
/// DependencyObject
/// DependencyPropertyChangedEventArgs
private static void OnLineColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ChartGrid chartGrid = d as ChartGrid;
chartGrid.UpdateVisual("LineColor", e.NewValue);
}
///
/// LineStyleProperty changed call back function
///
/// DependencyObject
/// DependencyPropertyChangedEventArgs
private static void OnLineStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ChartGrid chartGrid = d as ChartGrid;
chartGrid.UpdateVisual("LineStyle", e.NewValue);
}
///
/// LineThicknessProperty changed call back function
///
/// DependencyObject
/// DependencyPropertyChangedEventArgs
private static void OnLineThicknessPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ChartGrid chartGrid = d as ChartGrid;
chartGrid.UpdateVisual("LineThickness", e.NewValue);
}
///
/// InterlacedColorProperty changed call back function
///
/// DependencyObject
/// DependencyPropertyChangedEventArgs
private static void OnInterlacedColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ChartGrid chartGrid = d as ChartGrid;
chartGrid.UpdateVisual("InterlacedColor", e.NewValue);
}
#endregion
#region Private Properties
///
/// Identifies the Visifire.Charts.ChartGrid.ToolTipText dependency property.
///
///
/// The identifier for the Visifire.Charts.ChartGrid.ToolTipText dependency property.
///
private new static readonly DependencyProperty ToolTipTextProperty = DependencyProperty.Register
("ToolTipText",
typeof(String),
typeof(ChartGrid),
null);
///
/// List of interlaced rectangles
///
private List InterlacedRectangles
{
get;
set;
}
///
/// List of interlaced lines
///
private List InterlacedLines
{
get;
set;
}
#endregion
#region Internal Methods
///
/// Creates the visual element for chart grid
///
/// ChartVisualCanvas width
/// ChartVisualCanvas height
/// Whether animation is enabled
/// Animation duration
internal void CreateVisualObject(Double width, Double height, bool animationEnabled, Double animationDuration)
{
if (!(Boolean)Enabled)
{
Visual = null;
return;
}
Visual = new Canvas();
Width = width;
Height = height;
if (animationEnabled)
{
Storyboard = new Storyboard();
ScaleTransform st = new ScaleTransform() { ScaleX = 1, ScaleY = 1 };
Visual.RenderTransformOrigin = new Point(0.5, 0.5);
Visual.RenderTransform = st;
if (Placement == PlacementTypes.Top || Placement == PlacementTypes.Bottom)
Storyboard.Children.Add(CreateDoubleAnimation(st, "(ScaleTransform.ScaleY)", 0, 1, 0, animationDuration));
else
Storyboard.Children.Add(CreateDoubleAnimation(st, "(ScaleTransform.ScaleX)", 0, 1, 0, animationDuration));
}
CreateAndPositionChartGrid(animationEnabled, animationDuration);
Visual.Opacity = this.Opacity;
}
///
/// Update visual used for partial update
///
/// Name of the property
/// Value of the property
internal override void UpdateVisual(string propertyName, object value)
{
if (Visual != null)
{
foreach (Rectangle rec in InterlacedRectangles)
rec.Fill = InterlacedColor;
foreach (Line line in InterlacedLines)
{
line.Stroke = LineColor;
line.StrokeThickness = LineThickness;
line.StrokeDashArray = ExtendedGraphics.GetDashArray(LineStyle);
}
}
else
FirePropertyChanged(propertyName);
}
#endregion
#region Internal Events
#endregion
#region Data
///
/// Set the width of the grid canvas, will be used only with the Horizontal axis
///
private Double _width;
///
/// Set the height of the grid canvas, will be used ony with the vertical axis
///
private Double _height;
#if WPF
///
/// Whether the default style is applied
///
private static Boolean _defaultStyleKeyApplied;
#endif
#endregion
}
}