/* 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.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Input; using System.Windows.Shapes; #else using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; using System.Windows.Input; #endif using Visifire.Commons; namespace Visifire.Charts { /// /// TrendLine can be used to draw lines to indicate significance of certain points /// public class TrendLine : ObservableObject { #region Public Methods /// /// Initializes a new instance of the Visifire.Charts.TrendLine class /// public TrendLine() { } #endregion #region Public Properties /// /// Identifies the Visifire.Charts.TrendLine.Enabled dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.Enabled dependency property. /// public static readonly DependencyProperty EnabledProperty = DependencyProperty.Register( "Enabled", typeof(Nullable), typeof(TrendLine), new PropertyMetadata(OnEnabledPropertyChanged)); #if WPF /// /// Identifies the Visifire.Charts.TrendLine.Opacity dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.Opacity dependency property. /// public new static readonly DependencyProperty OpacityProperty = DependencyProperty.Register ("Opacity", typeof(Double), typeof(TrendLine), new PropertyMetadata(1.0, OnOpacityPropertyChanged)); #endif /// /// Identifies the Visifire.Charts.TrendLine.LineColor dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.LineColor dependency property. /// public static readonly DependencyProperty LineColorProperty = DependencyProperty.Register( "LineColor", typeof(Brush), typeof(TrendLine), new PropertyMetadata(OnLineColorPropertyChanged)); /// /// Identifies the Visifire.Charts.TrendLine.LineThickness dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.LineThickness dependency property. /// public static readonly DependencyProperty LineThicknessProperty = DependencyProperty.Register( "LineThickness", typeof(Double), typeof(TrendLine), new PropertyMetadata(OnLineThicknessPropertyChanged)); /// /// Identifies the Visifire.Charts.TrendLine.LineStyle dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.LineStyle dependency property. /// public static readonly DependencyProperty LineStyleProperty = DependencyProperty.Register( "LineStyle", typeof(LineStyles), typeof(TrendLine), new PropertyMetadata(OnLineStylePropertyChanged)); /// /// Identifies the Visifire.Charts.TrendLine.ShadowEnabled dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.ShadowEnabled dependency property. /// public static readonly DependencyProperty ShadowEnabledProperty = DependencyProperty.Register( "ShadowEnabled", typeof(bool), typeof(TrendLine), new PropertyMetadata(OnShadowEnabledPropertyChanged)); /// /// Identifies the Visifire.Charts.TrendLine.Value dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.Value dependency property. /// public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof(Object), typeof(TrendLine), new PropertyMetadata(OnValuePropertyChanged)); /// /// Identifies the Visifire.Charts.TrendLine.HrefTarget dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.HrefTarget dependency property. /// public static readonly DependencyProperty HrefTargetProperty = DependencyProperty.Register( "HrefTarget", typeof(HrefTargets), typeof(TrendLine), new PropertyMetadata(OnHrefTargetChanged)); /// /// Identifies the Visifire.Charts.TrendLine.Href dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.Href dependency property. /// public static readonly DependencyProperty HrefProperty = DependencyProperty.Register( "Href", typeof(String), typeof(TrendLine), new PropertyMetadata(OnHrefChanged)); /// /// Identifies the Visifire.Charts.TrendLine.AxisType dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.AxisType dependency property. /// public static readonly DependencyProperty AxisTypeProperty = DependencyProperty.Register( "AxisType", typeof(AxisTypes), typeof(TrendLine), new PropertyMetadata(OnAxisTypePropertyChanged)); /// /// Identifies the Visifire.Charts.TrendLine.Orientation dependency property. /// /// /// The identifier for the Visifire.Charts.TrendLine.Orientation dependency property. /// public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register( "Orientation", typeof(Orientation), typeof(TrendLine), new PropertyMetadata(Orientation.Horizontal, OnOrientationPropertyChanged)); /// /// Enables or disables the TrendLine /// [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 Opacity property /// public new Double Opacity { get { return (Double)GetValue(OpacityProperty); } set { #if SL if (Opacity != value) { SetValue(OpacityProperty, value); FirePropertyChanged("Opacity"); } #else SetValue(OpacityProperty, value); #endif } } /// /// Get or set the Cursor property /// public new Cursor Cursor { get { return base.Cursor; } set { if (base.Cursor != value) { base.Cursor = value; FirePropertyChanged("Cursor"); } } } /// /// Get or set the Color of the TrendLine /// public Brush LineColor { get { return (Brush)GetValue(LineColorProperty) == null ? new SolidColorBrush(Colors.Red) : (Brush)GetValue(LineColorProperty); } set { SetValue(LineColorProperty, value); } } /// /// Get or set the Line thickness of TrendLine /// public Double LineThickness { get { return (Double)GetValue(LineThicknessProperty) == 0 ? 2 : (Double)GetValue(LineThicknessProperty); } set { SetValue(LineThicknessProperty, value); } } /// /// Get or set the Line style of TrendLine /// public LineStyles LineStyle { get { return (LineStyles)GetValue(LineStyleProperty); } set { SetValue(LineStyleProperty, value); } } /// /// Whether shadow is enebled for the TrendLine /// public bool ShadowEnabled { get { return (bool)GetValue(ShadowEnabledProperty); } set { SetValue(ShadowEnabledProperty, value); } } /// /// Get or set the Value of the TrendLine /// public Object Value { get { return (Object)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } /// /// Get or set the AxisType of the TrendLine /// public AxisTypes AxisType { get { return (AxisTypes)GetValue(AxisTypeProperty); } set { SetValue(AxisTypeProperty, value); } } /// /// Get or set the Orientation of the TrendLine. /// Whether the TrendLine should be vertically oriented or horizontally oriented /// public Orientation Orientation { get { return (Orientation)GetValue(OrientationProperty); } set { SetValue(OrientationProperty, value); } } /// /// Get or set the HrefTarget property of TrendLine /// public HrefTargets HrefTarget { get { return (HrefTargets)GetValue(HrefTargetProperty); } set { SetValue(HrefTargetProperty, value); } } /// /// Get or set the Href property of TrendLine /// public String Href { get { return (String)GetValue(HrefProperty); } set { SetValue(HrefProperty, value); } } #endregion #region Public Events And Delegates #endregion #region Protected Methods #endregion #region Internal Properties /// /// Get or set the Value of the TrendLine /// internal DateTime InternalDateValue { get; set; } /// /// Get or set the Value of the TrendLine /// internal Double InternalNumericValue { get; set; } /// /// Axis reference /// internal Axis ReferingAxis { get; set; } /// /// TrendLine canvas /// internal Canvas Visual { get; set; } #endregion #region Private Properties /// /// Line visual /// private Line Line { get; set; } /// /// Shadow visual /// private Line Shadow { get; set; } #endregion #region Private Delegates #endregion #region Private Methods /// /// EnabledProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine source = d as TrendLine; source.FirePropertyChanged("Enabled"); } #if WPF /// /// OpacityProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnOpacityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine source = d as TrendLine; source.FirePropertyChanged("Opacity"); } #endif /// /// LineColorProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnLineColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine source = d as TrendLine; source.UpdateVisual("LineColor", e.NewValue); } /// /// LineThicknessProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnLineThicknessPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine source = d as TrendLine; //source.FirePropertyChanged("LineThickness"); source.UpdateVisual("LineThickness", e.NewValue); } /// /// LineStyleProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnLineStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine source = d as TrendLine; source.UpdateVisual("LineStyle", e.NewValue); } /// /// ShadowEnabledProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnShadowEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine trendLine = d as TrendLine; trendLine.UpdateVisual("ShadowEnabled", e.NewValue); } /// /// ValueProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine trendLine = d as TrendLine; // Double / Int32 value entered in Managed Code if (e.NewValue.GetType().Equals(typeof(Double)) || e.NewValue.GetType().Equals(typeof(Int32))) { trendLine.InternalNumericValue = Convert.ToDouble(e.NewValue); } // DateTime value entered in Managed Code else if ((e.NewValue.GetType().Equals(typeof(DateTime)))) { trendLine.InternalDateValue = (DateTime)e.NewValue; } // Double / Int32 / DateTime entered in XAML else if ((e.NewValue.GetType().Equals(typeof(String)))) { DateTime dateTimeresult; Double doubleResult; if (String.IsNullOrEmpty(e.NewValue.ToString())) { trendLine.InternalNumericValue = Double.NaN; } // Double entered in XAML else if (Double.TryParse((string)e.NewValue, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.InvariantCulture, out doubleResult)) { trendLine.InternalNumericValue = doubleResult; } // DateTime entered in XAML else if (DateTime.TryParse((string)e.NewValue, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dateTimeresult)) { trendLine.InternalDateValue = dateTimeresult; } else { System.Diagnostics.Debug.WriteLine("Invalid Input for AxisMaximum"); throw new Exception("Invalid Input for AxisMaximum"); } } else { System.Diagnostics.Debug.WriteLine("Invalid Input for AxisMaximum"); throw new Exception("Invalid Input for AxisMaximum"); } //trendLine.FirePropertyChanged("Value"); trendLine.UpdateVisual("Value", e.NewValue); } /// /// AxisTypeProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnAxisTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine source = d as TrendLine; source.FirePropertyChanged("AxisType"); } /// /// OrientationProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnOrientationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine source = d as TrendLine; source.FirePropertyChanged("Orientation"); } /// /// HrefTargetProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnHrefTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine trendLine = d as TrendLine; trendLine.FirePropertyChanged("HrefTarget"); } /// /// HrefProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnHrefChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TrendLine trendLine = d as TrendLine; trendLine.FirePropertyChanged("Href"); } /// /// Apply properties of TrendLine to line visual and line-shadow visual /// private void ApplyProperties() { Line.Stroke = LineColor; Line.StrokeThickness = LineThickness; Line.StrokeDashArray = ExtendedGraphics.GetDashArray(LineStyle); Shadow.StrokeThickness = LineThickness + 2; Shadow.StrokeDashArray = ExtendedGraphics.GetDashArray(LineStyle); Shadow.Stroke = new SolidColorBrush(Colors.LightGray); Shadow.Opacity = 0.7; Shadow.StrokeDashCap = PenLineCap.Round; Shadow.StrokeLineJoin = PenLineJoin.Round; Shadow.Visibility = ShadowEnabled ? Visibility.Visible : Visibility.Collapsed; } #endregion #region Internal Methods /// /// UpdateVisual is used for partial rendering /// /// Name of the property /// Value of the property internal override void UpdateVisual(string propertyName, object value) { if (Line == null || Shadow == null) FirePropertyChanged(propertyName); else if (propertyName == "Value") { Chart chart = (Chart as Chart); Axis axis = chart.PlotDetails.GetAxisXFromChart(chart, AxisType); chart.PlotDetails.SetTrendLineValue(this, axis); Canvas visualCanvas = (Chart as Chart).ChartArea.ChartVisualCanvas; PositionTheLine(visualCanvas.Width, visualCanvas.Height); } else ApplyProperties(); } /// /// Set the position of line /// /// /// private void PositionTheLine(Double width, Double height) { Double shadowThickness = LineThickness + 2; switch (Orientation) { case Orientation.Vertical: Line.Y1 = 0; Line.Y2 = height; Line.X1 = Graphics.ValueToPixelPosition(0, width, (Double)ReferingAxis.InternalAxisMinimum, (Double)ReferingAxis.InternalAxisMaximum, InternalNumericValue); Line.X2 = Line.X1; Visual.Height = height; Visual.Width = shadowThickness; break; case Orientation.Horizontal: Line.X1 = 0; Line.X2 = width; Line.Y1 = Graphics.ValueToPixelPosition(height, 0, (Double)ReferingAxis.InternalAxisMinimum, (Double)ReferingAxis.InternalAxisMaximum, InternalNumericValue); Line.Y2 = Line.Y1; Visual.Height = shadowThickness; Visual.Width = width; break; } if (Orientation == Orientation.Horizontal) { Shadow.X1 = Line.X1; Shadow.X2 = Line.X2 + 3; Shadow.Y1 = Line.Y1 + 3; Shadow.Y2 = Line.Y2 + 3; } else { Shadow.X1 = Line.X1 + 3; Shadow.X2 = Line.X2 + 3; Shadow.Y1 = Line.Y1 + 3; Shadow.Y2 = Line.Y2; } } /// /// Create visual objects for TrendLine /// /// Width of the ChartCanvas /// Height of the ChartCanvas internal void CreateVisualObject(Double width, Double height) { if (ReferingAxis == null || !(Boolean)Enabled) { Visual = null; return; } Visual = new Canvas(); Visual.Opacity = this.Opacity; Visual.Cursor = this.Cursor; Double shadowThickness = LineThickness + 2; Line = new Line() { Tag = new ElementData() { Element = this } }; Shadow = new Line() { IsHitTestVisible = false }; ApplyProperties(); PositionTheLine(width, height); Visual.Children.Add(Shadow); Visual.Children.Add(Line); AttachToolTip(ReferingAxis.Chart, this, Line); AttachHref(ReferingAxis.Chart, Line, Href, HrefTarget); } #endregion #region Internal Events And Delegates #endregion #region Data #endregion } }