/* 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.Controls.Primitives; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; using System.Globalization; using System.Collections.ObjectModel; #else using System; using System.Windows; using System.Linq; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Windows.Browser; #endif using Visifire.Commons; using System.Windows.Data; namespace Visifire.Charts { /// /// Visifire.Charts.Axis class /// #if SL [System.Windows.Browser.ScriptableType] #endif public class Axis : ObservableObject { #region Public Methods /// /// Initializes a new instance of the Visifire.Charts.Axis class /// public Axis() { // Initialize list of ChartGrid list Grids = new ChartGridCollection(); // Initialize list of Ticks list Ticks = new TicksCollection(); // Initialize AxisLabels element AxisLabels = new AxisLabels(); // Attach event handler on collection changed event with chart grid collection Grids.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Grids_CollectionChanged); // Attach event handler on collection changed event with ticks collection Ticks.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Ticks_CollectionChanged); InternalAxisMinimum = Double.NaN; InternalAxisMaximum = Double.NaN; } public override void Bind() { #if SL Binding b = new Binding("Background"); b.Source = this; this.SetBinding(InternalBackgroundProperty, b); b = new Binding("Padding"); b.Source = this; this.SetBinding(InternalPaddingProperty, b); b = new Binding("Opacity"); b.Source = this; this.SetBinding(InternalOpacityProperty, b); #endif } #endregion #region Public Properties /// /// Identifies the Visifire.Charts.Axis.AxisLabels dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.AxisLabels dependency property. /// public static DependencyProperty AxisLabelsProperty = DependencyProperty.Register ("AxisLabels", typeof(AxisLabels), typeof(Axis), new PropertyMetadata(OnAxisLabelsPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.HrefTarget dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.HrefTarget dependency property. /// public static readonly DependencyProperty HrefTargetProperty = DependencyProperty.Register ("HrefTarget", typeof(HrefTargets), typeof(Axis), new PropertyMetadata(OnHrefTargetChanged)); /// /// Identifies the Visifire.Charts.Axis.Href dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Href dependency property. /// public static readonly DependencyProperty HrefProperty = DependencyProperty.Register ("Href", typeof(String), typeof(Axis), new PropertyMetadata(OnHrefChanged)); #if WPF /// /// Identifies the Visifire.Charts.Axis.Padding dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Padding dependency property. /// public new static readonly DependencyProperty PaddingProperty = DependencyProperty.Register ("Padding", typeof(Thickness), typeof(Axis), new PropertyMetadata(OnPaddingPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.Background dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Background dependency property. /// public new static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register ("Background", typeof(Brush), typeof(Axis), new PropertyMetadata(OnBackgroundPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.Opacity dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Opacity dependency property. /// public new static readonly DependencyProperty OpacityProperty = DependencyProperty.Register ("Opacity", typeof(Double), typeof(Axis), new PropertyMetadata(1.0, OnOpacityPropertyChanged)); #endif /// /// Identifies the Visifire.Charts.Axis.Interval dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Interval dependency property. /// public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register ("Interval", typeof(Nullable), typeof(Axis), new PropertyMetadata(OnIntervalPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.LineColor dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.LineColor dependency property. /// public static readonly DependencyProperty LineColorProperty = DependencyProperty.Register ("LineColor", typeof(Brush), typeof(Axis), new PropertyMetadata(OnLineColorPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.LineThickness dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.LineThickness dependency property. /// public static readonly DependencyProperty LineThicknessProperty = DependencyProperty.Register ("LineThickness", typeof(Double), typeof(Axis), new PropertyMetadata(OnLineThicknessPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.LineStyle dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.LineStyle dependency property. /// public static readonly DependencyProperty LineStyleProperty = DependencyProperty.Register ("LineStyle", typeof(LineStyles), typeof(Axis), new PropertyMetadata(OnLineStylePropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.Title dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Title dependency property. /// public static readonly DependencyProperty TitleProperty = DependencyProperty.Register ("Title", typeof(String), typeof(Axis), new PropertyMetadata(OnTitlePropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.TitleFontColor dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.TitleFontColor dependency property. /// public static readonly DependencyProperty TitleFontColorProperty = DependencyProperty.Register ("TitleFontColor", typeof(Brush), typeof(Axis), new PropertyMetadata(OnTitleFontColorPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.TitleFontFamily dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.TitleFontFamily dependency property. /// public static readonly DependencyProperty TitleFontFamilyProperty = DependencyProperty.Register ("TitleFontFamily", typeof(FontFamily), typeof(Axis), new PropertyMetadata(OnTitleFontFamilyPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.TitleFontSize dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.TitleFontSize dependency property. /// public static readonly DependencyProperty TitleFontSizeProperty = DependencyProperty.Register ("TitleFontSize", typeof(Double), typeof(Axis), new PropertyMetadata(OnTitleFontSizePropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.TitleFontStyle dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.TitleFontStyle dependency property. /// public static readonly DependencyProperty TitleFontStyleProperty = DependencyProperty.Register ("TitleFontStyle", typeof(FontStyle), typeof(Axis), new PropertyMetadata(OnTitleFontStylePropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.TitleFontWeight dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.TitleFontWeight dependency property. /// public static readonly DependencyProperty TitleFontWeightProperty = DependencyProperty.Register ("TitleFontWeight", typeof(FontWeight), typeof(Axis), new PropertyMetadata(OnTitleFontWeightPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.AxisType dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.AxisType dependency property. /// public static readonly DependencyProperty AxisTypeProperty = DependencyProperty.Register ("AxisType", typeof(AxisTypes), typeof(Axis), new PropertyMetadata(OnAxisTypePropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.AxisMaximum dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.AxisMaximum dependency property. /// public static readonly DependencyProperty AxisMaximumProperty = DependencyProperty.Register ("AxisMaximum", typeof(Object), typeof(Axis), new PropertyMetadata(null, OnAxisMaximumPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.AxisMinimum dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.AxisMinimum dependency property. /// public static readonly DependencyProperty AxisMinimumProperty = DependencyProperty.Register ("AxisMinimum", typeof(Object), typeof(Axis), new PropertyMetadata(null, OnAxisMinimumPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.IncludeZero dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.IncludeZero dependency property. /// public static readonly DependencyProperty IncludeZeroProperty = DependencyProperty.Register ("IncludeZero", typeof(Boolean), typeof(Axis), new PropertyMetadata(OnIncludeZeroPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.StartFromZero dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.StartFromZero dependency property. /// public static readonly DependencyProperty StartFromZeroProperty = DependencyProperty.Register ("StartFromZero", typeof(Nullable), typeof(Axis), new PropertyMetadata(OnStartFromZeroPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.Prefix dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Prefix dependency property. /// public static readonly DependencyProperty PrefixProperty = DependencyProperty.Register ("Prefix", typeof(String), typeof(Axis), new PropertyMetadata(OnPrefixPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.Suffix dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Suffix dependency property. /// public static readonly DependencyProperty SuffixProperty = DependencyProperty.Register ("Suffix", typeof(String), typeof(Axis), new PropertyMetadata(OnSuffixPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.ScalingSet dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.ScalingSet dependency property. /// public static readonly DependencyProperty ScalingSetProperty = DependencyProperty.Register ("ScalingSet", typeof(String), typeof(Axis), new PropertyMetadata(OnScalingSetPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.ValueFormatString dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.ValueFormatString dependency property. /// public static readonly DependencyProperty ValueFormatStringProperty = DependencyProperty.Register ("ValueFormatString", typeof(String), typeof(Axis), new PropertyMetadata(OnValueFormatStringPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.ScrollBarOffset dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.ScrollBarOffset dependency property. /// public static readonly DependencyProperty ScrollBarOffsetProperty = DependencyProperty.Register ("ScrollBarOffset", typeof(Double), typeof(Axis), new PropertyMetadata(Double.NaN, OnScrollBarOffsetChanged)); // Using a DependencyProperty as the backing store for ScrollBarScale. This enables animation, styling, binding, etc... public static readonly DependencyProperty ScrollBarScaleProperty = DependencyProperty.Register("ScrollBarScale", typeof(double), typeof(Axis), new PropertyMetadata(Double.NaN, OnScrollBarScalePropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.Enabled dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Enabled dependency property. /// public static readonly DependencyProperty EnabledProperty = DependencyProperty.Register ("Enabled", typeof(Nullable), typeof(Axis), new PropertyMetadata(OnEnabledPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.InternalIntervalType dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.InternalIntervalType dependency property. /// public static readonly DependencyProperty IntervalTypeProperty = DependencyProperty.Register ("IntervalType", typeof(IntervalTypes), typeof(Axis), new PropertyMetadata(OnIntervalTypePropertyChanged)); /// /// Height of the Axis /// #if SL [ScriptableMember] #endif public new Double Height { get; internal set; } /// /// Width of the Axis /// #if SL [ScriptableMember] #endif public new Double Width { get; internal set; } /// /// Get or set the "AxisLabels element" property of the axis /// public IntervalTypes IntervalType { get { return (IntervalTypes)GetValue(IntervalTypeProperty); } set { SetValue(IntervalTypeProperty, value); } } /// /// Get or set the "AxisLabels element" property of the axis /// public AxisLabels AxisLabels { get { return (AxisLabels)GetValue(AxisLabelsProperty); } set { SetValue(AxisLabelsProperty, value); } } /// /// Get or set the Opacity property /// public new Double Opacity { get { return (Double)GetValue(OpacityProperty); } set { #if SL if (Opacity != value) { InternalOpacity = 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 href target property of the axis /// public HrefTargets HrefTarget { get { return (HrefTargets)GetValue(HrefTargetProperty); } set { SetValue(HrefTargetProperty, value); } } /// /// Get or set the href property of the axis /// public String Href { get { return (String)GetValue(HrefProperty); } set { SetValue(HrefProperty, value); } } /// /// Get or set the background property of the axis /// public new Brush Background { get { return (Brush)GetValue(BackgroundProperty); } set { #if SL if (Background != value) { InternalBackground = value; SetValue(BackgroundProperty, value); FirePropertyChanged("Background"); } #else SetValue(BackgroundProperty, value); #endif } } /// /// Get or set the interval for all the axis elements /// #if SL [System.ComponentModel.TypeConverter(typeof(Converters.NullableDoubleConverter))] #endif public Nullable Interval { get { if ((Nullable)GetValue(IntervalProperty) == null) return Double.NaN; else return (Nullable)GetValue(IntervalProperty); } set { SetValue(IntervalProperty, value); _axisIntervalOverride = (Double)value; } } /// /// Get or set the Color of the axis line /// public Brush LineColor { get { return (Brush)GetValue(LineColorProperty); } set { SetValue(LineColorProperty, value); } } /// /// Get or set the thickness of the axis line /// public Double LineThickness { get { return (Double)GetValue(LineThicknessProperty); } set { SetValue(LineThicknessProperty, value); } } /// /// Get or set the style of the axis line. It takes values like "Dashed", "Dotted" etc /// public LineStyles LineStyle { get { return (LineStyles)GetValue(LineStyleProperty); } set { SetValue(LineStyleProperty, value); } } /// /// Get or set the padding of the axis /// public new Thickness Padding { get { return (Thickness)GetValue(PaddingProperty); } set { #if WPF SetValue(PaddingProperty, value); #else InternalPadding = value; SetValue(PaddingProperty, value); FirePropertyChanged("Padding"); #endif } } /// /// Get or set the title for the axis /// public String Title { get { return (String)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } /// /// Get or set the font color for axis title /// public Brush TitleFontColor { get { return (Brush)GetValue(TitleFontColorProperty); } set { SetValue(TitleFontColorProperty, value); } } /// /// Get or set the font family for axis title /// public FontFamily TitleFontFamily { get { return (FontFamily)GetValue(TitleFontFamilyProperty); } set { SetValue(TitleFontFamilyProperty, value); } } /// /// Get or set the font size for axis title /// public Double TitleFontSize { get { return (Double)GetValue(TitleFontSizeProperty); } set { SetValue(TitleFontSizeProperty, value); } } /// /// Get or set Sets the font style for axis title /// public FontStyle TitleFontStyle { get { return (FontStyle)GetValue(TitleFontStyleProperty); } set { SetValue(TitleFontStyleProperty, value); } } /// /// Get or set the font weight for axis title /// public FontWeight TitleFontWeight { get { return (FontWeight)GetValue(TitleFontWeightProperty); } set { SetValue(TitleFontWeightProperty, value); } } /// /// Get or set the axis type (Primary or Secondary) /// public AxisTypes AxisType { get { return (AxisTypes)GetValue(AxisTypeProperty); } set { SetValue(AxisTypeProperty, value); } } /// /// Get or set the maximum value for the axis /// //#if SL // [System.ComponentModel.TypeConverter(typeof(Converters.NullableDoubleConverter))] //#endif public Object AxisMaximum { get { return (Object)GetValue(AxisMaximumProperty); } set { SetValue(AxisMaximumProperty, value); } } /// /// Get or set the minimum value for the axis /// //#if SL // [System.ComponentModel.TypeConverter(typeof(Converters.NullableDoubleConverter))] //#endif public Object AxisMinimum { get { return (Object)GetValue(AxisMinimumProperty); } set { SetValue(AxisMinimumProperty, value); } } /// /// Include zero within the axis range /// public Boolean IncludeZero { get { return (Boolean)GetValue(IncludeZeroProperty); } set { SetValue(IncludeZeroProperty, value); } } /// /// Get or set dateTime from zero property of the axis. /// Forces the axis to include zero or atleast have either AxisMinimum or AxisMaximum as zero /// [System.ComponentModel.TypeConverter(typeof(NullableBoolConverter))] public Nullable StartFromZero { get { if ((Nullable)GetValue(StartFromZeroProperty) == null) { if (AxisRepresentation == AxisRepresentations.AxisY) return true; else return false; } else return (Nullable)GetValue(StartFromZeroProperty); } set { SetValue(StartFromZeroProperty, value); } } /// /// Get or set the prefix for the axis labels used in the axis /// public String Prefix { get { return (String)GetValue(PrefixProperty); } set { SetValue(PrefixProperty, value); } } /// /// Get or set the suffix for the axis labels used in the axis /// public String Suffix { get { return (String)GetValue(SuffixProperty); } set { SetValue(SuffixProperty, value); } } /// /// Get or set the scaling values for the axis /// public String ScalingSet { get { return (String)GetValue(ScalingSetProperty); } set { SetValue(ScalingSetProperty, value); } } /// /// Get or set the format string that can be used with the axis labels /// public String ValueFormatString { get { return String.IsNullOrEmpty((String)GetValue(ValueFormatStringProperty)) ? "###,##0.##" : (String)GetValue(ValueFormatStringProperty); } set { SetValue(ValueFormatStringProperty, value); } } /// /// Get or set scrollbar offset value property of the axis. /// ScrollBarOffset value can be accessed after the chart is rendered. Value range from 0 to 1 /// public Double ScrollBarOffset { get { return (Double)GetValue(ScrollBarOffsetProperty); } set { if (value < 0 || value > 1) throw new Exception("Value does not fall under the expected range. ScrollBarOffset always varies from 0 to 1."); SetValue(ScrollBarOffsetProperty, value); } } /// /// ScrollBarScale sets the size of ScrollBar thumb. /// Example, if ScrollBarScale is set to 0.5, width of ScrollBar thumb will be /// half of the ScrollBar width which in turn increase the PlotArea width to /// double the actual width of PlotArea. /// public Double ScrollBarScale { get { return (Double)GetValue(ScrollBarScaleProperty); } set { if (value <= 0 || value > 1) throw new Exception("Value does not fall under the expected range. ScrollBarScale always varies from 0 to 1."); SetValue(ScrollBarScaleProperty, value); } } /// /// Get or set enabled property of the axis /// [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); } } /// /// Collection of grids for an axis /// public ChartGridCollection Grids { get; set; } /// /// Collection of ticks for an axis /// public TicksCollection Ticks { get; set; } #endregion #region Public Events And Delegates #endregion #region Protected Methods #endregion #region Internal Properties #if SL /// /// Identifies the Visifire.Charts.Axis.Padding dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Padding dependency property. /// private static readonly DependencyProperty InternalPaddingProperty = DependencyProperty.Register ("InternalPadding", typeof(Thickness), typeof(Axis), new PropertyMetadata(OnPaddingPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.Opacity dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Opacity dependency property. /// private static readonly DependencyProperty InternalOpacityProperty = DependencyProperty.Register ("InternalOpacity", typeof(Double), typeof(Axis), new PropertyMetadata(1.0, OnOpacityPropertyChanged)); /// /// Identifies the Visifire.Charts.Axis.Background dependency property. /// /// /// The identifier for the Visifire.Charts.Axis.Background dependency property. /// private static readonly DependencyProperty InternalBackgroundProperty = DependencyProperty.Register ("InternalBackground", typeof(Brush), typeof(Axis), new PropertyMetadata(OnBackgroundPropertyChanged)); #endif /// /// Get or set the Background property of title /// internal Brush InternalBackground { get { return (Brush)((_internalBackground == null) ? GetValue(BackgroundProperty) : _internalBackground); } set { _internalBackground = value; } } /// /// Get or set the Padding property of title /// public Thickness InternalPadding { get { return (Thickness)((_internalPadding == null) ? GetValue(PaddingProperty) : _internalPadding); } set { _internalPadding = value; } } /// /// Get or set the Opacity property /// internal Double InternalOpacity { get { return (Double)(Double.IsNaN(_internalOpacity) ? GetValue(OpacityProperty) : _internalOpacity); } set { _internalOpacity = value; } } /// /// AxisMinimum Numeric value /// internal Double AxisMinimumNumeric = Double.NaN; /// /// AxisMinimum DateTime value /// internal DateTime AxisMinimumDateTime; /// /// AxisMaximum numeric value /// internal Double AxisMaximumNumeric = Double.NaN; /// /// AxisMaximum DateTime value /// internal DateTime AxisMaximumDateTime; /// /// Internal interval type used to handle auto interval type /// internal IntervalTypes InternalIntervalType { get; set; } /// /// Axis is a DateTime axis /// internal Boolean IsDateTimeAxis { get; set; } /// /// Axis XValue Types /// internal ChartValueTypes XValueType { get; set; } /// /// Axis Minimum Date /// internal DateTime MinDate { get; set; } /// /// Axis Maximum Date /// internal DateTime MaxDate { get; set; } internal TimeSpan MinDateRange { get; set; } internal TimeSpan MaxDateRange { get; set; } /// /// Returns the visual element for the Axis /// internal StackPanel Visual { get; set; } /// /// Internal axis minimum is used for internal calculation purpose /// internal Double InternalAxisMinimum { get; set; } /// /// Internal axis maximum is used for internal calculation purpose /// internal Double InternalAxisMaximum { get; set; } /// /// Internal interval is used for internal calculation purpose /// internal Double InternalInterval { get; set; } /// /// Keep tracks about current offsetvalue of the axis scrollviewer /// internal Double CurrentScrollScrollBarOffset { get; set; } /// /// Get or set the data maximum for the axis /// internal Double Maximum { get; set; } /// /// Get or set the data minimum for the axis /// internal Double Minimum { get; set; } /// /// Get or set majorgrid element /// internal ChartGrid MajorGridsElement { get; set; } /// /// Get or set the scroll bar /// internal ScrollBar ScrollBarElement { get; set; } /// /// Get or set axis scrollviewer element /// internal Canvas ScrollViewerElement { get; set; } /// /// Get or set the major ticks /// internal Ticks MajorTicksElement { get; set; } /// /// Get or set the axis title element /// internal Title AxisTitleElement { get; set; } /// /// Get or set the axis manager of the axis /// internal AxisManager AxisManager { get; set; } /// /// Scrollable size of PlotArea /// internal Double ScrollableSize { get; set; } /// /// Line for axis /// internal Line AxisLine { get; set; } /// /// Get or set the axis orientation. /// Vertical = AxisY for all types except bar, /// Horizontal = AxesX for types except bar /// internal Orientation AxisOrientation { get { return _orientation; } set { _orientation = value; } } /// /// Get or set the axis representation /// internal AxisRepresentations AxisRepresentation { get; set; } /// /// Details about plot groups /// internal PlotDetails PlotDetails { get; set; } /// /// Scale values of axis /// internal List ScaleValues { get { return _scaleValues; } } /// /// Scale units of axis /// internal List ScaleUnits { get { return _scaleUnits; } } /// /// Get or set the axis dateTime offset /// internal Double StartOffset { get; set; } /// /// Get or set the axis end offset /// internal Double EndOffset { get; set; } /// /// Get or set the axis skip offset /// internal Int32 SkipOffset { get; set; } #endregion #region Private Properties /// /// StackPanel used for internal purpose /// private Canvas InternalStackPanel { get; set; } #region Hidden Control Properties /// /// Get or set /// private new FontFamily FontFamily { get; set; } private new static DependencyProperty FontFamilyProperty = DependencyProperty.Register ("FontFamily", typeof(FontFamily), typeof(Axis), null); private new Double FontSize { get; set; } private new static DependencyProperty FontSizeProperty = DependencyProperty.Register ("FontSize", typeof(Double), typeof(Axis), null); private new FontStretch FontStretch { get; set; } private new static DependencyProperty FontStretchProperty = DependencyProperty.Register ("FontStretch", typeof(FontStretch), typeof(Axis), null); private new FontStyle FontStyle { get; set; } private new static DependencyProperty FontStyleProperty = DependencyProperty.Register ("FontStyle", typeof(FontStyle), typeof(Axis), null); private new FontWeight FontWeight { get; set; } private new static DependencyProperty FontWeightProperty = DependencyProperty.Register ("FontWeight", typeof(FontWeight), typeof(Axis), null); private new Brush Foreground { get; set; } private new static DependencyProperty ForegroundProperty = DependencyProperty.Register ("Foreground", typeof(Brush), typeof(Axis), null); private new Thickness BorderThickness { get; set; } private new static DependencyProperty BorderThicknessProperty = DependencyProperty.Register ("BorderThickness", typeof(Thickness), typeof(Axis), null); private new Brush BorderBrush { get; set; } private new static DependencyProperty BorderBrushProperty = DependencyProperty.Register ("BorderBrush", typeof(Brush), typeof(Axis), null); #endregion #endregion #region Private Delegates #endregion #region Private Methods // /// Event handler attached with Padding property changed event of AxisLabels elements /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnPaddingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.InternalPadding = (Thickness)e.NewValue; axis.FirePropertyChanged("Padding"); } /// /// Event handler manages background property change of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnBackgroundPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.InternalBackground = (Brush)e.NewValue; axis.FirePropertyChanged("Background"); } /// /// OpacityProperty changed call back function /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnOpacityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.InternalOpacity= (Double) e.NewValue; axis.FirePropertyChanged("Opacity"); } /// /// Event handler manages axislabels property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnAxisLabelsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; if (axis.Chart != null) axis.AxisLabels.Chart = axis.Chart; axis.AxisLabels.Parent = axis; axis.AxisLabels.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(AxisLabels_PropertyChanged); axis.FirePropertyChanged("AxisLabels"); } /// /// Event handler manages property change event of axislabels element /// /// ObservableObject /// PropertyChangedEventArgs private static void AxisLabels_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { (sender as AxisLabels).Parent.FirePropertyChanged(e.PropertyName); } /// /// Event handler manages href target property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnHrefTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("HrefTarget"); } /// /// Event handler manages href property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnHrefChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("Href"); } /// /// Event handler manages interval property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnIntervalPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("Interval"); } /// /// Event handler manages linecolor property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnLineColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("LineColor"); } /// /// Event handler manages linethickness property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnLineThicknessPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("LineThickness"); } /// /// Event handler manages linestyle property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnLineStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("LineStyle"); } /// /// Event handler manages title property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnTitlePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("Title"); } /// /// Event handler manages titlefontcolor property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnTitleFontColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("TitleFontColor"); } /// /// Event handler manages titlefontfamily property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnTitleFontFamilyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("TitleFontFamily"); } /// /// Event handler manages titlefontsize property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnTitleFontSizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("TitleFontSize"); } /// /// Event handler manages titlefontstyle property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnTitleFontStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("TitleFontStyle"); } /// /// Event handler manages title fontweight property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnTitleFontWeightPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("TitleFontWeight"); } /// /// Event handler manages axistype property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnAxisTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("AxisType"); } /// /// Event handler manages axis maximum property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnAxisMaximumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; Double numericVal = axis.AxisMaximumNumeric; DateTime dateTimeValue = axis.AxisMaximumDateTime; Axis.ConvertValueToDateTimeOrNumeric("AxisMaximum", e.NewValue, ref numericVal, ref dateTimeValue, out axis._axisMaximumValueType); axis.AxisMaximumNumeric = numericVal; axis.AxisMaximumDateTime = dateTimeValue; axis.FirePropertyChanged("AxisMaximum"); } /// /// Event handler manages axis minimum property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnAxisMinimumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; Double numericVal = axis.AxisMinimumNumeric; DateTime dateTimeValue = axis.AxisMinimumDateTime; Axis.ConvertValueToDateTimeOrNumeric("AxisMinimum", e.NewValue, ref numericVal, ref dateTimeValue, out axis._axisMinimumValueType); axis.AxisMinimumNumeric = numericVal; axis.AxisMinimumDateTime = dateTimeValue; axis.FirePropertyChanged("AxisMinimum"); } private static void ConvertValueToDateTimeOrNumeric(String propertyName, Object newValue, ref Double numericVal, ref DateTime dateTimeValue, out ChartValueTypes valueType) { // Double / Int32 value entered in Managed Code if (newValue.GetType().Equals(typeof(Double)) || newValue.GetType().Equals(typeof(Int32))) { numericVal = Convert.ToDouble(newValue); valueType = ChartValueTypes.Numeric; } // DateTime value entered in Managed Code else if ((newValue.GetType().Equals(typeof(DateTime)))) { dateTimeValue = (DateTime)newValue; valueType = ChartValueTypes.DateTime; } // Double / Int32 / DateTime entered in XAML else if ((newValue.GetType().Equals(typeof(String)))) { DateTime dateTimeresult; Double doubleResult; if (String.IsNullOrEmpty(newValue.ToString())) { numericVal = Double.NaN; valueType = ChartValueTypes.Numeric; } // Double entered in XAML else if (Double.TryParse((string)newValue, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.InvariantCulture, out doubleResult)) { numericVal = doubleResult; valueType = ChartValueTypes.Numeric; } // DateTime entered in XAML else if (DateTime.TryParse((string)newValue, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dateTimeresult)) { dateTimeValue = dateTimeresult; valueType = ChartValueTypes.DateTime; } else { System.Diagnostics.Debug.WriteLine("Invalid Input for " + propertyName); throw new Exception("Invalid Input for " + propertyName); } } else { System.Diagnostics.Debug.WriteLine("Invalid Input for " + propertyName); throw new Exception("Invalid Input for " + propertyName); } } /// /// Event handler manages include zero property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnIncludeZeroPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("IncludeZero"); } /// /// Event handler manages dateTime from zero property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnStartFromZeroPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("StartFromZero"); } /// /// Event handler manages prefix property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnPrefixPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("Prefix"); } /// /// Event handler manages suffix property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnSuffixPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("Suffix"); } /// /// Event handler manages scaling set property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnScalingSetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.ParseScalingSets((String)e.NewValue); axis.FirePropertyChanged("ScalingSet"); } /// /// Event handler manages value format string property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnValueFormatStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("ValueFormatString"); } /// /// Event handler manages scrollbar offset property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnScrollBarOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; if (axis._isScrollToOffsetEnabled) axis.SetScrollBarValueFromOffset((Double)e.NewValue); } private static void OnScrollBarScalePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; //if (axis._isScrollToOffsetEnabled) // axis.SetScrollBarValueFromOffset((Double)e.NewValue); axis.FirePropertyChanged("ScrollBarScale"); if (axis.Chart != null && (axis.Chart as Chart).ChartArea != null) { if (axis.IsNotificationEnable) { (axis.Chart as Chart).ChartArea.IsAutoCalculatedScrollBarScale = false; } else { (axis.Chart as Chart).ChartArea.IsAutoCalculatedScrollBarScale = true; } } } /// /// Event handler manages enabled property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.FirePropertyChanged("Enabled"); } /// /// Event handler manages interval type property change event of axis /// /// DependencyObject /// DependencyPropertyChangedEventArgs private static void OnIntervalTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Axis axis = d as Axis; axis.InternalIntervalType = (IntervalTypes)e.NewValue; axis.FirePropertyChanged("IntervalType"); } /// /// Set up axis manager and calculate axis values /// private void SetUpAxisManager() { // Get the minimum and maximum value dependeing on the axis representation value Minimum = AxisRepresentation == AxisRepresentations.AxisX ? PlotDetails.GetAxisXMinimumDataValue(this) : PlotDetails.GetAxisYMinimumDataValue(this); Maximum = AxisRepresentation == AxisRepresentations.AxisX ? PlotDetails.GetAxisXMaximumDataValue(this) : PlotDetails.GetAxisYMaximumDataValue(this); Boolean overflowValidity = (AxisRepresentation == AxisRepresentations.AxisX); Boolean stackingOverride = PlotDetails.GetStacked100OverrideState(); // Create and initialize the AxisManagers AxisManager = new AxisManager(Maximum, Minimum, (Boolean)StartFromZero, overflowValidity, stackingOverride, AxisRepresentation); // Set the include zero state AxisManager.IncludeZero = IncludeZero; // settings specific to axis X if (AxisRepresentation == AxisRepresentations.AxisX) { Double interval = GenerateDefaultInterval(); if (IsDateTimeAxis) { if (interval > 0 || !Double.IsNaN(interval)) { AxisManager.Interval = interval; InternalInterval = interval; } else { // if interval is greater than zero then set the interval of the axis manager if (Interval > 0 || !Double.IsNaN((Double)Interval)) { AxisManager.Interval = (Double)Interval; InternalInterval = (Double)Interval; } } } else if (interval > 0 || !Double.IsNaN(interval)) { AxisManager.Interval = interval; InternalInterval = interval; } } else { // if interval is greater than zero then set the interval of the axis manager if (Interval > 0 || !Double.IsNaN((Double)Interval)) { AxisManager.Interval = (Double)Interval; InternalInterval = (Double)Interval; } } // set the axis maximum value if user has provided it if (!Double.IsNaN((Double)AxisMaximumNumeric)) { AxisManager.AxisMaximumValue = (Double)AxisMaximumNumeric; InternalAxisMaximum = (Double)AxisMaximumNumeric; } // set the axis minimum value if the user has provided it if (!Double.IsNaN((Double)AxisMinimumNumeric)) { AxisManager.AxisMinimumValue = (Double)AxisMinimumNumeric; InternalAxisMinimum = (Double)AxisMinimumNumeric; } // Calculate the various parameters for creating the axis AxisManager.Calculate(); // Set axis specific limits based on axis limits. // if (AxisRepresentation == AxisRepresentations.AxisX && !(Boolean)StartFromZero) // if (!SetAxesXLimits()) // return; if (AxisRepresentation == AxisRepresentations.AxisX) if (!SetAxesXLimits()) return; // Settings specific to axis y if (this.AxisRepresentation == AxisRepresentations.AxisY && this.AxisType == AxisTypes.Primary) { // Set the internal axis limits the one obtained from axis manager InternalAxisMaximum = AxisManager.AxisMaximumValue; InternalAxisMinimum = AxisManager.AxisMinimumValue; } else if (this.AxisRepresentation == AxisRepresentations.AxisY && this.AxisType == AxisTypes.Secondary) { var axisYPrimary = (from axis in (Chart as Chart).InternalAxesY where axis.AxisRepresentation == AxisRepresentations.AxisY && axis.AxisType == AxisTypes.Primary select axis); Axis primaryAxisY = null; if (axisYPrimary.Count() > 0) primaryAxisY = axisYPrimary.First(); if (Double.IsNaN((double)Interval) && primaryAxisY != null) { // number of interval in the primary axis Double primaryAxisIntervalCount = ((double)primaryAxisY.InternalAxisMaximum - (double)primaryAxisY.InternalAxisMinimum) / (double)primaryAxisY.InternalInterval; // This will set the internal overriding flag AxisManager.AxisMinimumValue = AxisManager.AxisMinimumValue; AxisManager.AxisMaximumValue = AxisManager.AxisMaximumValue; // This interval will reflect the interval in primary axis it is not same as that of primary axis AxisManager.Interval = (AxisManager.AxisMaximumValue - AxisManager.AxisMinimumValue) / primaryAxisIntervalCount; AxisManager.Calculate(); } InternalAxisMaximum = AxisManager.AxisMaximumValue; InternalAxisMinimum = AxisManager.AxisMinimumValue; } else { // Set the internal axis limits the one obtained from axis manager InternalAxisMaximum = AxisManager.AxisMaximumValue; InternalAxisMinimum = AxisManager.AxisMinimumValue; } InternalInterval = AxisManager.Interval; } /// /// Applies setting for vertical type axis /// private void ApplyVerticalAxisSettings() { // Apply settings based on the axis type switch (AxisType) { case AxisTypes.Primary: ApplyVerticalPrimaryAxisSettings(); break; case AxisTypes.Secondary: ApplyVerticalSecondaryAxisSettings(); break; } } /// /// Apply axis title properties /// private void ApplyTitleProperties() { #region Apply AxisTitle Properties AxisTitleElement.IsNotificationEnable = false; if (this.TitleFontFamily != null) AxisTitleElement.InternalFontFamily = this.TitleFontFamily; if (this.TitleFontSize != 0) AxisTitleElement.InternalFontSize = this.TitleFontSize; if (this.TitleFontStyle != null) AxisTitleElement.InternalFontStyle = this.TitleFontStyle; if (this.TitleFontWeight != null) AxisTitleElement.InternalFontWeight = this.TitleFontWeight; if (!String.IsNullOrEmpty(this.Title) && String.IsNullOrEmpty(AxisTitleElement.Text)) AxisTitleElement.Text = GetFormattedMultilineText(this.Title); AxisTitleElement.InternalFontColor = Visifire.Charts.Chart.CalculateFontColor((Chart as Chart), this.TitleFontColor, false); AxisTitleElement.IsNotificationEnable = true; #endregion } /// /// Create line for axis /// /// Y1 /// Y2 /// X1 /// X2 /// Axis width /// Axis height private void CreateAxisLine(Double y1, Double y2, Double x1, Double x2, Double width, Double height) { AxisLine = new Line() { Y1 = y1, Y2 = y2, X1 = x1, X2 = x2, Width = width, Height = height }; AxisLine.StrokeThickness = LineThickness; AxisLine.Stroke = LineColor; AxisLine.StrokeDashArray = ExtendedGraphics.GetDashArray(LineStyle); } /// /// Clip vertical axis /// /// Ticks width private void ClipVerticalAxis(Double ticksWidth) { // Clip at top or bottom of the scrallable axis in order to avoid axislabel clip if (Height != ScrollableSize) { // clip addition value at top or bottom of the scrallable axis in order to avoid axislabel clip Double clipAdditionValue = 4; PathGeometry pathGeometry = new PathGeometry(); pathGeometry.Figures = new PathFigureCollection(); PathFigure pathFigure = new PathFigure(); pathFigure.StartPoint = new Point(0, -(clipAdditionValue - 1)); pathFigure.Segments = new PathSegmentCollection(); // Do not change the order of the lines below // Segmens required to create the rectangle pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(ScrollViewerElement.Width - ticksWidth, -(clipAdditionValue - 1)))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(ScrollViewerElement.Width - ticksWidth, 0))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(ScrollViewerElement.Width, 0))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(ScrollViewerElement.Width, Height))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(ScrollViewerElement.Width - ticksWidth, Height))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(ScrollViewerElement.Width - ticksWidth, Height + clipAdditionValue))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(0, Height + clipAdditionValue))); pathGeometry.Figures.Add(pathFigure); ScrollViewerElement.Clip = pathGeometry; } } /// /// Applies setting for primary vertical axis (Primary axis Y or Primary axis X in Bar) /// private void ApplyVerticalPrimaryAxisSettings() { // Set the parameters fo the Axis Stack panel Visual.Children.Add(new Border() { Width = this.InternalPadding.Left }); Visual.HorizontalAlignment = HorizontalAlignment.Left; Visual.VerticalAlignment = VerticalAlignment.Stretch; Visual.Orientation = Orientation.Horizontal; InternalStackPanel.Width = 0; InternalStackPanel.HorizontalAlignment = HorizontalAlignment.Left; InternalStackPanel.VerticalAlignment = VerticalAlignment.Stretch; ScrollViewerElement.VerticalAlignment = VerticalAlignment.Stretch; // Set the parameters for the scroll bar ScrollBarElement.Orientation = Orientation.Vertical; ScrollBarElement.Width = 10; // Set the parameters for the axis labels AxisLabels.Placement = PlacementTypes.Left; AxisLabels.Height = ScrollableSize; CreateAxisLine(StartOffset, Height - EndOffset, LineThickness / 2, LineThickness / 2, LineThickness, this.Height); // Set parameters for the Major Grids foreach (ChartGrid grid in Grids) grid.Placement = PlacementTypes.Left; // Generate the visual object for the required elements AxisLabels.CreateVisualObject(); // Set the alignement for the axis Title AxisTitleElement.InternalHorizontalAlignment = HorizontalAlignment.Left; AxisTitleElement.InternalVerticalAlignment = VerticalAlignment.Center; CreateAxisTitleVisual(new Thickness(INNER_MARGIN, 0, INNER_MARGIN, 0)); // Place the visual elements in the axis stack panel if (!String.IsNullOrEmpty(Title)) { Visual.Children.Add(AxisTitleElement.Visual); } if (AxisLabels.Visual != null) { InternalStackPanel.Width += AxisLabels.Visual.Width; if (Height == ScrollableSize) { if (AxisLabels.Visual != null) Visual.Children.Add(AxisLabels.Visual); } else { InternalStackPanel.Children.Add(AxisLabels.Visual); } } Double ticksWidth = 0; List ticks = Ticks.Reverse().ToList(); foreach (Ticks tick in ticks) { tick.SetParms(PlacementTypes.Left, Double.NaN, ScrollableSize); tick.CreateVisualObject(); if (tick.Visual != null) { if (Height == ScrollableSize) Visual.Children.Add(tick.Visual); else { InternalStackPanel.Children.Add(tick.Visual); tick.Visual.SetValue(Canvas.LeftProperty, InternalStackPanel.Width + ticksWidth); ticksWidth += tick.Visual.Width; } } } InternalStackPanel.Width += ticksWidth; if (Height != ScrollableSize) { ScrollViewerElement.Children.Add(InternalStackPanel); Visual.Children.Add(ScrollViewerElement); } Visual.Children.Add(AxisLine); InternalStackPanel.Width += AxisLine.Width; ScrollViewerElement.Width = InternalStackPanel.Width; ClipVerticalAxis(ticksWidth); } /// /// Applies setting for secondary vertical axis (Secondary axis Y or Secondary axis X in Bar) /// private void ApplyVerticalSecondaryAxisSettings() { // Set the parameters fo the Axis Stack panel Visual.HorizontalAlignment = HorizontalAlignment.Right; Visual.VerticalAlignment = VerticalAlignment.Stretch; Visual.Orientation = Orientation.Horizontal; InternalStackPanel.HorizontalAlignment = HorizontalAlignment.Right; InternalStackPanel.VerticalAlignment = VerticalAlignment.Stretch; InternalStackPanel.SizeChanged += delegate(object sender, SizeChangedEventArgs e) { ScrollViewerElement.Width = e.NewSize.Width; }; ScrollViewerElement.VerticalAlignment = VerticalAlignment.Stretch; // Set the parameters for the scroll bar ScrollBarElement.Orientation = Orientation.Vertical; ScrollBarElement.Width = 10; // Set the parameters for the axis labels AxisLabels.Placement = PlacementTypes.Right; AxisLabels.Height = ScrollableSize; CreateAxisLine(StartOffset, Height - EndOffset, LineThickness / 2, LineThickness / 2, LineThickness, this.Height); // Set parameters for the Major Grids foreach (ChartGrid grid in Grids) grid.Placement = PlacementTypes.Right; // Set the alignement for the axis Title AxisTitleElement.InternalHorizontalAlignment = HorizontalAlignment.Right; AxisTitleElement.InternalVerticalAlignment = VerticalAlignment.Center; // Generate the visual object for the required elements AxisLabels.CreateVisualObject(); // Place the visual elements in the axis stack panel Visual.Children.Add(AxisLine); foreach (Ticks tick in Ticks) { tick.SetParms(PlacementTypes.Right, Double.NaN, ScrollableSize); tick.CreateVisualObject(); if (tick.Visual != null) { if (Height == ScrollableSize) Visual.Children.Add(tick.Visual); else InternalStackPanel.Children.Add(tick.Visual); } } if (Height == ScrollableSize) { if (AxisLabels.Visual != null) Visual.Children.Add(AxisLabels.Visual); } else { InternalStackPanel.Children.Add(AxisLabels.Visual); ScrollViewerElement.Children.Add(InternalStackPanel); Visual.Children.Add(ScrollViewerElement); } CreateAxisTitleVisual(new Thickness(INNER_MARGIN, 0, INNER_MARGIN, 0)); if (!String.IsNullOrEmpty(Title)) { Visual.Children.Add(AxisTitleElement.Visual); } Visual.Children.Add(new Border() { Width = this.InternalPadding.Right }); } /// /// Applies setting for primary horizontal axis (Primary axis X or Primary axis Y in Bar) /// private void ApplyHorizontalPrimaryAxisSettings() { // Set the parameters fo the Axis Stack panel Visual.HorizontalAlignment = HorizontalAlignment.Stretch; Visual.VerticalAlignment = VerticalAlignment.Bottom; Visual.Orientation = Orientation.Vertical; InternalStackPanel.Height = 0; InternalStackPanel.HorizontalAlignment = HorizontalAlignment.Stretch; InternalStackPanel.VerticalAlignment = VerticalAlignment.Bottom; ScrollViewerElement.HorizontalAlignment = HorizontalAlignment.Stretch; // Set the parameters for the scroll bar ScrollBarElement.Orientation = Orientation.Horizontal; ScrollBarElement.Height = 10; // Set the parameters for the axis labels AxisLabels.Placement = PlacementTypes.Bottom; AxisLabels.Width = ScrollableSize; CreateAxisLine(LineThickness / 2, LineThickness / 2, StartOffset, Width - EndOffset, this.Width, LineThickness); // Set parameters for the Major Grids foreach (ChartGrid grid in Grids) grid.Placement = PlacementTypes.Bottom; // Set the alignement for the axis Title AxisTitleElement.InternalHorizontalAlignment = HorizontalAlignment.Center; AxisTitleElement.InternalVerticalAlignment = VerticalAlignment.Bottom; // Generate the visual object for the required elements AxisLabels.CreateVisualObject(); // Place the visual elements in the axis stack panel Visual.Children.Add(AxisLine); Double ticksHeight = 0; //AxisLabels.Visual.Background = new SolidColorBrush(Colors.Orange); foreach (Ticks tick in Ticks) { tick.SetParms(PlacementTypes.Bottom, ScrollableSize, Double.NaN); tick.CreateVisualObject(); if (tick.Visual != null) { if (Width == ScrollableSize) Visual.Children.Add(tick.Visual); else { InternalStackPanel.Children.Add(tick.Visual); tick.Visual.SetValue(Canvas.TopProperty, ticksHeight); ticksHeight += tick.Visual.Height; } } } InternalStackPanel.Height += ticksHeight; if (Width == ScrollableSize) { if (AxisLabels.Visual != null) Visual.Children.Add(AxisLabels.Visual); } else { if (AxisLabels.Visual != null) { InternalStackPanel.Width = AxisLabels.Visual.Width; AxisLabels.Visual.SetValue(Canvas.TopProperty, InternalStackPanel.Height); InternalStackPanel.Children.Add(AxisLabels.Visual); InternalStackPanel.Height += AxisLabels.Visual.Height; } ScrollViewerElement.Children.Add(InternalStackPanel); Visual.Children.Add(ScrollViewerElement); } ScrollViewerElement.Height = InternalStackPanel.Height; ClipHorizontalAxis(ticksHeight); CreateAxisTitleVisual(new Thickness(0, INNER_MARGIN, 0, INNER_MARGIN)); if (!String.IsNullOrEmpty(Title)) { Visual.Children.Add(AxisTitleElement.Visual); } Visual.Children.Add(new Border() { Height = this.InternalPadding.Bottom }); } /// /// Clip horizontal axis /// /// Ticks height private void ClipHorizontalAxis(Double ticksHeight) { // Clip at left or right the scrallable axis in order to avoid axislabel clip if (Width != ScrollableSize) { // clip addition value at right or left of the scrallable axis in order to avoid axislabel clip Double clipAdditionValue = 4; PathGeometry pathGeometry = new PathGeometry(); pathGeometry.Figures = new PathFigureCollection(); PathFigure pathFigure = new PathFigure(); pathFigure.StartPoint = new Point(0, 0); pathFigure.Segments = new PathSegmentCollection(); // Do not change the order of the lines below pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(Width, 0))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(Width, ticksHeight))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(Width + clipAdditionValue, ticksHeight))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(Width + clipAdditionValue, ScrollViewerElement.Height))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(-clipAdditionValue, ScrollViewerElement.Height))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(-clipAdditionValue, ticksHeight))); pathFigure.Segments.Add(Graphics.GetLineSegment(new Point(0, ticksHeight))); pathGeometry.Figures.Add(pathFigure); ScrollViewerElement.Clip = pathGeometry; } } /// /// Applies setting for secondary horizontal axis (Secondary axis X or Secondary axis Y in Bar) /// private void ApplyHorizontalSecondaryAxisSettings() { // Set the parameters fo the Axis Stack panel Visual.Children.Add(new Border() { Height = this.InternalPadding.Top }); Visual.HorizontalAlignment = HorizontalAlignment.Stretch; Visual.VerticalAlignment = VerticalAlignment.Top; Visual.Orientation = Orientation.Vertical; InternalStackPanel.HorizontalAlignment = HorizontalAlignment.Stretch; InternalStackPanel.VerticalAlignment = VerticalAlignment.Top; InternalStackPanel.SizeChanged += delegate(object sender, SizeChangedEventArgs e) { ScrollViewerElement.Height = e.NewSize.Height; }; ScrollViewerElement.HorizontalAlignment = HorizontalAlignment.Stretch; // Set the parameters for the scroll bar ScrollBarElement.Orientation = Orientation.Horizontal; ScrollBarElement.Height = 10; // Set the parameters for the axis labels AxisLabels.Placement = PlacementTypes.Top; AxisLabels.Width = ScrollableSize; CreateAxisLine(LineThickness / 2, LineThickness / 2, StartOffset, Width - EndOffset, this.Width, LineThickness); // Set parameters for the Major Grids foreach (ChartGrid grid in Grids) grid.Placement = PlacementTypes.Top; // Set the alignement for the axis Title AxisTitleElement.InternalHorizontalAlignment = HorizontalAlignment.Center; AxisTitleElement.InternalVerticalAlignment = VerticalAlignment.Top; AxisLabels.CreateVisualObject(); CreateAxisTitleVisual(new Thickness(0, INNER_MARGIN, 0, INNER_MARGIN)); // Place the visual elements in the axis stack panel if (!String.IsNullOrEmpty(Title)) { Visual.Children.Add(AxisTitleElement.Visual); } if (AxisLabels.Visual != null) { if (Width == ScrollableSize) Visual.Children.Add(AxisLabels.Visual); else InternalStackPanel.Children.Add(AxisLabels.Visual); } List ticks = Ticks.Reverse().ToList(); foreach (Ticks tick in ticks) { tick.SetParms(PlacementTypes.Top, ScrollableSize, Double.NaN); tick.CreateVisualObject(); if (tick.Visual != null) { if (Width == ScrollableSize) Visual.Children.Add(tick.Visual); else InternalStackPanel.Children.Add(tick.Visual); } } if (Width != ScrollableSize) { ScrollViewerElement.Children.Add(InternalStackPanel); Visual.Children.Add(ScrollViewerElement); } Visual.Children.Add(AxisLine); } /// /// Create axis title visual /// /// Margin between axis title and axis scale private void CreateAxisTitleVisual(Thickness margin) { AxisTitleElement.InternalMargin = margin; AxisTitleElement.IsNotificationEnable = false; RECAL: AxisTitleElement.CreateVisualObject(new ElementData() { Element = this }); #if WPF AxisTitleElement.Visual.FlowDirection = FlowDirection.LeftToRight; #endif Size size = Graphics.CalculateVisualSize(AxisTitleElement.Visual); if (AxisOrientation == Orientation.Horizontal) { if (size.Width > Width && Width != 0) { if (AxisTitleElement.InternalFontSize == 0.2) goto RETURN; AxisTitleElement.InternalFontSize -= 0.2; goto RECAL; } } else { if (size.Height > Height && Height != 0) { if (AxisTitleElement.InternalFontSize == 0.2) goto RETURN; AxisTitleElement.InternalFontSize -= 0.2; goto RECAL; } } RETURN: AxisTitleElement.IsNotificationEnable = true; } /// /// Set the axis limits considering the width of the columns that will be drawn in the chart /// private bool SetAxesXLimits() { //if (PlotDetails.DrawingDivisionFactor > 0) { if (!SetAxisLimitForMinimumGap()) return false; } MatchLeftAndRightGaps(); return true; } /// /// Set the limits such that the gap between plot area and the Columns will be minimum /// private bool SetAxisLimitForMinimumGap() { Double minimumDifference = PlotDetails.GetMaxOfMinDifferencesForXValue(); Double minValue = minimumDifference; if (Double.IsInfinity(minValue)) { minValue = (AxisManager.AxisMaximumValue - AxisManager.AxisMinimumValue) * .8; } if (AxisMinimum != null && IsDateTimeAxis) { AxisMinimumNumeric = DateTimeHelper.DateDiff(AxisMinimumDateTime, MinDate, MinDateRange, MaxDateRange, InternalIntervalType, XValueType); AxisManager.AxisMinimumValue = AxisMinimumNumeric; AxisManager.Calculate(); } if (AxisMaximum != null && IsDateTimeAxis) { AxisMaximumNumeric = DateTimeHelper.DateDiff(AxisMaximumDateTime, MinDate, MinDateRange, MaxDateRange, InternalIntervalType, XValueType); AxisManager.AxisMaximumValue = AxisMaximumNumeric; AxisManager.Calculate(); } if (Double.IsNaN((Double)AxisMinimumNumeric) && !(Boolean)StartFromZero) { if (PlotDetails.DrawingDivisionFactor != 0) { AxisManager.AxisMinimumValue = AxisManager.MinimumValue - (minValue / 2 * 1.1); } else { AxisManager.AxisMinimumValue = AxisManager.MinimumValue - (minValue) / 2 * .4; } if (XValueType != ChartValueTypes.Numeric) { DateTime startDate; Double start; startDate = DateTimeHelper.AlignDateTime(MinDate, 1, InternalIntervalType); start = DateTimeHelper.DateDiff(startDate, MinDate, MinDateRange, MaxDateRange, InternalIntervalType, XValueType); if (AxisManager.AxisMinimumValue > start) { AxisManager.AxisMinimumValue = start; } else { Double temp = Math.Floor((start - AxisManager.AxisMinimumValue) / InternalInterval); if (!Double.IsInfinity(temp) && temp >= 1) start = (start - Math.Floor(temp) * InternalInterval); } DateTime tempFirstLabelDate = DateTimeHelper.XValueToDateTime(MinDate, start, InternalIntervalType); FirstLabelDate = DateTimeHelper.AlignDateTime(tempFirstLabelDate, InternalInterval < 1 ? InternalInterval : 1, InternalIntervalType); FirstLabelPosition = DateTimeHelper.DateDiff(FirstLabelDate, MinDate, MinDateRange, MaxDateRange, InternalIntervalType, XValueType); if (AxisManager.AxisMinimumValue > FirstLabelPosition) { FirstLabelDate = tempFirstLabelDate; FirstLabelPosition = DateTimeHelper.DateDiff(FirstLabelDate, MinDate, MinDateRange, MaxDateRange, InternalIntervalType, XValueType); } } } else { if (!Double.IsNaN(AxisMinimumNumeric)) AxisManager.AxisMinimumValue = (Double)AxisMinimumNumeric; FirstLabelPosition = AxisManager.AxisMinimumValue; if (XValueType != ChartValueTypes.Numeric) FirstLabelDate = DateTimeHelper.XValueToDateTime(MinDate, AxisManager.AxisMinimumValue, InternalIntervalType); } if (Double.IsNaN((Double)AxisMaximumNumeric)) { if (PlotDetails.DrawingDivisionFactor != 0 && Double.IsNaN((Double)AxisMaximumNumeric)) { AxisManager.AxisMaximumValue = AxisManager.MaximumValue + (minValue) / 2 * 1.1; } else { AxisManager.AxisMaximumValue = AxisManager.MaximumValue + (minValue) / 2 * .4; } } else { AxisManager.AxisMaximumValue = (Double)AxisMaximumNumeric; } return true; } internal Double FirstLabelPosition { get; set; } internal DateTime FirstLabelDate { get; set; } /// /// Calculate and set axis manager maximum and minimum value in order to match equal gaps at the right and left side of the chart /// private void MatchLeftAndRightGaps() { Double minimumDifference = PlotDetails.GetMaxOfMinDifferencesForXValue(); if (Double.IsNaN((Double)AxisMinimumNumeric)) { if (Double.IsNaN((Double)AxisMaximumNumeric)) { if ((AxisManager.AxisMaximumValue - Maximum) <= (Minimum - AxisManager.AxisMinimumValue)) { // This part makes the gaps equal AxisManager.AxisMaximumValue = Maximum + Minimum - AxisManager.AxisMinimumValue; } } else { AxisManager.AxisMaximumValue = (Double)AxisMaximumNumeric; } } } /// /// Convert scaling sets from string to unit and value array /// /// ScalingSets as string private void ParseScalingSets(String scalingSets) { if (String.IsNullOrEmpty(scalingSets)) return; // scaling sets are available in the form of value,unit;value,unit;value,unit; String[] pairs = scalingSets.Split(';'); // Since scale has to be successively multiplied initialize it to 1 Double scale = 1; // variable to store the parsed double value Double parsedValue; _scaleUnits = new List(); _scaleValues = new List(); for (Int32 i = 0; i < pairs.Length; i++) { // split the individual pairs available in "value,unit" form String[] sets = pairs[i].Split(','); // if either of value or unit is missing then throw this exception if (sets.Length != 2) throw new Exception("Invalid scaling set parameters. should be of the form value,unit;value,unit;..."); // parse the value part of the string as double parsedValue = Double.Parse(sets[0], CultureInfo.InvariantCulture); // multiply the scale with the parsed value and store it scale *= parsedValue; _scaleValues.Add(scale); // store the unit in the units list _scaleUnits.Add(sets[1]); } } /// /// Apply axis visual properties /// private void ApplyVisualProperty() { Visual.Cursor = (Cursor == null) ? Cursors.Arrow : Cursor; AttachHref(Chart, Visual, Href, HrefTarget); AttachToolTip(Chart, this, Visual); AttachEvents2Visual(this, this.Visual); Visual.Opacity = this.InternalOpacity; } /// /// Calculate and return default interval for axis /// /// Interval as Double private Double GenerateDefaultInterval() { if (_isDateTimeAutoInterval || (XValueType != ChartValueTypes.Numeric && IntervalType != IntervalTypes.Years && Double.IsNaN((Double)Interval) && Double.IsNaN((Double)AxisLabels.Interval) && !Double.IsNaN(InternalInterval) && InternalInterval >= 1)) return InternalInterval; if (AxisType == AxisTypes.Primary) { if (Double.IsNaN((Double)Interval) && Double.IsNaN((Double)AxisLabels.Interval) && PlotDetails.IsAllPrimaryAxisXLabelsPresent) { List uniqueXValues = (from entry in PlotDetails.AxisXPrimaryLabels orderby entry.Key select entry.Key).ToList(); if (uniqueXValues.Count > 0) { Double minDiff = Double.MaxValue; for (Int32 i = 0; i < uniqueXValues.Count - 1; i++) { minDiff = Math.Min(minDiff, Math.Abs(uniqueXValues[i] - uniqueXValues[i + 1])); } if (minDiff != Double.MaxValue) return minDiff; } } } else { if (Double.IsNaN((Double)Interval) && Double.IsNaN((Double)AxisLabels.Interval) && PlotDetails.IsAllSecondaryAxisXLabelsPresent) { List uniqueXValues = (from entry in PlotDetails.AxisXSecondaryLabels orderby entry.Key select entry.Key).ToList(); if (uniqueXValues.Count > 0) { Double minDiff = Double.MaxValue; for (Int32 i = 0; i < uniqueXValues.Count - 1; i++) { minDiff = Math.Min(minDiff, Math.Abs(uniqueXValues[i] - uniqueXValues[i + 1])); } if (minDiff != Double.MaxValue) return minDiff; } } } return (Double)Interval; } /// /// Event handler manages the addition and removal of ticks from axis /// private void Ticks_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { Boolean isAutoTick = false; if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { if (e.NewItems != null) { foreach (Ticks tick in e.NewItems) { if (tick._isAutoGenerated) isAutoTick = true; if (Chart != null) tick.Chart = Chart; tick.PropertyChanged -= tick_PropertyChanged; tick.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(tick_PropertyChanged); } } } if (!isAutoTick) this.FirePropertyChanged("Ticks"); } /// /// Event handler manages the addition and removal of chartgrid from axis /// private void Grids_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { Boolean isAutoGrids = false; if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { if (e.NewItems != null) { foreach (ChartGrid grid in e.NewItems) { if (grid._isAutoGenerated) isAutoGrids = true; if (Chart != null) grid.Chart = Chart; grid.PropertyChanged -= grid_PropertyChanged; grid.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(grid_PropertyChanged); } } } if (!isAutoGrids) this.FirePropertyChanged("Grids"); } /// /// Event handler attached with PropertyChanged event of chartgrids /// /// ObservableObject /// PropertyChangedEventArgs private void grid_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { this.FirePropertyChanged(e.PropertyName); } /// /// Event handler attached with PropertyChanged event of ticks /// /// ObservableObject /// PropertyChangedEventArgs private void tick_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { this.FirePropertyChanged(e.PropertyName); } /// /// Applies axis settings for horizontal type axis /// private void ApplyHorizontalAxisSettings() { // Apply settings based on the axis type switch (AxisType) { case AxisTypes.Primary: ApplyHorizontalPrimaryAxisSettings(); break; case AxisTypes.Secondary: ApplyHorizontalSecondaryAxisSettings(); break; } } #endregion #region Internal Methods /// /// Calculate total tick length from an axis /// /// /// /// /// internal static void CalculateTotalTickLength(Chart chart, ref Double tickLengthOfAxisX, ref Double tickLengthOfPrimaryAxisY, ref Double tickLengthOfSecondaryAxisY) { tickLengthOfAxisX = (from tick in chart.AxesX[0].Ticks where (Boolean)chart.AxesX[0].Enabled && (Boolean)tick.Enabled select tick.TickLength).Sum(); if (tickLengthOfAxisX == 0) tickLengthOfAxisX = 5; tickLengthOfPrimaryAxisY = (from axis in chart.AxesY where axis.AxisType == AxisTypes.Primary from tick in axis.Ticks where (Boolean)axis.Enabled && (Boolean)tick.Enabled select tick.TickLength).Sum(); if (tickLengthOfPrimaryAxisY == 0) tickLengthOfPrimaryAxisY = 8; tickLengthOfSecondaryAxisY = (from axis in chart.AxesY where axis.AxisType == AxisTypes.Secondary from tick in axis.Ticks where (Boolean)axis.Enabled && (Boolean)tick.Enabled select tick.TickLength).Sum(); if (tickLengthOfSecondaryAxisY == 0) tickLengthOfSecondaryAxisY = 8; } /// /// Converts pixel position to value /// /// Pixel width of the scale /// Pixel position /// Double internal Double PixelPositionToXValue(Double maxWidth, Double pixelPosition) { return Graphics.PixelPositionToValue(0, maxWidth, InternalAxisMinimum, InternalAxisMaximum, pixelPosition); } /// /// Converts pixel position to value /// /// Pixel width of the scale /// Pixel position /// Double internal Double PixelPositionToYValue(Double maxHeight, Double pixelPosition) { return Graphics.PixelPositionToValue(maxHeight, 0, InternalAxisMinimum, InternalAxisMaximum, pixelPosition); } /// /// Add prefix and suffix /// /// /// internal string AddPrefixAndSuffix(String str) { return Prefix + str + Suffix; } /// /// Return formatted string from a given value depending upon scaling set and value format string /// /// Double value /// String internal String GetFormattedString(Double value) { String str = value.ToString(); if (ScaleValues != null && ScaleUnits != null) { String sUnit = ScaleUnits[0]; Double sValue = ScaleValues[0]; for (Int32 i = 0; i < ScaleValues.Count; i++) { if ((Math.Abs(value) / ScaleValues[i]) < 1) { break; } sValue = ScaleValues[i]; sUnit = ScaleUnits[i]; } str = (value / sValue).ToString(ValueFormatString) + sUnit; } else { str = value.ToString(ValueFormatString); } str = AddPrefixAndSuffix(str); return str; } /// /// Associate a scrollbar with itself /// internal void SetScrollBar() { if (this.AxisOrientation == Orientation.Vertical) ScrollBarElement = (AxisType == AxisTypes.Primary) ? Chart._leftAxisScrollBar : Chart._rightAxisScrollBar; else ScrollBarElement = (AxisType == AxisTypes.Primary) ? Chart._bottomAxisScrollBar : Chart._topAxisScrollBar; } /// /// Set axis scroll value to scrollbar associated with this axis /// /// Scrollbar offset internal void SetScrollBarValueFromOffset(Double offset) { if (ScrollBarElement != null) { Double value = GetScrollBarValueFromOffset(offset); ScrollBarElement.SetValue(ScrollBar.ValueProperty, value); if (Scroll != null) Scroll(ScrollBarElement, new ScrollEventArgs(ScrollEventType.First, value)); } } /// /// Get axis scroll value in pixel from scrollbar offset /// /// Scrollbar offset internal Double GetScrollBarValueFromOffset(Double offset) { if (Double.IsNaN(offset)) offset = 0; offset = (ScrollBarElement.Maximum - ScrollBarElement.Minimum) * offset + ScrollBarElement.Minimum; if (PlotDetails.ChartOrientation == ChartOrientationType.Horizontal) offset = ScrollBarElement.Maximum - offset; return offset; } /// /// Set up ticks for axis /// private void SetUpTicks() { if (Ticks.Count == 0) Ticks.Add(new Ticks() { _isAutoGenerated = true }); foreach (Ticks tick in Ticks) { tick.IsNotificationEnable = false; if (AxisRepresentation.ToString() == "AxisX") tick.ApplyStyleFromTheme(Chart, "AxisXTicks"); else if (AxisRepresentation.ToString() == "AxisY") tick.ApplyStyleFromTheme(Chart, "AxisYTicks"); tick.Maximum = AxisManager.AxisMaximumValue; tick.Minimum = AxisManager.AxisMinimumValue; tick.DataMaximum = Maximum; tick.DataMinimum = Minimum; //tick.TickLength = 5; tick.ParentAxis = this; tick.IsNotificationEnable = true; } } /// /// Set up grids for axis /// private void SetUpGrids() { if (Grids.Count == 0 && AxisRepresentation.ToString() != "AxisX") Grids.Add(new ChartGrid() { _isAutoGenerated = true }); foreach (ChartGrid grid in Grids) { grid.IsNotificationEnable = false; grid.Maximum = AxisManager.AxisMaximumValue; grid.Minimum = AxisManager.AxisMinimumValue; grid.DataMaximum = Maximum; grid.DataMinimum = Minimum; grid.ParentAxis = this; grid.IsNotificationEnable = true; } } /// /// Set up axis labels for axis /// private void SetUpAxisLabels() { // set the params to create Axis Labels AxisLabels.Maximum = AxisManager.AxisMaximumValue; AxisLabels.Minimum = AxisManager.AxisMinimumValue; AxisLabels.DataMaximum = Maximum; AxisLabels.DataMinimum = Minimum; AxisLabels.ParentAxis = this; AxisLabels.InternalRows = (Int32)AxisLabels.Rows; //AxisLabels.Padding = this.Padding; if (AxisRepresentation == AxisRepresentations.AxisX) { if (AxisType == AxisTypes.Primary) { AxisLabels.AxisLabelContentDictionary = PlotDetails.AxisXPrimaryLabels; AxisLabels.AllAxisLabels = PlotDetails.IsAllPrimaryAxisXLabelsPresent; } else { AxisLabels.AxisLabelContentDictionary = PlotDetails.AxisXSecondaryLabels; AxisLabels.AllAxisLabels = PlotDetails.IsAllSecondaryAxisXLabelsPresent; } } foreach (Ticks tick in Ticks) { tick.IsNotificationEnable = false; tick.AllAxisLabels = AxisLabels.AllAxisLabels; tick.AxisLabelsDictionary = AxisLabels.AxisLabelContentDictionary; tick.IsNotificationEnable = true; } } /// /// Creates the visual element for the Axis /// /// Chart internal void CreateVisualObject(Chart Chart) { IsNotificationEnable = false; AxisLabels.IsNotificationEnable = false; AxisLabels.Chart = Chart; if (AxisRepresentation == AxisRepresentations.AxisX) AxisLabels.ApplyStyleFromTheme(Chart, "AxisXLabels"); else if (AxisRepresentation == AxisRepresentations.AxisY) AxisLabels.ApplyStyleFromTheme(Chart, "AxisYLabels"); // Create visual elements Visual = new StackPanel() { Background = InternalBackground }; InternalStackPanel = new Canvas(); ScrollViewerElement = new Canvas(); AxisTitleElement = new Title(); ApplyVisualProperty(); ApplyTitleProperties(); SetUpAxisManager(); SetUpTicks(); SetUpGrids(); SetUpAxisLabels(); // set the placement order based on the axis orientation switch (AxisOrientation) { case Orientation.Horizontal: ApplyHorizontalAxisSettings(); break; case Orientation.Vertical: ApplyVerticalAxisSettings(); break; } IsNotificationEnable = true; AxisLabels.IsNotificationEnable = true; if (!(Boolean)this.Enabled) { Visual.Visibility = Visibility.Collapsed; } } #endregion #region Internal Events And Delegates /// /// Scroll event of axis /// internal event ScrollEventHandler Scroll; #endregion #region Data /// /// Value type of the AxisMinimum Property /// internal ChartValueTypes _axisMinimumValueType; /// /// Value type of the AxisMinimum Property /// internal ChartValueTypes _axisMaximumValueType; /// /// Whether ScrollBar scrolling is enabled due to change of ScrollBarOffset property /// internal Boolean _isScrollToOffsetEnabled = true; /// /// Whether Interval is auto-calculated for DateTime Axis /// internal Boolean _isDateTimeAutoInterval = false; /// /// Whether all XValues are equals to zero /// internal Boolean _isAllXValueZero = true; /// /// Stores the orientation (vertical or horizontal) of the axis /// private Orientation _orientation; /// /// Stores the units extracted from the scaling sets /// private List _scaleUnits; /// /// Stores the values extracted from the scaling sets /// private List _scaleValues; /// /// Whether user has set the axis interval or not /// private Double _axisIntervalOverride; /// /// Margin between axis title and axis scale /// private const Double INNER_MARGIN = 4; Double _internalOpacity = Double.NaN; Brush _internalBackground = null; Nullable _internalPadding = null; #endregion } }