using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Drawing.Drawing2D; using System.Globalization; using System.Text; using System.Text.RegularExpressions; using DevComponents.DotNetBar.Charts.Style; namespace DevComponents.DotNetBar.Charts { /// /// Represents the collection of ChartSeries. /// [Editor("DevComponents.Charts.Design.ChartSeriesCollectionEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public class ChartSeriesCollection : CustomNamedCollection { #region GetUniqueName public string GetUniqueName() { return (GetUniqueName("Series")); } #endregion } public class ChartSeries : BaseSeries { #region Constants private const int StockHigh = 0; private const int StockLow = 1; private const int StockClose = 2; private const int StockOpen = 3; private const int StockMedian = 4; #endregion #region Private variables private States _States; private SeriesPointCollection _SeriesPoints; private PointData _PointData; private PointData _EmptyPointData; private PointData _StepPointData; private ChartAxis _AxisX; private ChartAxis _AxisY; private int _BarOffset; private int _BarWidth; private double _BarWidthRatio; private Tbool _BarShadingEnabled = Tbool.NotSet; private BarFillRange _BarFillRange = BarFillRange.NotSet; private BarLabelPosition _BarLabelPosition = BarLabelPosition.NotSet; private Color[] _BarShadingColors; private ChartSeriesVisualStyle _ChartSeriesVisualStyle; private EffectiveStyle _EffectiveChartSeriesStyle; private DataLabelVisualStyle _DataLabelVisualStyle; private EffectiveStyle _EffectiveDataLabelStyle; private Tbool _CrosshairEnabled = Tbool.NotSet; private Tbool _CrosshairHighlightPoints = Tbool.NotSet; private Tbool _CrosshairHighlightSinglePoint = Tbool.NotSet; private Tbool _CrosshairShowLabels = Tbool.NotSet; private ScaleType _ScaleTypeX = ScaleType.NotSet; private ScaleType _ScaleTypeY = ScaleType.NotSet; private ScaleType _ActualScaleTypeX = ScaleType.NotSet; private ScaleType _ActualScaleTypeY = ScaleType.NotSet; private object _MinValueX; private object _MinValueY; private object _MaxValueX; private object _MaxValueY; private object _AreaBaseValue; private SortedSeriesPoints _SortedSeriesPoints; private object[] _EmptyValues; private List _QualitativeXValues; private List _QualitativeYValues; private PointMarker _PointMarker; private Image _PointMarkerImage; private Image _PointMarkerEmptyImage; private Image _PointMarkerHighlightImage; private Point _PointOffset; private int _GroupId; private object _PlotData; private double _DotPlotIndexValue = 1.0d; private ChartIndicatorCollection _ChartIndicators; private Point[] _ConvexHullPoints; private double _BubbleScaleFactor = 1.0d; private double _BubbleMaxPercentage = .25d; private int _BubbleMinSize = 4; private BubbleSizeMode _BubbleSizeMode = BubbleSizeMode.NotSet; private BubbleIntensityMode _BubbleIntensityMode = BubbleIntensityMode.NotSet; private ChartLineDisplayMode _ChartLineDisplayMode = ChartLineDisplayMode.NotSet; private ChartLineAreaDisplayMode _ChartLineAreaDisplayMode = ChartLineAreaDisplayMode.NotSet; private ConvexHullDisplayMode _ConvexHullDisplayMode = ConvexHullDisplayMode.NotSet; private PointLabelDisplayMode _PointLabelDisplayMode = PointLabelDisplayMode.NotSet; private StepLines _StepLines = StepLines.NotSet; private StepLineMode _StepLineMode = StepLineMode.NotSet; private StepLineMode _LastStepLineMode = StepLineMode.NotSet; private DataLabelCollection _DataLabels; private int _PointLabelSkip; private int _PointLabelMinDistance; private HiLoBarType _HiLoBarType = HiLoBarType.Box; #endregion #region Constructors public ChartSeries() : this(null, SeriesType.Point) { } public ChartSeries(string name) : this(name, SeriesType.Point) { } public ChartSeries(SeriesType seriesType) : this(null, seriesType) { } public ChartSeries(string name, SeriesType seriesType) { Name = name; SeriesType = seriesType; InitDefaultStates(); _EffectiveChartSeriesStyle = new EffectiveStyle(this); _EffectiveDataLabelStyle = new EffectiveStyle(this); } #endregion #region InitDefaultStates private void InitDefaultStates() { SetState(States.ShowInLegend, true); SetState(States.ShowInParentLegend, true); SetState(States.ShowCheckBoxInLegend, true); SetState(States.ShowMarkerInLegend, true); SetState(States.CheckedInLegend, true); SetState(States.DisplayLinePointsOnTop, true); SetState(States.StackQualitativePoints, true); SetState(States.ShowOriginValueLabels, true); SetState(States.ShowInnerRingsEx, true); } #endregion #region Public properties #region ActualScaleTypeX /// /// Gets the Actual X axis Scale Type (may be /// different than XScaleType when XScaleType is 'Auto'). /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ScaleType ActualScaleTypeX { get { if (IsRotated == false) return (_ActualScaleTypeX); return (_ActualScaleTypeY); } internal set { _ActualScaleTypeX = value; } } #endregion #region ActualScaleTypeY /// /// Gets the Actual Y axis Scale Type (may be /// different than YScaleType when YScaleType is 'Auto'). /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ScaleType ActualScaleTypeY { get { if (IsRotated == true) return (_ActualScaleTypeX); return (_ActualScaleTypeY); } internal set { _ActualScaleTypeY = value; } } #endregion #region AreaBaseValue /// /// Gets or sets the base, reference value for displaying Line/Spline/Step Areas. /// [DefaultValue(null), Category("Data")] [Description("Indicates the base, reference value for displaying Line/Spline/Step Areas.")] [TypeConverter("DevComponents.Charts.Design.PointValueConverter," + "DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf")] public object AreaBaseValue { get { return (_AreaBaseValue); } set { if (value != _AreaBaseValue) { _AreaBaseValue = value; OnPropertyChangedEx("AreaBaseValue", Style.VisualChangeType.Render); } } } #endregion #region AxisX /// /// Gets a reference to the X-Axis associated with the series. /// [Category("Axis"), DefaultValue(null)] [Description("Indicates the reference to the X-Axis associated with the series.")] [TypeConverter(typeof(AxisTypeConverter))] [Editor("DevComponents.Charts.Design.AxisListTypeEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public ChartAxis AxisX { get { return (_AxisX); } set { if (value != _AxisX) { ChartXy chartXy = Parent as ChartXy; if (value != null) { if (value.IsPrimaryAxis == false) { if (chartXy != null) { if (chartXy.AncillaryAxesX.Contains(value) == false) { throw new Exception("Cannot set the series XAxis. The axis is not primary " + "or a member of the chart's AncillaryAxesX collection."); } } } } if (_AxisX != null) { _AxisX.SeriesRangeChanged = true; _AxisX.PropertyChanged -= AxisX_PropertyChanged; } else { if (chartXy != null) chartXy.AxisX.SeriesRangeChanged = true; } _AxisX = value; if (_AxisX != null) { _AxisX.SeriesRangeChanged = true; _AxisX.PropertyChanged += AxisX_PropertyChanged; } else { if (chartXy != null) chartXy.AxisX.SeriesRangeChanged = true; } OnPropertyChangedEx("AxisX", VisualChangeType.Layout); } } } void AxisX_PropertyChanged(object sender, PropertyChangedEventArgs e) { InvalidateLayout(); } #endregion #region AxisY /// /// Gets a reference to the Y-Axis associated with the series. /// [Category("Axis"), DefaultValue(null)] [Description("Indicates the reference to the Y-Axis associated with the series.")] [Editor("DevComponents.Charts.Design.AxisListTypeEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public ChartAxis AxisY { get { return (_AxisY); } set { if (value != _AxisY) { ChartXy chartXy = Parent as ChartXy; if (value != null) { if (value.IsPrimaryAxis == false) { if (chartXy != null) { if (chartXy.AncillaryAxesY.Contains(value) == false) { throw new Exception("Cannot set the series YAxis. The axis is not primary " + "or a member of the chart's AncillaryAxesY collection."); } } } } if (_AxisY != null) { _AxisY.SeriesRangeChanged = true; _AxisY.PropertyChanged -= AxisY_PropertyChanged; } else { if (chartXy != null) chartXy.AxisY.SeriesRangeChanged = true; } _AxisY = value; if (_AxisY != null) { _AxisY.SeriesRangeChanged = true; _AxisY.PropertyChanged += AxisY_PropertyChanged; } else { if (chartXy != null) chartXy.AxisY.SeriesRangeChanged = true; } OnPropertyChangedEx("AxisY", VisualChangeType.Layout); } } } void AxisY_PropertyChanged(object sender, PropertyChangedEventArgs e) { InvalidateLayout(); } #endregion #region BarFillRange /// /// Gets or sets how series bars are filled (either according to /// each individual bar range, or the entire series range). /// [DefaultValue(BarFillRange.NotSet), Category("Bar Display")] [Description("Indicates how series bars are filled (either according to each individual bar range, or the entire series range).")] public BarFillRange BarFillRange { get { return (_BarFillRange); } set { if (value != _BarFillRange) { _BarFillRange = value; OnPropertyChangedEx("BarFillRange", VisualChangeType.Render); } } } #endregion #region BarLabelPosition /// /// Gets or sets the position of bar series labels (default is Center). /// [DefaultValue(BarLabelPosition.NotSet), Category("Bar Display")] [Description("Indicates the position of bar series labels (default is Center).")] public BarLabelPosition BarLabelPosition { get { return (_BarLabelPosition); } set { if (value != _BarLabelPosition) { _BarLabelPosition = value; OnPropertyChangedEx("BarLabelPosition", VisualChangeType.Layout); } } } #endregion #region BarShadingEnabled /// /// Gets or sets whether Bar shading is enabled for Horizontal and Vertical Bar series. /// [DefaultValue(Tbool.NotSet), Category("Bar Display")] [Description("Indicates whether Bar shading is enabled for Horizontal and Vertical Bar series.")] public Tbool BarShadingEnabled { get { return (_BarShadingEnabled); } set { if (value != _BarShadingEnabled) { _BarShadingEnabled = value; OnPropertyChangedEx("BarShadingEnabled", VisualChangeType.Render); } } } #endregion #region BarWidthRatio /// /// Gets or sets the ratio of bar width to bar spacing within /// the same series (defaults to 2 - bar is twice as wide as spacing). /// [DefaultValue(0d), Category("Bar Display")] [Description("Indicates the ratio of bar width to bar spacing within the same series (defaults to 2 - bar is twice as wide as spacing).")] public double BarWidthRatio { get { return (_BarWidthRatio); } set { if (value != _BarWidthRatio) { if (value < 0) throw new ArgumentException("Value must be > 0"); _BarWidthRatio = value; OnPropertyChangedEx("BarWidthRatio", VisualChangeType.Layout); } } } #endregion #region BubbleIntensityMode /// /// Gets or sets the mode used to determine bubble intensities. /// [DefaultValue(BubbleIntensityMode.NotSet), Category("Display")] [Description("Indicates the mode used to determine bubble intensities.")] public BubbleIntensityMode BubbleIntensityMode { get { return (_BubbleIntensityMode); } set { if (value != _BubbleIntensityMode) { _BubbleIntensityMode = value; OnPropertyChangedEx("BubbleIntensityMode", VisualChangeType.Render); } } } #endregion #region BubbleMaxPercentage /// /// Gets or sets the max percentage of the display /// area used to calculate series bubble sizes (default is .25). /// [DefaultValue(0.25d), Category("Display")] [Description("Indicates the max percentage of the display area used to calculate series bubble sizes (default is .25).")] public double BubbleMaxPercentage { get { return (_BubbleMaxPercentage); } set { if (value != _BubbleMaxPercentage) { if (value <= 0 || value > 1) throw new ArgumentException("Value must be between 0 and 1"); _BubbleMaxPercentage = value; OnPropertyChangedEx("BubbleMaxPercentage", VisualChangeType.Layout); } } } #endregion #region BubbleMinSize /// /// Gets or sets the minimum series bubble size (in pixels) Default is 4. /// [DefaultValue(4), Category("Display")] [Description("Indicates the minimum series bubble size (in pixels). Default is 4.")] public int BubbleMinSize { get { return (_BubbleMinSize); } set { if (value != _BubbleMinSize) { if (value < 0) throw new ArgumentException("Value must be > 0"); _BubbleMinSize = value; OnPropertyChangedEx("BubbleMinSize", VisualChangeType.Layout); } } } #endregion #region BubbleScaleFactor /// /// Gets or sets the Scale Factor used to calculate series bubble sizes. /// [DefaultValue(1.0d), Category("Display")] [Description("Indicates the Scale Factor used to calculate series bubble sizes.")] public double BubbleScaleFactor { get { return (_BubbleScaleFactor); } set { if (value != _BubbleScaleFactor) { _BubbleScaleFactor = value; OnPropertyChangedEx("BubbleScaleFactor", VisualChangeType.Layout); } } } #endregion #region BubbleSizeMode /// /// Gets or sets the mode used to calculate series bubble sizes. /// [DefaultValue(BubbleSizeMode.NotSet), Category("Display")] [Description("Indicates the mode used to calculate series bubble sizes.")] public BubbleSizeMode BubbleSizeMode { get { return (_BubbleSizeMode); } set { if (value != _BubbleSizeMode) { _BubbleSizeMode = value; OnPropertyChangedEx("BubbleSizeMode", VisualChangeType.Render); } } } #endregion #region ChartIndicators /// /// Gets a reference to the Chart Indicators collection. /// [DefaultValue(null), Category("Appearance")] [Description("Indicates the Chart Indicators collection.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public ChartIndicatorCollection ChartIndicators { get { if (_ChartIndicators == null) { _ChartIndicators = new ChartIndicatorCollection(); _ChartIndicators.CollectionChanged += ChartIndicators_CollectionChanged; } return (_ChartIndicators); } internal set { if (_ChartIndicators != null) _ChartIndicators.CollectionChanged -= ChartIndicators_CollectionChanged; _ChartIndicators = value; if (_ChartIndicators != null) _ChartIndicators.CollectionChanged += ChartIndicators_CollectionChanged; } } #region ChartIndicators_CollectionChanged void ChartIndicators_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { bool updateLayout = false; switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (ChartIndicator ci in e.NewItems) { if (ci.ShowInLegend == true || ci.ShowInParentLegend == true) updateLayout = true; ci.Parent = this; } break; case NotifyCollectionChangedAction.Replace: foreach (ChartIndicator ci in e.OldItems) { if (ci.ShowInLegend == true || ci.ShowInParentLegend == true) updateLayout = true; ci.Parent = null; } foreach (ChartIndicator ci in e.NewItems) { if (ci.ShowInLegend == true || ci.ShowInParentLegend == true) updateLayout = true; ci.Parent = this; } break; case NotifyCollectionChangedAction.Remove: foreach (ChartIndicator ci in e.OldItems) { if (ci.ShowInLegend == true || ci.ShowInParentLegend == true) updateLayout = true; ci.Parent = null; } break; } if (updateLayout == true) InvalidateLayout(); else InvalidateRender(); } #endregion #endregion #region ChartLineAreaDisplayMode /// /// Gets or sets the Line 'Area' display mode. /// [DefaultValue(ChartLineAreaDisplayMode.NotSet), Category("Display")] [Description("Indicates the Line ChartType display mode.")] [Editor("DevComponents.Charts.Design.FlagsEnumUIEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public ChartLineAreaDisplayMode ChartLineAreaDisplayMode { get { return (_ChartLineAreaDisplayMode); } set { if (value != _ChartLineAreaDisplayMode) { _ChartLineAreaDisplayMode = value; OnPropertyChangedEx("ChartLineAreaDisplayMode", VisualChangeType.Render); } } } #endregion #region ChartLineDisplayMode /// /// Gets or sets the Line ChartType display mode. /// [DefaultValue(ChartLineDisplayMode.NotSet), Category("Display")] [Description("Indicates the Line ChartType display mode.")] [Editor("DevComponents.Charts.Design.FlagsEnumUIEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public ChartLineDisplayMode ChartLineDisplayMode { get { return (_ChartLineDisplayMode); } set { if (value != _ChartLineDisplayMode) { _ChartLineDisplayMode = value; _SortedSeriesPoints = null; OnPropertyChangedEx("ChartLineDisplayMode", VisualChangeType.Render); } } } #endregion #region ChartSeriesVisualStyle /// /// Gets or sets the visual style for the series. /// [Category("Style")] [Description("Indicates the visual style for the series.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public ChartSeriesVisualStyle ChartSeriesVisualStyle { get { if (_ChartSeriesVisualStyle == null) { _ChartSeriesVisualStyle = new ChartSeriesVisualStyle(); StyleVisualChangeHandler(null, _ChartSeriesVisualStyle); } return (_ChartSeriesVisualStyle); } set { if (_ChartSeriesVisualStyle != value) { ChartSeriesVisualStyle oldValue = _ChartSeriesVisualStyle; _ChartSeriesVisualStyle = value; OnStyleChanged("ChartSeriesVisualStyle", oldValue, value); if (oldValue != null) oldValue.Dispose(); } } } #endregion #region ConvexHullDisplayMode /// /// Gets or sets the ConvexHull display mode. /// [DefaultValue(ConvexHullDisplayMode.NotSet), Category("Display")] [Description("Indicates the ConvexHull display mode.")] [Editor("DevComponents.Charts.Design.FlagsEnumUIEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public ConvexHullDisplayMode ConvexHullDisplayMode { get { return (_ConvexHullDisplayMode); } set { if (value != _ConvexHullDisplayMode) { _ConvexHullDisplayMode = value; OnPropertyChangedEx("ConvexHullDisplayMode", VisualChangeType.Render); } } } #endregion #region CrosshairEnabled /// /// Gets or sets whether Crosshair support is enabled for the series. /// [DefaultValue(Tbool.NotSet), Category("Crosshair")] [Description("Indicates whether Crosshair support is enabled for the series.")] public Tbool CrosshairEnabled { get { return (_CrosshairEnabled); } set { if (value != _CrosshairEnabled) { _CrosshairEnabled = value; OnPropertyChanged("CrosshairEnabled"); } } } #endregion #region CrosshairHighlightPoints /// /// Gets or sets whether Crosshair Point highlighting is enabled for the series. /// [DefaultValue(Tbool.NotSet), Category("Crosshair")] [Description("Indicates whether Crosshair Point highlighting is enabled for the series.")] public Tbool CrosshairHighlightPoints { get { return (_CrosshairHighlightPoints); } set { if (value != _CrosshairHighlightPoints) { _CrosshairHighlightPoints = value; OnPropertyChanged("CrosshairHighlightPoints"); } } } #endregion #region CrosshairHighlightSinglePoint /// /// Gets or sets whether Crosshair Point highlighting will /// only highlight a single point for the series. /// [DefaultValue(Tbool.NotSet), Category("Crosshair")] [Description("Indicates whether Crosshair Point highlighting will only highlight a single point for the series.")] public Tbool CrosshairHighlightSinglePoint { get { return (_CrosshairHighlightSinglePoint); } set { if (value != _CrosshairHighlightSinglePoint) { _CrosshairHighlightSinglePoint = value; OnPropertyChanged("CrosshairHighlightSinglePoint"); } } } #endregion #region CrosshairShowLabels /// /// Gets or sets whether Crosshair labels are shown for the series. /// [DefaultValue(Tbool.NotSet), Category("Crosshair")] [Description("Indicates whether Crosshair labels are shown for the series.")] public Tbool CrosshairShowLabels { get { return (_CrosshairShowLabels); } set { if (value != _CrosshairShowLabels) { _CrosshairShowLabels = value; OnPropertyChanged("CrosshairShowLabels"); } } } #endregion #region DataLabels /// /// Gets or sets the list of instance Data Labels. /// [DefaultValue(null), Category("DataLabel")] [Description("Indicates the list of instance Data Labels.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public DataLabelCollection DataLabels { get { if (_DataLabels == null) { _DataLabels = new DataLabelCollection(); _DataLabels.PropertyChanged += DataLabels_PropertyChanged; _DataLabels.CollectionChanged += DataLabels_CollectionChanged; } return (_DataLabels); } internal set { if (_DataLabels != null) { _DataLabels.PropertyChanged -= DataLabels_PropertyChanged; _DataLabels.CollectionChanged -= DataLabels_CollectionChanged; } _DataLabels = value; if (_DataLabels != null) { _DataLabels.PropertyChanged += DataLabels_PropertyChanged; _DataLabels.CollectionChanged += DataLabels_CollectionChanged; } } } #region DataLabels_PropertyChanged void DataLabels_PropertyChanged(object sender, PropertyChangedEventArgs e) { InvalidateRender(); } #endregion #region DataLabels_CollectionChanged private void DataLabels_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (DataLabel dl in e.NewItems) { dl.Parent = this; dl.PropertyChanged += DataLabel_PropertyChanged; } break; case NotifyCollectionChangedAction.Replace: foreach (DataLabel dl in e.OldItems) { dl.Parent = null; dl.PropertyChanged -= DataLabel_PropertyChanged; } foreach (DataLabel dl in e.NewItems) { dl.Parent = this; dl.PropertyChanged += DataLabel_PropertyChanged; } break; case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Reset: if (e.OldItems != null) { foreach (DataLabel dl in e.OldItems) dl.PropertyChanged -= DataLabel_PropertyChanged; } break; } InvalidateLayout(); } private void DataLabel_PropertyChanged(object sender, PropertyChangedEventArgs e) { InvalidateLayout(); } #endregion #endregion #region DataLabelVisualStyle /// /// Gets or sets the visual style for the data labels. /// [Category("Style")] [Description("Indicates the visual style for the data labels.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public DataLabelVisualStyle DataLabelVisualStyle { get { if (_DataLabelVisualStyle == null) { _DataLabelVisualStyle = new DataLabelVisualStyle(); StyleVisualChangeHandler(null, _DataLabelVisualStyle); } return (_DataLabelVisualStyle); } set { if (_DataLabelVisualStyle != value) { DataLabelVisualStyle oldValue = _DataLabelVisualStyle; _DataLabelVisualStyle = value; OnStyleChanged("DataLabelVisualStyle", oldValue, value); if (oldValue != null) oldValue.Dispose(); } } } #endregion #region DisplayLinePointsOnTop /// /// Gets or sets whether series points are displayed on top of series line. /// [DefaultValue(true), Category("Appearance")] [Description("Indicates whether series points are displayed on top of series line.")] public bool DisplayLinePointsOnTop { get { return (TestState(States.DisplayLinePointsOnTop)); } set { if (value != DisplayLinePointsOnTop) { SetState(States.DisplayLinePointsOnTop, value); OnPropertyChangedEx("DisplayLinePointsOnTop", VisualChangeType.Render); } } } #endregion #region DotPlotIndexValue /// /// Gets or sets the value used to index between DotPlot points. Default is 1. /// [DefaultValue(1.0d), Category("Display")] [Description("Indicates the value used to index between DotPlot points. Default is 1.")] public double DotPlotIndexValue { get { return (_DotPlotIndexValue); } set { if (value != _DotPlotIndexValue) { if (value < 0) throw new ArgumentException("Value must be > 0"); _DotPlotIndexValue = value; OnPropertyChangedEx("DotPlotIndexValue", VisualChangeType.Layout); } } } #endregion #region EffectiveDataLabelStyle /// /// Gets a reference to the DataLabel effective (cached, composite) style. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public DataLabelVisualStyle EffectiveDataLabelStyle { get { return (_EffectiveDataLabelStyle.Style); } } #endregion #region EffectiveSeriesStyle /// /// Gets a reference to the Series's effective (cached, composite) style. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Description("Indicates a reference to the Series's Effective (cached, composite) style.")] public ChartSeriesVisualStyle EffectiveChartSeriesStyle { get { return (_EffectiveChartSeriesStyle.Style); } } #endregion #region EmptyValues /// /// Gets or sets the value(s) used to determine if /// a series point is empty or missing. /// [Category("Empty")] [Description("Indicates the value(s) used to determine if a series point is empty or missing.")] [Editor("DevComponents.Charts.Design.SeriesPointValueEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public object[] EmptyValues { get { return (_EmptyValues); } set { if (value != _EmptyValues) { _EmptyValues = value; OnPropertyChangedEx("EmptyValue", Style.VisualChangeType.Layout); } } } #endregion #region EnableEmptyValues /// /// Gets or sets whether EmptyValues are processed in the series /// [DefaultValue(false), Category("Empty")] [Description("Indicates whether EmptyValues are processed in the series.")] public bool EnableEmptyValues { get { return (TestState(States.EnableEmptyValues)); } set { if (value != EnableEmptyValues) { SetState(States.EnableEmptyValues, value); _PointData = null; _EmptyPointData = null; _StepPointData = null; OnPropertyChangedEx("EnableEmptyValues", VisualChangeType.Layout); } } } #endregion #region GroupId /// /// Gets or sets the logical Id used to group qualitative series. /// [DefaultValue(0), Category("Display")] [Description("Indicates the logical Id used to group qualitative series).")] public int GroupId { get { return (_GroupId); } set { if (value != _GroupId) { _GroupId = value; OnPropertyChangedEx("GroupId", Style.VisualChangeType.Layout); } } } #endregion #region HiLoBarType /// /// Gets or sets the Series HiLoBar Type. /// [DefaultValue(HiLoBarType.Box), Category("Appearance")] [Description("Indicates the Series HiLoBar Type.")] public HiLoBarType HiLoBarType { get { return (_HiLoBarType); } set { if (value != _HiLoBarType) { _HiLoBarType = value; OnPropertyChangedEx("HiLoBarType", VisualChangeType.Layout); } } } #endregion #region MaxValueX /// /// Gets the series Maximum X value. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object MaxValueX { get { UpdateSeriesRange(); if (IsRotated == true) return (_MaxValueY); return (_MaxValueX); } } #endregion #region MaxValueY /// /// Gets the series Maximum Y value. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object MaxValueY { get { UpdateSeriesRange(); if (IsRotated == true) return (_MaxValueX); return (_MaxValueY); } } #endregion #region MinValueX /// /// Gets the series minimum X value. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object MinValueX { get { UpdateSeriesRange(); if (IsRotated == true) return (_MinValueY); return (_MinValueX); } } #endregion #region MinValueY /// /// Gets the series minimum Y value. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object MinValueY { get { UpdateSeriesRange(); if (IsRotated == true) return (_MinValueX); return (_MinValueY); } } #endregion #region PointLabelDisplayMode /// /// Gets or sets the display mode for the chart PointLabels. /// [DefaultValue(PointLabelDisplayMode.NotSet), Category("DataLabel")] [Description("Indicates the display mode for the chart PointLabels.")] [Editor("DevComponents.Charts.Design.FlagsEnumUIEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public PointLabelDisplayMode PointLabelDisplayMode { get { return (_PointLabelDisplayMode); } set { if (value != _PointLabelDisplayMode) { _PointLabelDisplayMode = value; InvalidatePointLabels(); OnPropertyChangedEx("PointLabelDisplayMode", VisualChangeType.Render); } } } #endregion #region PointLabelMinDistance /// /// Gets or sets the minimum distance between label data points. /// [DefaultValue(0), Category("DataLabel")] [Description("Indicates the minimum distance between label data points.")] public int PointLabelMinDistance { get { return (_PointLabelMinDistance); } set { if (value != _PointLabelMinDistance) { if (value < 0) throw new Exception("Minimum Distance must be >= 0"); _PointLabelMinDistance = value; InvalidatePointLabels(); OnPropertyChangedEx("PointLabelMinDistance", Style.VisualChangeType.Render); } } } #endregion #region PointLabelSkip /// /// Gets or sets the number of inter-label points to skip. /// [DefaultValue(0), Category("DataLabel")] [Description("Indicates the number of inter-label points to skip.")] public int PointLabelSkip { get { return (_PointLabelSkip); } set { if (value != _PointLabelSkip) { if (value < 0) throw new Exception("Skip value must be >= 0"); _PointLabelSkip = value; InvalidatePointLabels(); OnPropertyChangedEx("PointLabelSkip", Style.VisualChangeType.Render); } } } #endregion #region ScaleTypeX /// /// Gets or sets the X axis Scale Type. /// [DefaultValue(ScaleType.NotSet), Category("Axis")] [Description("Indicates the X axis Scale Type.")] public ScaleType ScaleTypeX { get { return (_ScaleTypeX); } set { if (value != _ScaleTypeX) { if (ValidScaleTypeX(value) == false) throw new Exception("Incompatible ScaleTypeX for defined series data."); _ScaleTypeX = value; InvalidatePoints(); OnPropertyChangedEx("ScaleTypeX", VisualChangeType.Layout); } } } #region ValidScaleTypeX private bool ValidScaleTypeX(ScaleType scaleType) { if (scaleType == ScaleType.NotSet || scaleType == ScaleType.Auto) return (true); if (SeriesPoints.Count > 0) { for (int i = 0; i < SeriesPoints.Count; i++) { SeriesPoint sp = SeriesPoints[i]; if (sp.ValueX != null) { Type dataType = sp.ValueX.GetType(); ScaleType autoType = SeriesPoint.GetScaleType(dataType); if (scaleType == autoType) return (true); if (scaleType == ScaleType.Qualitative) return (true); return (false); } } } return (true); } #endregion #endregion #region ScaleTypeY /// /// Gets or sets the Y axis Scale Type. /// [DefaultValue(ScaleType.NotSet), Category("Axis")] [Description("Indicates the Y axis Scale Type.")] public ScaleType ScaleTypeY { get { return (_ScaleTypeY); } set { if (value != _ScaleTypeY) { if (ValidScaleTypeY(value) == false) throw new Exception("Incompatible ScaleTypeY for defined series data."); _ScaleTypeY = value; InvalidatePoints(); OnPropertyChangedEx("ScaleTypeY", VisualChangeType.Layout); } } } #region ValidScaleTypeY private bool ValidScaleTypeY(ScaleType scaleType) { if (scaleType == ScaleType.NotSet || scaleType == ScaleType.Auto) return (true); if (SeriesPoints.Count > 0) { for (int i = 0; i < SeriesPoints.Count; i++) { SeriesPoint sp = SeriesPoints[i]; if (sp.ValueY != null && sp.ValueY.Length > 0) { Type dataType = sp.ValueY[0].GetType(); ScaleType autoType = SeriesPoint.GetScaleType(dataType); if (scaleType == autoType) return (true); if (scaleType == ScaleType.Qualitative) return (true); return (false); } } } return (true); } #endregion #endregion #region SeriesPoints /// /// Gets the series point data collection /// [Category("Data")] [Description("Indicates the series point data collection.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public SeriesPointCollection SeriesPoints { get { if (_SeriesPoints == null) { _SeriesPoints = new SeriesPointCollection(); _SeriesPoints.CollectionChanged += SeriesPoints_CollectionChanged; } return (_SeriesPoints); } set { if (value != _SeriesPoints) { if (_SeriesPoints != null) _SeriesPoints.CollectionChanged -= SeriesPoints_CollectionChanged; _SeriesPoints = value; if (_SeriesPoints != null) _SeriesPoints.CollectionChanged += SeriesPoints_CollectionChanged; } } } #region SeriesPoints_CollectionChanged void SeriesPoints_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { SeriesRangeChanged = true; InvalidateLayout(); } #endregion #endregion #region SeriesType /// /// Gets or sets the Series Type. /// [DefaultValue(SeriesType.Point), Category("Appearance")] [Description("Indicates the Series Type.")] public override SeriesType SeriesType { get { return (base.SeriesType); } set { if (value != base.SeriesType) { base.SeriesType = value; IsRotated = ( value == SeriesType.HorizontalDot || value == SeriesType.HorizontalBar || value == SeriesType.HorizontalHiLoBar); } } } #endregion #region ShowHiLoBarMedianLines /// /// Gets or sets whether defined HiLoBar Median lines are shown. /// [DefaultValue(false), Category("Empty")] [Description("Indicates whether defined HiLoBar Median lines are shown.")] public bool ShowHiLoBarMedianLines { get { return (TestState(States.ShowHiLoBarMedianLines)); } set { if (value != ShowHiLoBarMedianLines) { SetState(States.ShowHiLoBarMedianLines, value); OnPropertyChangedEx("ShowHiLoBarMedianLines", VisualChangeType.Render); } } } #endregion #region ShowEmptyLines /// /// Gets or sets whether EmptyLines are shown in the series. /// [DefaultValue(false), Category("Empty")] [Description("Indicates whether EmptyLines are shown in the series.")] public bool ShowEmptyLines { get { return (TestState(States.ShowEmptyLines)); } set { if (value != ShowEmptyLines) { SetState(States.ShowEmptyLines, value); InvalidatePoints(); OnPropertyChangedEx("ShowEmptyLines", VisualChangeType.Render); } } } #endregion #region ShowEmptyPoints /// /// Gets or sets whether EmptyPoints are shown in the series. /// [DefaultValue(false), Category("Empty")] [Description("Indicates whether EmptyPoints are shown in the series.")] public bool ShowEmptyPoints { get { return (TestState(States.ShowEmptyPoints)); } set { if (value != ShowEmptyPoints) { SetState(States.ShowEmptyPoints, value); InvalidatePoints(); OnPropertyChangedEx("ShowEmptyPoints", VisualChangeType.Render); } } } #endregion #region ShowOriginValueLabels /// /// Gets or sets whether labels are shown for 'Origin' data values. /// [DefaultValue(true), Category("Appearance")] [Description("Indicates whether labels are shown for 'Origin' data values.")] public bool ShowOriginValueLabels { get { return (TestState(States.ShowOriginValueLabels)); } set { if (value != ShowOriginValueLabels) { SetState(States.ShowOriginValueLabels, value); OnPropertyChangedEx("ShowOriginValueLabels", VisualChangeType.Layout); } } } #endregion #region StackQualitativePoints /// /// Gets or sets whether Qualitative points are /// stacked or spread across the associated grouped column. /// [DefaultValue(true), Category("Appearance")] [Description("Indicates whether Qualitative points are stacked or spread across the associated grouped column.")] public bool StackQualitativePoints { get { return (TestState(States.StackQualitativePoints)); } set { if (value != StackQualitativePoints) { SetState(States.StackQualitativePoints, value); OnPropertyChangedEx("StackQualitativePoints", VisualChangeType.Layout); } } } #endregion #region StepLines /// /// Gets or sets which 'Step lines' are displayed. /// [DefaultValue(StepLines.NotSet), Category("Display")] [Description("Indicates which 'Step lines' are displayed.")] public StepLines StepLines { get { return (_StepLines); } set { if (value != _StepLines) { _StepLines = value; OnPropertyChangedEx("StepLines", VisualChangeType.Render); } } } #endregion #region StepLineMode /// /// Gets or sets the mode used to render "Step Lines" in /// the defined Line series. /// [DefaultValue(StepLineMode.NotSet), Category("Display")] [Description("Indicates the mode used to render 'Step Lines' in the defined Line series.")] public StepLineMode StepLineMode { get { return (_StepLineMode); } set { if (value != _StepLineMode) { _StepLineMode = value; OnPropertyChangedEx("StepLineMode", VisualChangeType.Render); } } } #endregion #endregion #region Internal properties #region BarOffset internal int BarOffset { get { return (_BarOffset); } set { _BarOffset = value; } } #endregion #region BarShadingColors internal Color[] BarShadingColors { get { if (_BarShadingColors == null) { // Top, Bottom, Left, Right _BarShadingColors = new Color[] { Color.FromArgb(200, Color.White), Color.FromArgb(100, Color.Black), Color.FromArgb(100, Color.Black), Color.FromArgb(100, Color.Black)}; } return (_BarShadingColors); } } #endregion #region BarWidth internal int BarWidth { get { return (_BarWidth); } set { _BarWidth = value; } } #endregion #region IsQualitativeXValues internal bool IsQualitativeXValues { get { UpdateSeriesRange(); return (QualitativeXValues.Count > 0); } } #endregion #region IsQualitativeYValues internal bool IsQualitativeYValues { get { UpdateSeriesRange(); return (QualitativeYValues.Count > 0); } } #endregion #region IsBarSeries internal bool IsBarSeries { get { return (SeriesType == SeriesType.HorizontalBar || SeriesType == SeriesType.VerticalBar || SeriesType == SeriesType.HorizontalHiLoBar || SeriesType == SeriesType.VerticalHiLoBar); } } #endregion #region IsRotated internal bool IsRotated { get { return (TestState(States.IsRotated)); } set { SetState(States.IsRotated, value); } } #endregion #region IsSorted internal bool IsSorted { get { return (TestState(States.IsSorted)); } set { SetState(States.IsSorted, value); } } #endregion #region PlotData internal object PlotData { get { return (_PlotData); } set { _PlotData = value; } } #endregion #region PointMarkerEmptyImage internal Image PointMarkerEmptyImage { get { return (_PointMarkerEmptyImage); } set { _PointMarkerEmptyImage = value; } } #endregion #region PointMarkerImage internal Image PointMarkerImage { get { return (_PointMarkerImage); } set { _PointMarkerImage = value; } } #endregion #region PointMarkerHighlightImage internal Image PointMarkerHighlightImage { get { return (_PointMarkerHighlightImage); } set { _PointMarkerHighlightImage = value; } } #endregion #region PointOffset internal Point PointOffset { get { return (_PointOffset); } set { _PointOffset = value; } } #endregion #region QualitativeXValues internal List QualitativeXValues { get { if (_QualitativeXValues == null) _QualitativeXValues = new List(); return (_QualitativeXValues); } set { _QualitativeXValues = value; } } #endregion #region QualitativeYValues internal List QualitativeYValues { get { if (_QualitativeYValues == null) _QualitativeYValues = new List(); return (_QualitativeYValues); } set { _QualitativeYValues = value; } } #endregion #region SeriesRangeChanged public override bool SeriesRangeChanged { get { return (base.SeriesRangeChanged); } set { if (value != base.SeriesRangeChanged) { base.SeriesRangeChanged = value; if (value == true) _SortedSeriesPoints = null; } } } #endregion #endregion #region MeasureOverride protected override void MeasureOverride(ChartLayoutInfo layoutInfo) { UpdateDataBindings(); UpdateMarkerImage(layoutInfo.Graphics); } #region UpdateMarkerImage private void UpdateMarkerImage(Graphics g) { switch (SeriesType) { case SeriesType.Bubble: case SeriesType.VerticalDot: case SeriesType.Line: case SeriesType.Point: case SeriesType.HorizontalDot: if (PointMarkerImage == null) { ChartXy chartXy = Parent as ChartXy; ChartSeriesVisualStyle sstyle = EffectiveChartSeriesStyle; PointMarkerImage = chartXy.GetPointMarker(g, sstyle.MarkerVisualStyle); } break; } } #endregion #endregion #region ArrangeOverride protected override void ArrangeOverride(ChartLayoutInfo layoutInfo) { BoundsRelative = layoutInfo.LayoutBounds; if (SeriesType == SeriesType.Bubble) UpdateBubblePointOffset(); } #region UpdateBubblePointOffset private void UpdateBubblePointOffset() { BubblePlotData bdata = _PlotData as BubblePlotData; if (bdata != null) { ChartXy chartXy = Parent as ChartXy; Rectangle bounds = chartXy.ContentBoundsEx; float minSize = Dpi.Width(BubbleMinSize); float maxSize = (float)(Math.Min(bounds.Width, bounds.Height) * BubbleMaxPercentage); double minTotalSize; double maxTotalSize; chartXy.GetChartBubbleData(out minTotalSize, out maxTotalSize); BubbleSizeMode smode = GetBubbleSizeMode(chartXy); double range = maxSize - minSize; double sizeRange = (smode == BubbleSizeMode.Diameter) ? maxTotalSize - minTotalSize : MathHelper.ToScalar((float)(maxTotalSize - minTotalSize)); SortedSeriesPoints ssp = GetSortedSeriesPoints(chartXy); for (int i = 0; i < ssp.Count; i++) { SeriesPoint sp = ssp[i]; if (sp.Visible == true) { int size = GetBubbleSize(sp, smode, minSize, maxSize, range, sizeRange); sp.PointSize = new Size(size, size); } } } } #region GetBubbleSize private int GetBubbleSize(SeriesPoint sp, BubbleSizeMode smode, double minSize, double maxSize, double range, double sizeRange) { if (sp.ValueY == null || sp.ValueY.Length < 2 || sizeRange == 0) return (int)minSize; double size = Math.Abs(GetDoubleValue(sp.ValueY[1])); double value = (smode == BubbleSizeMode.Diameter) ? (size * range) / sizeRange : (MathHelper.ToScalar((float)size) * range) / sizeRange; if (BubbleScaleFactor > 0) value *= BubbleScaleFactor; value = Math.Max(minSize, value); return ((int)Math.Min(maxSize, value)); } #endregion #endregion #endregion #region RenderOverride protected override void RenderOverride(ChartRenderInfo renderInfo) { if (SeriesPoints.Count > 0) { Graphics g = renderInfo.Graphics; if (SeriesPoints.Count > 0) { ChartXy chartXy = Parent as ChartXy; ChartSeriesVisualStyle sstyle = EffectiveChartSeriesStyle; SortedSeriesPoints ssp = GetSortedSeriesPoints(chartXy); ssp.SeriesLayoutCount = chartXy.SeriesLayoutCount; UpdateMarkerImage(g); int n = Dpi.Width1; Point pt = chartXy.GetGlobalAdjustedPoint(chartXy.ContentBounds.Location); RenderBounds = new Rectangle(pt, chartXy.ContentBounds.Size); if (RenderBounds.Width > 0 && RenderBounds.Height > 0) { switch (SeriesType) { case SeriesType.Bubble: RenderBubblePlot(g, chartXy, ssp, sstyle); break; case SeriesType.HorizontalBar: RenderHBarPlot(g, chartXy, ssp, sstyle); break; case SeriesType.HorizontalDot: RenderHDotPlot(g, chartXy, ssp, sstyle); break; case SeriesType.HorizontalHiLoBar: RenderHStockPlot(renderInfo, chartXy, ssp, sstyle); break; case SeriesType.Point: RenderPointPlot(g, chartXy, ssp, true, sstyle); break; case SeriesType.Line: RenderLinePlot(g, chartXy, ssp, sstyle); break; case SeriesType.VerticalBar: RenderVBarPlot(g, chartXy, ssp, sstyle); break; case SeriesType.VerticalDot: RenderVDotPlot(g, chartXy, ssp, sstyle); break; case SeriesType.VerticalHiLoBar: RenderVStockPlot(renderInfo, chartXy, ssp, sstyle); break; } } } } } #region GetSortedSeriesPoints internal SortedSeriesPoints GetSortedSeriesPoints(ChartXy chartXy) { if (_SortedSeriesPoints == null) { bool sort = (IsSorted == false && NeedSortedSeries(chartXy) == true); _SortedSeriesPoints = new SortedSeriesPoints(this, sort); if (SeriesType == SeriesType.VerticalDot || SeriesType == SeriesType.HorizontalDot) CombineDuplicates(_SortedSeriesPoints); } return (_SortedSeriesPoints); } #region CombineDuplicates private void CombineDuplicates(SortedSeriesPoints ssp) { SeriesPoint spLast = null; List cList = new List(); List iList = new List(); int dcount = 0; int spLastIndex = 0; for (int i = 0; i < ssp.Count; i++) { SeriesPoint sp = ssp[i]; if (spLast != null && spLast.ValueX.Equals(sp.ValueX) == false) { iList.Add(spLastIndex); cList.Add(dcount); dcount = 0; spLast = sp; spLastIndex = (ssp.IndexArray != null ? ssp.IndexArray[i] : i); } dcount += GetDotCount(sp); if (spLast == null) { spLast = sp; spLastIndex = (ssp.IndexArray != null ? ssp.IndexArray[i] : i); } } if (dcount > 0) { iList.Add(spLastIndex); cList.Add(dcount); } int[] indexArray = new int[iList.Count]; int[] countArray = new int[iList.Count]; for (int i = 0; i < iList.Count; i++) { indexArray[i] = iList[i]; countArray[i] = cList[i]; } ssp.IndexArray = indexArray; ssp.CountArray = countArray; } #endregion #region NeedSortedSeries private bool NeedSortedSeries(ChartXy chartXy) { if (IsSorted == true || _ActualScaleTypeX == ScaleType.Qualitative) return (false); if (SeriesType != SeriesType.Line) return (true); ChartLineDisplayMode mode = GetLineDisplayMode(chartXy); return ((mode & ChartLineDisplayMode.DisplayUnsorted) != ChartLineDisplayMode.DisplayUnsorted); } #endregion #endregion #region RenderBarPlot #region RenderHBarPlot private void RenderHBarPlot(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, ChartSeriesVisualStyle sstyle) { g.RenderingOrigin = chartXy.GetLocalAdjustedPoint(Point.Empty); BarRenderData rd = new BarRenderData(chartXy, AxisX ?? chartXy.AxisX); rd.FillRange = GetBarFillRange(chartXy); rd.BarShading = GetBarShading(chartXy); rd.SeriesStyle = sstyle; int index = 0; bool isHistogram = false; if (chartXy.BarShowAsHistogram == Tbool.True) { ChartAxis axisY = AxisY ?? chartXy.AxisY; AxisBar axisBar = axisY.AxisBars[(int)AxisBarType.Bar]; if (axisBar.BarCount == 1) { TickmarkLayout layout = axisY.TickmarkLayout; for (int i = 0; i < layout.Ticks.Length; i++) { if (layout.Ticks[i].LabelIndex >= 0) { index = i; break; } } isHistogram = true; } } for (int i = 0; i < ssp.Count; i++) { SeriesPoint sp = ssp[i]; if (sp.Visible == true) { rd.Spt = sp.Point[0]; rd.Sp = sp; RenderHBar(g, rd, isHistogram, i + index); } } } #region RenderHBar private void RenderHBar( Graphics g, BarRenderData rd, bool isHistogram, int index) { ChartXy chartXy = rd.ChartXy; SeriesPoint sp = rd.Sp; sp.PointSize = new Size(5, BarWidth); Point ptt = chartXy.GetDataPointEx(this, sp, 0); int y = (int)(ptt.Y + BarOffset - BarWidth / 2); int height = BarWidth; if (isHistogram == true) y = GetHistogramSizeY(chartXy, ptt, index, out height); int x1 = ptt.X; int x2 = GetHBarStart(chartXy, sp); int xOrigin = GetHBarOrigin(chartXy, rd.Axis, sp); if (x1 > x2) { int xtemp = x1; x1 = x2; x2 = xtemp; } if (x2 <= xOrigin) { RenderLeftBar(g, rd, y, height, x1, x2, xOrigin); } else if (x1 >= xOrigin) { RenderRightBar(g, rd, y, height, x1, x2, xOrigin); } else { RenderLeftBar(g, rd, y, height, x1, xOrigin, xOrigin); RenderRightBar(g, rd, y, height, xOrigin, x2, xOrigin); } } #region GetHistogramSizeY private int GetHistogramSizeY( ChartXy chartXy, Point spt, int index, out int height) { ChartAxis axis = AxisY ?? chartXy.AxisY; TickmarkLayout layout = axis.TickmarkLayout; if (index < layout.Ticks.Length) height = layout.Ticks[index + 1].TickPoint.Y - spt.Y; else height = (int)layout.MajorInterval; int y = spt.Y - (int)(layout.MajorInterval / 2); return (y); } #endregion #region GetHBarStart internal int GetHBarStart(ChartXy chartXy, SeriesPoint sp) { ChartAxis axis = AxisX ?? chartXy.AxisX; object value = ((sp.ValueY.Length > 1) ? sp.ValueY[1] : chartXy.BarOrigin ?? null); if (value == null) { if (axis.ScaleType == ScaleType.Quantitative) value = 0; else value = axis.ActualMinValue; } return (chartXy.GetDataPointX(axis, value)); } #endregion #region GetHBarOrigin private int GetHBarOrigin( ChartXy chartXy, ChartAxis axis, SeriesPoint sp) { object value = ((sp.ValueY != null && sp.ValueY.Length > 2) ? sp.ValueY[2] : (chartXy.BarOrigin ?? null)); if (value == null) { if (axis.ScaleType == ScaleType.Quantitative) value = 0; else value = axis.ActualMinValue; } return (chartXy.GetDataPointX(axis, value)); } #endregion #region RenderRightBar private void RenderRightBar(Graphics g, BarRenderData rd, int y, int height, int x1, int x2, int xOrigin) { Rectangle r = new Rectangle(x1, y, x2 - x1, Math.Max(1, height - 1)); if (r.IntersectsWith(RenderBounds)) { Background bk = rd.SeriesStyle.BarVisualStyle.Background; ChartLineVisualStyle lstyle = rd.SeriesStyle.BarVisualStyle.Border; // r is actual area, r2 is FillRange area Rectangle r2 = r; if (rd.FillRange == BarFillRange.BySeries) { r2.X = xOrigin; r2.Width = rd.ChartXy.GetDataPointX(rd.Axis, MaxValueX) - r2.X; } BarSegment segment = (x1 > xOrigin) ? BarSegment.Right : BarSegment.RightPartial; RenderFullHBar(g, rd, r, r2, bk, lstyle, segment); } } #endregion #region RenderLeftBar private void RenderLeftBar(Graphics g, BarRenderData rd, int y, int height, int x1, int x2, int xOrigin) { Rectangle r = new Rectangle(x1, y, x2 - x1, Math.Max(1, height - 1)); if (r.IntersectsWith(RenderBounds)) { ChartSeriesVisualStyle sstyle = rd.SeriesStyle; Background bk = sstyle.BarVisualStyle.AlternateBackground; if (bk.IsEmpty) bk = sstyle.BarVisualStyle.Background; ChartLineVisualStyle lstyle = sstyle.BarVisualStyle.AlternateBorder; if (lstyle.IsEmpty) lstyle = sstyle.BarVisualStyle.Border; Rectangle r2 = r; if (rd.FillRange == BarFillRange.BySeries) { int left = rd.ChartXy.GetDataPointX(rd.Axis, MinValueX); r2.X = left; r2.Width = xOrigin - left; } BarSegment segment = (x2 < xOrigin) ? BarSegment.Left : BarSegment.LeftPartial; RenderFullHBar(g, rd, r, r2, bk, lstyle, segment); } } #endregion #region RenderFullHBar private void RenderFullHBar(Graphics g, BarRenderData rd, Rectangle r, Rectangle r2, Background bk, ChartLineVisualStyle lstyle, BarSegment segment) { if (r2.Width > 0 && r2.Height > 0) { ChartXy chartXy = rd.ChartXy; ChartControl chartControl = ChartControl; if (chartControl.DoPreRenderSeriesBarEvent(g, chartXy, this, rd.Sp, r, r2, segment) == false) { using (Brush br = bk.GetBrush(r2)) g.FillRectangle(br, r); int lw = 0; if (lstyle.LinePattern != LinePattern.None) { SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.None; using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { lw = (int)pen.Width; if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; g.DrawRectangle(pen, r); } g.SmoothingMode = sm; } if (rd.BarShading == true) { Rectangle t = r; t.Inflate(-lw / 2, -lw / 2); t.Width++; t.Height++; RenderHBarShading(g, t, r2, segment); } chartControl.DoPostRenderSeriesBarEvent(g, chartXy, this, rd.Sp, r, r2, segment); } } } #region RenderHBarShading private void RenderHBarShading( Graphics g, Rectangle r, Rectangle r2, BarSegment segment) { if (r.Width > 6) { SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.None; int n = (int)(r.Height * .15); Color[] colors = (Color[])BarShadingColors.Clone(); colors[2] = Color.FromArgb(Math.Max(0, colors[2].A - 30), colors[2]); colors[3] = Color.FromArgb(Math.Max(0, colors[3].A - 30), colors[3]); Rectangle r3 = r; r3.Inflate(1, 1); using (LinearGradientBrush lbr = new LinearGradientBrush(r3, Color.Empty, Color.Empty, 90f)) { lbr.WrapMode = WrapMode.Tile; ColorBlend cb = new ColorBlend(4); cb.Colors = new Color[] { colors[0], Color.Transparent, Color.Transparent, colors[1] }; cb.Positions = new float[] { 0f, .25f, .75f, 1f }; lbr.InterpolationColors = cb; r3.Inflate(-1, -1); g.FillRectangle(lbr, r3); } switch (segment) { case BarSegment.LeftPartial: FillLeft(g, r, n, colors); break; case BarSegment.RightPartial: FillRight(g, r, n, colors); break; default: FillLeft(g, r, n, colors); FillRight(g, r, n, colors); break; } g.SmoothingMode = sm; } } #region FillLeft private void FillLeft(Graphics g, Rectangle r, int n, Color[] colors) { r.Width = n - 1; r.Inflate(1, 0); using (LinearGradientBrush lbr = new LinearGradientBrush(r, colors[2], Color.Transparent, 0f)) { lbr.WrapMode = WrapMode.TileFlipX; r.X++; g.FillRectangle(lbr, r); } } #endregion #region FillRight private void FillRight(Graphics g, Rectangle r, int n, Color[] colors) { r.X = r.Right - n; r.Width = n; r.Inflate(1, 0); using (LinearGradientBrush lbr = new LinearGradientBrush(r, colors[2], Color.Transparent, 180f)) { r.X++; r.Width--; g.FillRectangle(lbr, r); } } #endregion #endregion #endregion #endregion #endregion #region RenderVBarPlot private void RenderVBarPlot(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, ChartSeriesVisualStyle sstyle) { PointData pd = GatherSeriesPoints(chartXy, ssp, 0, ssp.Count, false); if (pd.Points.Count > 0) { g.RenderingOrigin = chartXy.GetLocalAdjustedPoint(Point.Empty); BarRenderData rd = new BarRenderData(chartXy, AxisY ?? chartXy.AxisY); rd.FillRange = GetBarFillRange(chartXy); rd.BarShading = GetBarShading(chartXy); rd.SeriesStyle = sstyle; int index = 0; bool isHistogram = false; if (chartXy.BarShowAsHistogram == Tbool.True) { ChartAxis axisX = AxisX ?? chartXy.AxisX; AxisBar axisBar = axisX.AxisBars[(int)AxisBarType.Bar]; if (axisBar.BarCount == 1) { TickmarkLayout layout = axisX.TickmarkLayout; for (int i = 0; i < layout.Ticks.Length; i++) { if (layout.Ticks[i].LabelIndex >= 0) { index = i; break; } } isHistogram = true; } } for (int i = 0; i < pd.Points.Count; i++) { Point[] pts = pd.Points[i]; SeriesPoint[] spts = pd.SeriesPoints[i]; for (int j = 0; j < pts.Length; j++) { rd.Spt = pts[j]; rd.Sp = spts[j]; RenderVBar(g, rd, isHistogram, j + index); } } } } #region RenderVBar private void RenderVBar( Graphics g, BarRenderData rd, bool isHistogram, int index) { ChartXy chartXy = rd.ChartXy; SeriesPoint sp = rd.Sp; Point spt = rd.Spt; sp.PointSize = new Size(BarWidth, 5); int x = (int)(spt.X + BarOffset - BarWidth / 2); int width = BarWidth; if (isHistogram == true) x = GetHistogramSizeX(chartXy, spt, index, out width); int y1 = spt.Y; int y2 = GetVBarStart(chartXy, sp); int yOrigin = GetVBarOrigin(chartXy, rd.Axis, sp); if (y1 > y2) { int ytemp = y1; y1 = y2; y2 = ytemp; } if (y2 <= yOrigin) { RenderAscendingBar(g, rd, x, width, y1, y2, yOrigin); } else if (y1 >= yOrigin) { RenderDescendingBar(g, rd, x, width, y1, y2, yOrigin); } else { RenderAscendingBar(g, rd, x, width, y1, yOrigin, yOrigin); RenderDescendingBar(g, rd, x, width, yOrigin, y2, yOrigin); } } #region GetHistogramSizeX private int GetHistogramSizeX( ChartXy chartXy, Point spt, int index, out int width) { ChartAxis axis = AxisX ?? chartXy.AxisX; TickmarkLayout layout = axis.TickmarkLayout; if (index < layout.Ticks.Length) width = layout.Ticks[index + 1].TickPoint.X - spt.X; else width = (int)layout.MajorInterval; int x = spt.X - (int)(layout.MajorInterval / 2); return (x); } #endregion #region GetVBarStart internal int GetVBarStart(ChartXy chartXy, SeriesPoint sp) { ChartAxis axis = AxisY ?? chartXy.AxisY; object value = ((sp.ValueY != null && sp.ValueY.Length > 1) ? sp.ValueY[1] : (chartXy.BarOrigin ?? null)); if (value == null) { if (axis.ScaleType == ScaleType.Quantitative) value = 0; else value = axis.ActualMinValue; } return (chartXy.GetDataPointY(axis, value)); } #endregion #region GetVBarOrigin private int GetVBarOrigin( ChartXy chartXy, ChartAxis axis, SeriesPoint sp) { object value = ((sp.ValueY != null && sp.ValueY.Length > 2) ? sp.ValueY[2] : (chartXy.BarOrigin ?? null)); if (value == null) { if (axis.ScaleType == ScaleType.Quantitative) value = 0; else value = axis.ActualMinValue; } return (chartXy.GetDataPointY(axis, value)); } #endregion #region RenderAscendingBar private void RenderAscendingBar(Graphics g, BarRenderData rd, int x, int width, int y1, int y2, int yOrigin) { Rectangle r = new Rectangle(x, y1, Math.Max(1, width - 1), y2 - y1); if (r.IntersectsWith(RenderBounds)) { Background bk = rd.SeriesStyle.BarVisualStyle.Background; ChartLineVisualStyle lstyle = rd.SeriesStyle.BarVisualStyle.Border; Rectangle r2 = r; if (rd.FillRange == BarFillRange.BySeries) { int top = rd.ChartXy.GetDataPointY(rd.Axis, MaxValueY); r2.Y = top; r2.Height = yOrigin - top; } BarSegment segment = (y2 < yOrigin) ? BarSegment.Top : BarSegment.TopPartial; RenderFullVBar(g, rd, r, r2, bk, lstyle, segment); } } #endregion #region RenderDescendingBar private void RenderDescendingBar(Graphics g, BarRenderData rd, int x, int width, int y1, int y2, int yOrigin) { Rectangle r = new Rectangle(x, y1, Math.Max(1, width - 1), y2 - y1); if (r.IntersectsWith(RenderBounds)) { ChartSeriesVisualStyle sstyle = rd.SeriesStyle; Background bk = sstyle.BarVisualStyle.AlternateBackground; if (bk.IsEmpty) bk = sstyle.BarVisualStyle.Background; ChartLineVisualStyle lstyle = sstyle.BarVisualStyle.AlternateBorder; if (lstyle.IsEmpty) lstyle = sstyle.BarVisualStyle.Border; Rectangle r2 = r; if (GetBarFillRange(rd.ChartXy) == BarFillRange.BySeries) { r2.Y = yOrigin; r2.Height = rd.ChartXy.GetDataPointY(rd.Axis, MinValueY) - r2.Y; } BarSegment segment = (y1 > yOrigin) ? BarSegment.Bottom : BarSegment.BottomPartial; RenderFullVBar(g, rd, r, r2, bk, lstyle, segment); } } #endregion #region RenderFullVBar private void RenderFullVBar(Graphics g, BarRenderData rd, Rectangle r, Rectangle r2, Background bk, ChartLineVisualStyle lstyle, BarSegment segment) { if (r2.Width > 0 && r2.Height > 0) { ChartXy chartXy = rd.ChartXy; ChartControl chartControl = ChartControl; if (chartControl.DoPreRenderSeriesBarEvent(g, chartXy, this, rd.Sp, r, r2, segment) == false) { using (Brush br = bk.GetBrush(r2)) g.FillRectangle(br, r); int lw = 0; if (lstyle.LinePattern != LinePattern.None) { SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.None; using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { lw = (int)pen.Width; if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; g.DrawRectangle(pen, r); } g.SmoothingMode = sm; } if (rd.BarShading == true) { Rectangle t = r; t.Inflate(-lw / 2, -lw / 2); t.Width++; t.Height++; RenderVBarShading(g, t, r2, segment); } chartControl.DoPostRenderSeriesBarEvent(g, chartXy, this, rd.Sp, r, r2, segment); } } } #region RenderVBarShading private void RenderVBarShading( Graphics g, Rectangle r, Rectangle r2, BarSegment segment) { int n = r.Width / 10 + 1; if (r.Width > 6 && r.Height > n) { SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.None; Color[] colors = (Color[])BarShadingColors.Clone(); Rectangle r3 = r; using (LinearGradientBrush lbr = new LinearGradientBrush(r3, Color.Empty, Color.Empty, 0f)) { lbr.WrapMode = WrapMode.TileFlipX; ColorBlend cb = new ColorBlend(4); cb.Colors = new Color[] { colors[2], Color.Transparent, Color.Transparent, colors[3] }; cb.Positions = new float[] { 0f, .15f, .85f, 1f }; lbr.InterpolationColors = cb; g.FillRectangle(lbr, r3); } switch (segment) { case BarSegment.TopPartial: FillTop(g, r, n, colors); break; case BarSegment.BottomPartial: FillBottom(g, r, n, colors); break; default: FillTop(g, r, n, colors); FillBottom(g, r, n, colors); break; } g.SmoothingMode = sm; } } #region FillTop private void FillTop(Graphics g, Rectangle r, int n, Color[] colors) { using (Pen pen = new Pen(colors[0])) { Point pt1 = new Point(r.X + 1, r.Y); Point pt2 = new Point(r.Right - 2, r.Y); for (int i = 0; i < n; i++) { g.DrawLine(pen, pt1, pt2); pt1.X++; pt2.X--; pt1.Y++; pt2.Y++; } } } #endregion #region FillBottom private void FillBottom(Graphics g, Rectangle r, int n, Color[] colors) { using (Pen pen = new Pen(colors[1])) { Point pt1 = new Point(r.X + 1, r.Bottom - 1); Point pt2 = new Point(r.Right - 2, r.Bottom - 1); for (int i = 0; i < n; i++) { g.DrawLine(pen, pt1, pt2); pt1.X++; pt2.X--; pt1.Y--; pt2.Y--; } } } #endregion #endregion #endregion #endregion #endregion #region GetBarFillRange private BarFillRange GetBarFillRange(ChartXy chartXy) { BarFillRange fillRange = BarFillRange; if (fillRange == BarFillRange.NotSet) fillRange = chartXy.BarFillRange; return ((fillRange != BarFillRange.NotSet) ? fillRange : BarFillRange.ByBar); } #endregion #region GetBarLabelPosition internal BarLabelPosition GetBarLabelPosition(ChartXy chartXy) { BarLabelPosition labelPos = BarLabelPosition; if (labelPos == BarLabelPosition.NotSet) labelPos = chartXy.BarLabelPosition; return ((labelPos != BarLabelPosition.NotSet) ? labelPos : BarLabelPosition.Center); } #endregion #region GetBarShading private bool GetBarShading(ChartXy chartXy) { Tbool barShading = BarShadingEnabled; if (barShading == Tbool.NotSet) barShading = chartXy.BarShadingEnabled; return (barShading == Tbool.True); } #endregion #endregion #region RenderBubblePlot private void RenderBubblePlot(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, ChartSeriesVisualStyle sstyle) { BubblePlotData bdata = _PlotData as BubblePlotData; if (bdata != null) { double minIntensity = 32; double maxIntensity = 255; PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle; PointMarkerVisualStyle hstyle = GetHighlightStyle(chartXy, sstyle); if (DisplayLinePointsOnTop == true) RenderConvexHull(g, chartXy, ssp, sstyle, pstyle); BubbleIntensityMode imode = GetBubbleIntensityMode(chartXy); for (int i = 0; i < ssp.Count; i++) { SeriesPoint sp = ssp[i]; if (sp.Visible == true) { int size = sp.PointSize.Width; Point pt = chartXy.GetDataPointNa(this, sp, 0); Rectangle r = new Rectangle(pt.X - size / 2, pt.Y - size / 2, size, size); if (r.IntersectsWith(RenderBounds)) { Point ppt = chartXy.GetLocalAdjustedPoint(pt); bool isCrossPoint = chartXy.IsCrosshairSeriesPoint(this, ppt); int intensity = GetIntensity(sp, imode, bdata, minIntensity, maxIntensity); PointMarkerVisualStyle style = (hstyle != null && isCrossPoint) ? hstyle : pstyle; Image image = style.GetPointMarkerImage(); if (image == null) image = GetPointMarker(g, style, r.Size); if (image != null) { g.DrawImage(image, r); } else if (style.Type == PointMarkerType.Ellipse || style.Type == PointMarkerType.NotSet) { using (Brush br = style.Background.GetBrush(r, intensity)) { g.FillEllipse(br, r); if (style.BorderColor.IsEmpty == false && style.BorderWidth > 0) { using (Pen pen = new Pen(style.BorderColor, Dpi.Width(style.BorderWidth))) g.DrawEllipse(pen, r); } } } } } } if (DisplayLinePointsOnTop == false) RenderConvexHull(g, chartXy, ssp, sstyle, pstyle); if (hstyle != null) hstyle.Dispose(); } } #region GetIntensity private int GetIntensity(SeriesPoint sp, BubbleIntensityMode imode, BubblePlotData bdata, double minIntensity, double maxIntensity) { if (imode != BubbleIntensityMode.None && imode != BubbleIntensityMode.NotSet) { if (sp.ValueY.Length > 2) { double intensity = -1; if (sp.ValueY[2] is double) intensity = (double)sp.ValueY[2]; else if (sp.ValueY[2] is int) intensity = Convert.ToDouble(sp.ValueY[2]); if (imode == BubbleIntensityMode.Alpha) return ((int)intensity); if (intensity >= 0) { double range = maxIntensity - minIntensity; double intensityRange = bdata.MaxIntensity - bdata.MinIntensity; if (intensityRange <= 0) return (-1); return (int)(((intensity - bdata.MinIntensity) * range) / intensityRange + minIntensity); } } } return (-1); } #endregion #region GetBubbleSizeMode private BubbleSizeMode GetBubbleSizeMode(ChartXy chartXy) { if (BubbleSizeMode != BubbleSizeMode.NotSet) return (BubbleSizeMode); if (chartXy.BubbleSizeMode != BubbleSizeMode.NotSet) return (chartXy.BubbleSizeMode); return (BubbleSizeMode.Area); } #endregion #region GetBubbleIntensityMode private BubbleIntensityMode GetBubbleIntensityMode(ChartXy chartXy) { if (BubbleIntensityMode != BubbleIntensityMode.NotSet) return (BubbleIntensityMode); if (chartXy.BubbleIntensityMode != BubbleIntensityMode.NotSet) return (chartXy.BubbleIntensityMode); return (BubbleIntensityMode.None); } #endregion #region GetPointMarker internal Image GetPointMarker(Graphics g, PointMarkerVisualStyle style, Size size) { if (style.Type == PointMarkerType.NotSet || style.Type == PointMarkerType.None || style.Type == PointMarkerType.Ellipse) { return (null); } if (_PointMarker == null) _PointMarker = new PointMarker(); return (_PointMarker.GetMarkerBitmap(g, style.Type, style.PointCount, size, style.Rotation, style.Background, style.BorderColor, style.BorderWidth)); } #endregion #endregion #region RenderDotPlot #region RenderHDotPlot private void RenderHDotPlot(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, ChartSeriesVisualStyle sstyle) { Image marker = PointMarkerImage; if (marker != null) { Size maxSize = chartXy.GetMaxDotPlotMarkerSize(); for (int i = 0; i < ssp.Count; i++) { SeriesPoint sp = ssp[i]; if (sp.Visible == true) { object pointValueX = chartXy.GetDataPointValueX(this, sp); Point pt = chartXy.GetPointFromValue(this, 0, pointValueX); Point ppt = new Point(pt.X + maxSize.Width / 2, pt.Y); int dcount = ssp.CountArray[i]; for (int j = 0; j < dcount; j++) { RenderPointMarker(g, chartXy, sp, ppt, maxSize, marker); ppt.X += maxSize.Width; } } } } } #endregion #region RenderVDotPlot private void RenderVDotPlot(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, ChartSeriesVisualStyle sstyle) { Image marker = PointMarkerImage; if (marker != null) { Size maxSize = chartXy.GetMaxDotPlotMarkerSize(); for (int i = 0; i < ssp.Count; i++) { SeriesPoint sp = ssp[i]; if (sp.Visible == true) { Point pt = chartXy.GetDataPointNa(this, sp, -1); Point ppt = new Point(pt.X, pt.Y - maxSize.Height / 2); int dcount = ssp.CountArray[i]; for (int j = 0; j < dcount; j++) { RenderPointMarker(g, chartXy, sp, ppt, maxSize, marker); ppt.Y -= maxSize.Height; } } } } } #endregion #region GetDotCount private int GetDotCount(SeriesPoint sp) { if (sp.ValueY != null && sp.ValueY.Length > 0) { int count = 0; foreach (object o in sp.ValueY) { if (o is int) count += (int)o; else if (o is double) count += (int)Convert.ChangeType(o, typeof(int)); } return (count); } return (1); } #endregion #endregion #region RenderPointPlot private void RenderPointPlot(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, bool showHull, ChartSeriesVisualStyle sstyle) { PointData pd = GatherSeriesPoints(chartXy, ssp, 0, ssp.Count, true); if (pd.Points.Count > 0) { PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle; PointMarkerVisualStyle hstyle = GetHighlightStyle(chartXy, sstyle); if (showHull == true) RenderConvexHull(g, chartXy, ssp, sstyle, pstyle); if (hstyle == null) { Image marker = chartXy.GetPointMarker(g, pstyle); if (marker != null) { for (int i = 0; i < pd.Points.Count; i++) { Point[] pts = pd.Points[i]; SeriesPoint[] spts = pd.SeriesPoints[i]; for (int j = 0; j < pts.Length; j++) RenderPointMarker(g, chartXy, spts[j], pts[j], Size.Empty, marker); } } } else { bool highlightSinglePoint = HighLightSinglePoint(chartXy); Image highlightMarker = GetHighlightImage(g, chartXy, hstyle); for (int i = 0; i < pd.Points.Count; i++) { Point[] pts = pd.Points[i]; SeriesPoint[] spts = pd.SeriesPoints[i]; for (int j = 0; j < pts.Length; j++) { Point ppt = pts[j]; Point ppt2 = chartXy.GetLocalAdjustedPoint(ppt); Image marker = PointMarkerImage; if (highlightMarker != null) { if (chartXy.IsCrosshairSeriesPoint(this, ppt2) == true) { marker = highlightMarker; if (highlightSinglePoint == true) highlightMarker = null; } } RenderPointMarker(g, chartXy, spts[j], ppt, Size.Empty, marker); } } } if (ShowEmptyPoints == true) RenderEmptyPoints(g, chartXy, pd, sstyle); } } #region RenderPointMarker private void RenderPointMarker(Graphics g, ChartXy chartXy, SeriesPoint sp, Point pt, Size maxSize, Image marker) { if (marker != null) { ChartControl control = ChartControl; Image ptMarker = marker; Size markerSize = marker.Size; Size size = maxSize.IsEmpty ? markerSize : maxSize; sp.PointSize = size; Point ptc = new Point( pt.X - markerSize.Width / 2, pt.Y - markerSize.Height / 2); Rectangle r = new Rectangle(ptc, markerSize); if (r.IntersectsWith(RenderBounds)) { if (control.DoPreRenderSeriesPointEvent(g, chartXy, this, sp, pt, size, ref ptMarker) == false) { if (ptMarker != null) { g.DrawImageUnscaled(ptMarker, ptc); control.DoPostRenderSeriesPointEvent(g, chartXy, this, sp, pt, ptMarker.Size, ptMarker); } } } } } #endregion #region RenderConvexHull private void RenderConvexHull(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, ChartSeriesVisualStyle sstyle, PointMarkerVisualStyle pstyle) { ConvexHullDisplayMode mode = GetConvexHullDisplayMode(chartXy); if (mode != ConvexHullDisplayMode.None) { if (_ConvexHullPoints == null) { PointData pd = GatherSeriesPointsEx(chartXy, ssp, 0, ssp.Count, true); _ConvexHullPoints = ConvexHull.GetConvexHull( (pd.Points.Count == 1) ? pd.Points[0] : CombineListPoints(pd.Points)); } if (_ConvexHullPoints.Length > 3) { using (GraphicsPath path = new GraphicsPath()) { path.AddPolygon(_ConvexHullPoints); if ((mode & ConvexHullDisplayMode.DisplayBackground) == ConvexHullDisplayMode.DisplayBackground) { Rectangle r = Rectangle.Round(path.GetBounds()); Background bg = (sstyle.ConvexHullBackground.IsEmpty) ? pstyle.Background : sstyle.ConvexHullBackground; using (Brush br = bg.GetBrush(r)) g.FillPath(br, path); } if ((mode & ConvexHullDisplayMode.DisplayBorder) == ConvexHullDisplayMode.DisplayBorder) { Color color; int width; LinePattern pattern; if (sstyle.ConvexHullLineStyle.IsEmpty == false) { color = sstyle.ConvexHullLineStyle.LineColor; width = sstyle.ConvexHullLineStyle.LineWidth; pattern = sstyle.ConvexHullLineStyle.LinePattern; } else { color = pstyle.BorderColor; width = pstyle.BorderWidth; pattern = LinePattern.Solid; } if (pattern != LinePattern.None) { using (Pen pen = new Pen(color, Dpi.Width(width))) { if (pattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)pattern; g.DrawPath(pen, path); } } } } } } } #region GetConvexHullDisplayMode private ConvexHullDisplayMode GetConvexHullDisplayMode(ChartXy chartXy) { if (ConvexHullDisplayMode != ConvexHullDisplayMode.NotSet) return (ConvexHullDisplayMode); ConvexHullDisplayMode mode = chartXy.ConvexHullDisplayMode; if (mode != ConvexHullDisplayMode.NotSet) return (mode); return (ConvexHullDisplayMode.None); } #endregion #region CombineListPoints private Point[] CombineListPoints(List plist) { int n = 0; foreach (Point[] points in plist) n += points.Length; Point[] fpoints = new Point[n]; n = 0; foreach (Point[] points in plist) { for (int i = 0; i < points.Length; i++) fpoints[n++] = points[i]; } return (fpoints); } #endregion #endregion #region RenderEmptyPoints private void RenderEmptyPoints(Graphics g, ChartXy chartXy, PointData pd, ChartSeriesVisualStyle sstyle) { PointData epd = _EmptyPointData; if (epd != null && epd.Points.Count > 0) { PointMarkerVisualStyle pstyle = sstyle.MarkerEmptyVisualStyle; Image marker = GetEmptyMarkerImage(g, chartXy, pstyle); if (marker != null) { for (int i = 0; i < epd.Points.Count; i++) { Point[] epts = epd.Points[i]; SeriesPoint[] septs = epd.SeriesPoints[i]; Point[] pts = GetEmptyPointRange(epts[0]); int run = pts[0].X - pts[1].X; int rise = pts[0].Y - pts[1].Y; double slope = (run != 0) ? (double)rise / run : 0; double b = pts[0].Y - (slope * pts[0].X); for (int j = 0; j < epts.Length; j++) { Point ept = epts[j]; SeriesPoint sept = septs[j]; Point ppt = new Point(ept.X, (int)(slope * ept.X + b)); RenderPointMarker(g, chartXy, sept, ppt, Size.Empty, marker); } } } } } #region GetEmptyPointRange private Point[] GetEmptyPointRange(Point pt) { Point[] pts = new Point[2]; pts[0] = Point.Empty; pts[1] = Point.Empty; PointData pd = _PointData; for (int i = 0; i < pd.Points.Count; i++) { Point[] lps = pd.Points[i]; if (pt.X <= lps[0].X) { pts[1] = lps[0]; if (i == 0) pts[0] = pts[1]; return (pts); } pts[0] = lps[lps.Length - 1]; } pts[1] = pts[0]; return (pts); } #endregion #endregion #endregion #region RenderLinePlot private void RenderLinePlot(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, ChartSeriesVisualStyle sstyle) { PointData pd = GatherSeriesPoints(chartXy, ssp, 0, ssp.Count, false); if (pd.Points.Count > 0) { ChartLineDisplayMode lineMode = GetLineDisplayMode(chartXy); ChartLineAreaDisplayMode areaMode = GetAreaDisplayMode(chartXy); PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle; RenderConvexHull(g, chartXy, ssp, sstyle, pstyle); if (DisplayLinePointsOnTop == true) RenderLinePlotLines(g, chartXy, pd, lineMode, areaMode, sstyle); if ((lineMode & ChartLineDisplayMode.DisplayPoints) == ChartLineDisplayMode.DisplayPoints) { RenderPointPlot(g, chartXy, ssp, false, sstyle); } else { if (ShowEmptyPoints == true) RenderEmptyPoints(g, chartXy, pd, sstyle); RenderPointLabelPoints(g, chartXy, sstyle); if (HighLightPoints(chartXy) == true) RenderHighlightPoints(g, chartXy, pd, sstyle); } if (DisplayLinePointsOnTop == false) RenderLinePlotLines(g, chartXy, pd, lineMode, areaMode, sstyle); } } #region RenderPointLabelPoints private void RenderPointLabelPoints(Graphics g, ChartXy chartXy, ChartSeriesVisualStyle sstyle) { List pointLabels = chartXy.PointLabels; if (pointLabels != null && pointLabels.Count > 0) { foreach (PointLabelGroup lg in pointLabels) { if (lg.ChartSeries == this) { PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle; Image marker = chartXy.GetPointMarker(g, pstyle); if (marker != null) { Size size = marker.Size; for (int i = 0; i < lg.PointLabels.Count; i++) { PointLabel pl = lg.PointLabels[i]; if (pl.Visible == true && pl.SeriesPoint.IsEmpty == false) { DataLabelVisualStyle dstyle = GetPointLabelVisualStyle(pl); if (dstyle.DrawPointMarker != Tbool.False) { SeriesPoint spt = pl.SeriesPoint; Point ppt = pl.Point; Point ppc = new Point(ppt.X, ppt.Y); RenderPointMarker(g, chartXy, spt, ppc, Size.Empty, marker); } } } } break; } } } } #endregion #region RenderLinePlotLines private void RenderLinePlotLines(Graphics g, ChartXy chartXy, PointData pd, ChartLineDisplayMode lineMode, ChartLineAreaDisplayMode areaMode, ChartSeriesVisualStyle sstyle) { if ((lineMode & ChartLineDisplayMode.DisplayStepLine) == ChartLineDisplayMode.DisplayStepLine) { StepLineMode slm = GetStepLineMode(chartXy); if (slm != StepLineMode.None) RenderStepLines(g, chartXy, pd, slm, areaMode, sstyle); } if ((lineMode & ChartLineDisplayMode.DisplayLine) == ChartLineDisplayMode.DisplayLine) RenderLines(g, chartXy, pd, lineMode, areaMode, sstyle); if ((lineMode & ChartLineDisplayMode.DisplaySpline) == ChartLineDisplayMode.DisplaySpline) RenderSplines(g, chartXy, pd, lineMode, areaMode, sstyle); if (ShowEmptyLines == true) { if ((lineMode & (ChartLineDisplayMode.DisplayLine | ChartLineDisplayMode.DisplaySpline)) != 0) RenderEmptyLines(g, chartXy, pd.Points, areaMode, sstyle); } } #region GetStepLineMode private StepLineMode GetStepLineMode(ChartXy chartXy) { StepLineMode mode = StepLineMode; if (mode == StepLineMode.NotSet) mode = chartXy.StepLineMode; if (mode == StepLineMode.NotSet) mode = StepLineMode.HorizontalThenVertical; return (mode); } #endregion #region RenderLines private void RenderLines(Graphics g, ChartXy chartXy, PointData pd, ChartLineDisplayMode lineMode, ChartLineAreaDisplayMode areaMode, ChartSeriesVisualStyle sstyle) { ChartLineVisualStyle lstyle = sstyle.LineStyle; if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; if ((lineMode & ChartLineDisplayMode.DisplayClosed) == ChartLineDisplayMode.DisplayClosed) { foreach (Point[] points in pd.Points) { if (points.Length > 1) g.DrawLines(pen, points); } Point fp = pd.Points[0][0]; Point[] lps = pd.Points[pd.Points.Count - 1]; Point lp = lps[lps.Length - 1]; if (fp.Equals(lp) == false) g.DrawLine(pen, lp, fp); } else { foreach (Point[] points in pd.Points) { if (points.Length > 1) { using (GraphicsPath path = new GraphicsPath()) { path.AddLines(points); if ((areaMode & ChartLineAreaDisplayMode.DisplayLine) == ChartLineAreaDisplayMode.DisplayLine) RenderAreaBackground(g, chartXy, points, path, sstyle.LineAreaBackground); g.DrawPath(pen, path); } } } } } } } #endregion #region RenderSplines private void RenderSplines(Graphics g, ChartXy chartXy, PointData pd, ChartLineDisplayMode lineMode, ChartLineAreaDisplayMode areaMode, ChartSeriesVisualStyle sstyle) { ChartLineVisualStyle lstyle = sstyle.SplineStyle; if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; if ((pd.Points.Count == 1) && (lineMode & ChartLineDisplayMode.DisplayClosed) == ChartLineDisplayMode.DisplayClosed) { Point[] points = pd.Points[0]; if (points.Length > 1) g.DrawClosedCurve(pen, points); } else { foreach (Point[] points in pd.Points) { if (points.Length > 1) { using (GraphicsPath path = new GraphicsPath()) { path.AddCurve(points); if ((areaMode & ChartLineAreaDisplayMode.DisplaySpline) == ChartLineAreaDisplayMode.DisplaySpline) RenderAreaBackground(g, chartXy, points, path, sstyle.SplineAreaBackground); g.DrawPath(pen, path); } } } } } } } #endregion #region RenderStepLines private void RenderStepLines(Graphics g, ChartXy chartXy, PointData pd, StepLineMode slm, ChartLineAreaDisplayMode areaMode, ChartSeriesVisualStyle sstyle) { StepLines sls = GetStepLines(chartXy); if (sls != StepLines.None) { PointData sd = GetStepPointData(chartXy, pd, slm); if (sd != null) { SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.Default; ChartCapLineVisualStyle lstyle = sstyle.StepLineStyle; if (sls == StepLines.Both) { RenderStepLinesEx1(g, sd, lstyle); } else { int n = ((sls == StepLines.Horizontal && (slm == StepLineMode.HorizontalThenVertical || slm == StepLineMode.MidPoint)) || (sls == StepLines.Vertical && slm == StepLineMode.VerticalThenHorizontal)) ? 0 : 1; RenderStepLinesEx2(g, sd, n, lstyle); if (sstyle.StepLineAltStyle.IsEmpty == false) RenderStepLinesEx2(g, sd, n ^ 1, sstyle.StepLineAltStyle); } g.SmoothingMode = sm; if ((areaMode & ChartLineAreaDisplayMode.DisplayStepLine) == ChartLineAreaDisplayMode.DisplayStepLine) { foreach (Point[] points in sd.Points) { using (GraphicsPath path = new GraphicsPath()) { path.AddLines(points); RenderAreaBackground(g, chartXy, points, path, sstyle.StepLineAreaBackground); } } } } } } #region GetStepLines private StepLines GetStepLines(ChartXy chartXy) { StepLines mode = StepLines; if (mode == StepLines.NotSet) mode = chartXy.StepLines; if (mode == StepLines.NotSet) mode = StepLines.Both; return (mode); } #endregion #region GetStepPointData private PointData GetStepPointData( ChartXy chartXy, PointData pd, Charts.StepLineMode slm) { if (_LastStepLineMode != slm) _StepPointData = null; if (_StepPointData == null) { PointData sd = new PointData(); sd.Points = new List(); foreach (Point[] points in pd.Points) { if (points.Length > 1) sd.Points.Add(GetStepPoints(slm, points)); } _StepPointData = sd; _LastStepLineMode = slm; } return (_StepPointData); } #region GetStepPoints private Point[] GetStepPoints(StepLineMode slm, Point[] pts) { if (slm == StepLineMode.HorizontalThenVertical || slm == StepLineMode.VerticalThenHorizontal) { Point[] points = new Point[pts.Length * 2 - 1]; if (slm == StepLineMode.HorizontalThenVertical) { for (int i = 0; i < pts.Length; i++) { int n = i * 2; points[n] = pts[i]; if (i + 1 < pts.Length) points[n + 1] = new Point(pts[i + 1].X, pts[i].Y); } } else { for (int i = 0; i < pts.Length; i++) { int n = i * 2; points[n] = pts[i]; if (i + 1 < pts.Length) points[n + 1] = new Point(pts[i].X, pts[i + 1].Y); } } return (points); } else { Point[] points = new Point[pts.Length * 2]; points[0] = pts[0]; for (int i = 0; i < pts.Length - 1; i++) { int n0 = i * 2 + 1; int n1 = n0 + 1; points[n0] = new Point((pts[i].X + pts[i + 1].X) / 2, pts[i].Y); points[n1] = new Point(points[n0].X, pts[i + 1].Y); } points[points.Length - 1] = pts[pts.Length - 1]; return (points); } } #endregion #endregion #region RenderStepLinesEx1 private void RenderStepLinesEx1(Graphics g, PointData sd, ChartCapLineVisualStyle lstyle) { if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; if (lstyle.StartCap != ChartLineCap.NotSet) pen.StartCap = (LineCap)lstyle.StartCap; if (lstyle.EndCap != ChartLineCap.NotSet) pen.EndCap = (LineCap)lstyle.EndCap; foreach (Point[] points in sd.Points) { if (points.Length > 1) g.DrawLines(pen, points); } } } } #endregion #region RenderStepLinesEx2 private void RenderStepLinesEx2(Graphics g, PointData sd, int n, ChartCapLineVisualStyle lstyle) { if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; if (lstyle.StartCap != ChartLineCap.NotSet) pen.StartCap = (LineCap)lstyle.StartCap; if (lstyle.EndCap != ChartLineCap.NotSet) pen.EndCap = (LineCap)lstyle.EndCap; foreach (Point[] points in sd.Points) { if (points.Length > 1) { for (int i = n; i < points.Length - 1; i += 2) { Point pt1 = points[i]; Point pt2 = points[i + 1]; g.DrawLine(pen, pt1, pt2); } } } } } } #endregion #endregion #region RenderEmptyLines private void RenderEmptyLines(Graphics g, ChartXy chartXy, List lpoints, ChartLineAreaDisplayMode areaMode, ChartSeriesVisualStyle sstyle) { if (lpoints.Count > 1) { ChartLineVisualStyle lstyle = sstyle.EmptyStyle; if (lstyle.LinePattern != LinePattern.None) { Point[] points = new Point[(lpoints.Count - 1) * 2]; Point[][] epoints = new Point[lpoints.Count - 1][]; for (int i = 0; i < lpoints.Count - 1; i++) { Point[] pts1 = lpoints[i]; Point[] pts2 = lpoints[i + 1]; epoints[i] = new Point[2]; epoints[i][0] = pts1[pts1.Length - 1]; epoints[i][1] = pts2[0]; } for (int i = 0; i < points.Length / 2; i++) { using (GraphicsPath path = new GraphicsPath()) { path.AddLines(epoints[i]); if ((areaMode & ChartLineAreaDisplayMode.DisplayEmptyLine) == ChartLineAreaDisplayMode.DisplayEmptyLine) RenderAreaBackground(g, chartXy, epoints[i], path, sstyle.EmptyAreaBackground); using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; g.DrawPath(pen, path); } } } } } } #endregion #region RenderAreaBackground private void RenderAreaBackground(Graphics g, ChartXy chartXy, Point[] points, GraphicsPath path, Background background) { bool backEmpty = (background == null || background.IsEmpty == true); if (backEmpty == true) background = new Background(Color.FromArgb(100, DefaultPaletteColor)); if (background != null && background.IsEmpty == false) { int y = chartXy.ContentBoundsEx.Bottom; if (AreaBaseValue != null) { ChartAxis axis = _AxisY ?? chartXy.AxisY; y = chartXy.GetDataPointY(axis, AreaBaseValue); } using (GraphicsPath path2 = new GraphicsPath()) { path2.AddLine(new Point(points[0].X, y), points[0]); path2.AddPath(path, true); path2.AddLine(points[points.Length - 1], new Point(points[points.Length - 1].X, y)); path2.CloseFigure(); Rectangle r = Rectangle.Round(path2.GetBounds()); using (Brush br = background.GetBrush(r)) g.FillPath(br, path2); } } if (backEmpty == true) background.Dispose(); } #endregion #endregion #region RenderHighlightPoints private void RenderHighlightPoints(Graphics g, ChartXy chartXy, PointData pd, ChartSeriesVisualStyle sstyle) { PointMarkerVisualStyle hstyle = GetHighlightStyle(chartXy, sstyle); Image marker = GetHighlightImage(g, chartXy, hstyle); if (marker != null) { Size size = marker.Size; Point pt = chartXy.GetLocalAdjustedPoint(Point.Empty); for (int i = 0; i < pd.Points.Count; i++) { Point[] pts = pd.Points[i]; SeriesPoint[] spts = pd.SeriesPoints[i]; for (int j = 0; j < pts.Length; j++) { Point ppt = pts[j]; Point ppc = new Point(ppt.X, ppt.Y); Point lppc = new Point(ppt.X + pt.X, ppt.Y + pt.Y); if (chartXy.IsCrosshairSeriesPoint(this, lppc) == true) { RenderPointMarker(g, chartXy, spts[j], ppc, Size.Empty, marker); if (HighLightSinglePoint(chartXy) == true) break; } } } } } #endregion #region GetLineDisplayMode private ChartLineDisplayMode GetLineDisplayMode(ChartXy chartXy) { ChartLineDisplayMode mode = ChartLineDisplayMode; if (mode == ChartLineDisplayMode.NotSet) mode = chartXy.ChartLineDisplayMode; if (mode == ChartLineDisplayMode.NotSet) mode = ChartLineDisplayMode.DisplayLine; return (mode); } #endregion #region GetAreaDisplayMode private ChartLineAreaDisplayMode GetAreaDisplayMode(ChartXy chartXy) { ChartLineAreaDisplayMode mode = ChartLineAreaDisplayMode; if (mode == ChartLineAreaDisplayMode.NotSet) mode = chartXy.ChartLineAreaDisplayMode; if (mode == ChartLineAreaDisplayMode.NotSet) mode = ChartLineAreaDisplayMode.None; return (mode); } #endregion #endregion #region RenderStockPlot #region RenderHStockPlot private void RenderHStockPlot(ChartRenderInfo renderInfo, ChartXy chartXy, SortedSeriesPoints ssp, ChartSeriesVisualStyle sstyle) { HiLoRenderData rd = new HiLoRenderData(chartXy, AxisX ?? chartXy.AxisX); rd.SeriesStyle = sstyle; for (int i = 0; i < ssp.Count; i++) { SeriesPoint sp = ssp[i]; if (sp.Visible == true) { rd.Sp = sp; rd.Spt = sp.Point[0]; rd.Index = i; RenderHStock(renderInfo, rd); } } } #region RenderHStock private void RenderHStock(ChartRenderInfo renderInfo, HiLoRenderData rd) { Graphics g = renderInfo.Graphics; rd.Value = GetHStockValues(rd.ChartXy, rd.Sp); if (rd.Value[StockHigh] != int.MinValue) { Point pt = rd.ChartXy.GetDataPointEx(this, rd.Sp, 0); Rectangle r = GetHBoundingRect(rd, pt); if (r.IntersectsWith(RenderBounds) == true) { int y = pt.Y + BarOffset; rd.Sp.PointSize = new Size(5, BarWidth / 3); switch (HiLoBarType) { case HiLoBarType.Box: case HiLoBarType.Candle: RenderHStockBox(g, rd, y); break; default: RenderHStockHiLo(g, rd, y); break; } } } } #region GetHBoundingRect private Rectangle GetHBoundingRect(HiLoRenderData rd, Point pt) { int x1 = rd.Value[StockHigh]; int x2 = rd.Value[StockLow]; if (rd.Value[StockOpen] != int.MinValue) { if (rd.Value[StockOpen] > x1) x1 = rd.Value[StockOpen]; if (rd.Value[StockOpen] < x2) x2 = rd.Value[StockOpen]; } if (rd.Value[StockClose] != int.MinValue) { if (rd.Value[StockClose] > x1) x1 = rd.Value[StockClose]; if (rd.Value[StockClose] < x2) x2 = rd.Value[StockClose]; } int y = pt.Y + BarOffset - BarWidth / 2; return (new Rectangle(x2, y, x1 - x2, BarWidth)); } #endregion #region RenderHStockBox private void RenderHStockBox(Graphics g, HiLoRenderData rd, int y) { int x1 = rd.Value[StockClose]; int x2 = rd.Value[StockOpen]; if (rd.Value[StockOpen] != int.MinValue && rd.Value[StockClose] != int.MinValue) { if (rd.Value[StockOpen] < rd.Value[StockClose]) { x1 = rd.Value[StockOpen]; x2 = rd.Value[StockClose]; } if (rd.Value[StockLow] > x1) rd.Value[StockLow] = x1; if (rd.Value[StockHigh] < x2) rd.Value[StockHigh] = x2; rd.IsAlternate = (rd.Value[StockOpen] > rd.Value[StockClose]); RenderHStockBoxWhisker(g, rd, rd.Value[StockLow], x1, y, HiLoBarSegment.LowWhisker); RenderHStockBoxWhisker(g, rd, x2, rd.Value[StockHigh], y, HiLoBarSegment.HighWhisker); RenderHStockBoxOpenClose(g, rd, x1, x2, y); } else { int x = (x1 != int.MinValue) ? x1 : x2; if (x != int.MinValue) { if (x > rd.Value[StockHigh]) rd.Value[StockHigh] = x; if (x < rd.Value[StockLow]) rd.Value[StockLow] = x; } if (x < rd.Value[StockHigh] && x > rd.Value[StockLow]) { RenderHStockBoxWhisker(g, rd, x, rd.Value[StockHigh], y, HiLoBarSegment.HighWhisker); RenderHStockBoxWhisker(g, rd, rd.Value[StockLow], x, y, HiLoBarSegment.LowWhisker); RenderHStockBoxOpenClose(g, rd, x, x, y); } else { RenderHStockBoxWhisker(g, rd, rd.Value[StockLow], rd.Value[StockHigh], y, HiLoBarSegment.CenterLine); if (x != int.MinValue) RenderHStockBoxOpenClose(g, rd, x, x, y); } } } #region RenderHStockBoxWhisker private void RenderHStockBoxWhisker(Graphics g, HiLoRenderData rd, int x1, int x2, int y, HiLoBarSegment segment) { if (x2 > x1) { Point pt1 = new Point(x1, y); Point pt2 = new Point(x2 + 1, y); RenderBoxWhisker(g, rd, pt1, pt2, segment); } } #endregion #region RenderHStockBoxOpenClose private void RenderHStockBoxOpenClose( Graphics g, HiLoRenderData rd, int x1, int x2, int y) { if (x2 == x1) { x1--; x2++; } x2++; Point pt1 = new Point(x1, y - BarWidth / 2); Point pt2 = new Point(x2, pt1.Y + BarWidth); int lw = RenderStockBox(g, rd, pt1, pt2); Rectangle r = new Rectangle(pt1.X, pt1.Y, pt2.X - pt1.X, pt2.Y - pt1.Y); if (r.Width > 0 && r.Height > 0) { if (GetBarShading(rd.ChartXy) == true) { ChartControl chartControl = ChartControl; if (chartControl.DoPreRenderSeriesHiloBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, HiLoBarSegment.BarShading) == false) { RenderHBarShading(g, r, r, BarSegment.Left); chartControl.DoPostRenderSeriesHiLoBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, HiLoBarSegment.BarShading); } } } } #endregion #endregion #region RenderHStockBoxMedian private void RenderHStockBoxMedian( Graphics g, HiLoRenderData rd, int y, int x1, int x2) { if (rd.Value.Length > StockMedian) { int x3 = rd.Value[StockMedian]; if (x3 > x1 && x3 < x2) { Point pt1 = new Point(x3, y); Point pt2 = new Point(x3, y + BarWidth - 1); ChartControl chartControl = ChartControl; if (chartControl.DoPreRenderSeriesHiloBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, HiLoBarSegment.MedianLine) == false) { ChartLineVisualStyle lstyle = GetSegLineStyle(rd, HiLoBarSegment.MedianLine); if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; if (lstyle.LineWidth > 1) pt2.Y++; g.DrawLine(pen, pt1, pt2); } } chartControl.DoPostRenderSeriesHiLoBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, HiLoBarSegment.MedianLine); } } } } #endregion #region RenderHStockHiLo private void RenderHStockHiLo(Graphics g, HiLoRenderData rd, int y) { int x1, x2, x3, x4; NormalizeHiLoValues(rd, out x1, out x2, out x3, out x4); ChartLineVisualStyle ostyle, cstyle; NormalizeHiLoStyles(rd, out ostyle, out cstyle); if (rd.Value[StockOpen] != int.MinValue) { Point pt1 = new Point(x2, y - BarWidth / 2); Point pt2 = new Point(pt1.X, pt1.Y + BarWidth / 2); RenderHiLoWhisker(g, rd, pt1, pt2, ostyle, HiLoBarSegment.OpenWhisker); } if (rd.Value[StockClose] != int.MinValue) { Point pt1 = new Point(x3, y); Point pt2 = new Point(pt1.X, pt1.Y + BarWidth / 2 + 1); RenderHiLoWhisker(g, rd, pt1, pt2, cstyle, HiLoBarSegment.CloseWhisker); } if (rd.IsAlternate == false) { int x = x2; x2 = x3; x3 = x; ChartLineVisualStyle style = ostyle; ostyle = cstyle; cstyle = ostyle; } if ((rd.IsAlternate == false && _RenderFullDefRange == true) || (rd.IsAlternate == true && _RenderFullAltRange == true)) { RenderHiLoRange(g, rd, new Point(x1, y), new Point(x4, y), HiLoBarSegment.FullRange); } else { // Open value either not specified or is // set to High value. if (x1 == x2 && x3 != x4) x2 = x3; if (x2 < x1) { int n = (ostyle != null) ? (ostyle.LineWidth + 1) / 2 : 1; RenderHiLoRange(g, rd, new Point(x1, y), new Point(x2 + n, y), HiLoBarSegment.HighWhisker); } if (x3 > x4) { int n = 1; // Low segment extends to the top. if (x3 == x1) n = (cstyle.LineWidth + 1) / 2; // We have a Center segment. else if (x3 != x2) n = -cstyle.LineWidth / 2; RenderHiLoRange(g, rd, new Point(x3 + n, y), new Point(x4, y), HiLoBarSegment.LowWhisker); } if (x2 > x3 || (x1 == x2 && x3 == x4)) { ChartLineVisualStyle y2Style = (x2 == rd.Value[StockOpen]) ? ostyle : cstyle; ChartLineVisualStyle y3Style = (x3 == rd.Value[StockOpen]) ? ostyle : cstyle; if (y2Style != null) x2 += ((y2Style.LineWidth + 1) / 2); if (y3Style != null) x3 -= (y3Style.LineWidth / 2); RenderHiLoRange(g, rd, new Point(x2, y), new Point(x3, y), HiLoBarSegment.CenterLine); } } } #endregion #endregion #endregion #region RenderVStockPlot private void RenderVStockPlot(ChartRenderInfo renderInfo, ChartXy chartXy, SortedSeriesPoints ssp, ChartSeriesVisualStyle sstyle) { HiLoRenderData rd = new HiLoRenderData(chartXy, AxisY ?? chartXy.AxisY); rd.SeriesStyle = sstyle; for (int i = 0; i < ssp.Count; i++) { SeriesPoint sp = ssp[i]; if (sp.Visible == true) { if (sp.ValueY.Length > 0) { rd.Sp = sp; rd.Spt = sp.Point[0]; rd.Index = i; rd.IsAlternate = false; RenderVStock(renderInfo, rd); } } } } #region RenderVStock private void RenderVStock(ChartRenderInfo renderInfo, HiLoRenderData rd) { Graphics g = renderInfo.Graphics; rd.Value = GetVStockValues(rd.ChartXy, rd.Sp); if (rd.Value[StockHigh] != int.MinValue) { Point pt = rd.ChartXy.GetDataPointEx(this, rd.Sp, 0); Rectangle r = GetVBoundingRect(rd, pt); if (r.IntersectsWith(RenderBounds) == true) { int x = pt.X + BarOffset; rd.Sp.PointSize = new Size(BarWidth / 3, 5); switch (HiLoBarType) { case HiLoBarType.Box: case HiLoBarType.Candle: RenderVStockBox(g, rd, x); break; default: RenderVStockHiLo(g, rd, x); break; } } } } #region GetVBoundingRect private Rectangle GetVBoundingRect(HiLoRenderData rd, Point pt) { int y1 = rd.Value[StockHigh]; int y2 = rd.Value[StockLow]; if (rd.Value[StockOpen] != int.MinValue) { if (y1 > rd.Value[StockOpen]) y1 = rd.Value[StockOpen]; if (y2 < rd.Value[StockOpen]) y2 = rd.Value[StockOpen]; } if (rd.Value[StockClose] != int.MinValue) { if (y1 > rd.Value[StockClose]) y1 = rd.Value[StockClose]; if (y2 < rd.Value[StockClose]) y2 = rd.Value[StockClose]; } int x = pt.X + BarOffset - BarWidth / 2; return (new Rectangle(x, y1, BarWidth, y2 - y1)); } #endregion #region RenderVStockBox private void RenderVStockBox(Graphics g, HiLoRenderData rd, int x) { int y1 = rd.Value[StockOpen]; int y2 = rd.Value[StockClose]; if (rd.Value[StockOpen] != int.MinValue && rd.Value[StockClose] != int.MinValue) { if (rd.Value[StockOpen] > rd.Value[StockClose]) { y1 = rd.Value[StockClose]; y2 = rd.Value[StockOpen]; } if (rd.Value[StockHigh] > y1) rd.Value[StockHigh] = y1; if (rd.Value[StockLow] < y2) rd.Value[StockLow] = y2; rd.IsAlternate = (rd.Value[StockOpen] < rd.Value[StockClose]); RenderVStockBoxWhisker(g, rd, x, rd.Value[StockHigh], y1, HiLoBarSegment.HighWhisker); RenderVStockBoxWhisker(g, rd, x, y2, rd.Value[StockLow], HiLoBarSegment.LowWhisker); RenderVStockBoxOpenClose(g, rd, x, y1, y2); } else { int y = (y1 != int.MinValue) ? y1 : y2; if (y != int.MinValue) { if (y < rd.Value[StockHigh]) rd.Value[StockHigh] = y; if (y > rd.Value[StockLow]) rd.Value[StockLow] = y; } if (y > rd.Value[StockHigh] && y < rd.Value[StockLow]) { RenderVStockBoxWhisker(g, rd, x, rd.Value[StockHigh], y, HiLoBarSegment.HighWhisker); RenderVStockBoxWhisker(g, rd, x, y, rd.Value[StockLow], HiLoBarSegment.LowWhisker); RenderVStockBoxOpenClose(g, rd, x, y, y); } else { RenderVStockBoxWhisker(g, rd, x, rd.Value[StockHigh], rd.Value[StockLow], HiLoBarSegment.CenterLine); if (y != int.MinValue) RenderVStockBoxOpenClose(g, rd, x, y, y); } } } #region RenderVStockBoxWhisker private void RenderVStockBoxWhisker(Graphics g, HiLoRenderData rd, int x, int y1, int y2, HiLoBarSegment segment) { if (y2 > y1) { Point pt1 = new Point(x, y1); Point pt2 = new Point(x, y2 + 1); RenderBoxWhisker(g, rd, pt1, pt2, segment); } } #endregion #region RenderVStockBoxOpenClose private void RenderVStockBoxOpenClose( Graphics g, HiLoRenderData rd, int x, int y1, int y2) { if (y2 == y1) { y1--; y2++; } y2++; Point pt1 = new Point(x - BarWidth / 2, y1); Point pt2 = new Point(pt1.X + BarWidth, y2); int lw = RenderStockBox(g, rd, pt1, pt2); Rectangle r = new Rectangle(pt1.X, pt1.Y, pt2.X - pt1.X, pt2.Y - pt1.Y); if (r.Width > 0 && r.Height > 0) { if (GetBarShading(rd.ChartXy) == true) { ChartControl chartControl = ChartControl; if (chartControl.DoPreRenderSeriesHiloBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, HiLoBarSegment.BarShading) == false) { RenderVBarShading(g, r, r, BarSegment.Top); chartControl.DoPostRenderSeriesHiLoBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, HiLoBarSegment.BarShading); } } } } #endregion #endregion #region RenderVStockBoxMedian private void RenderVStockBoxMedian( Graphics g, HiLoRenderData rd, int x, int y1, int y2) { if (rd.Value.Length > StockMedian) { int y3 = rd.Value[StockMedian]; if (y3 > y1 && y3 < y2) { Point pt1 = new Point(x, y3); Point pt2 = new Point(x + BarWidth - 1, y3); ChartControl chartControl = ChartControl; if (chartControl.DoPreRenderSeriesHiloBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, HiLoBarSegment.MedianLine) == false) { ChartLineVisualStyle lstyle = GetSegLineStyle(rd, HiLoBarSegment.MedianLine); if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, lstyle.LineWidth)) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; if (lstyle.LineWidth > 1) pt2.X++; g.DrawLine(pen, pt1, pt2); } } chartControl.DoPostRenderSeriesHiLoBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, HiLoBarSegment.MedianLine); } } } } #endregion #region RenderVStockHiLo private void RenderVStockHiLo(Graphics g, HiLoRenderData rd, int x) { int y1, y2, y3, y4; NormalizeHiLoValues(rd, out y1, out y2, out y3, out y4); ChartLineVisualStyle ostyle, cstyle; NormalizeHiLoStyles(rd, out ostyle, out cstyle); if (rd.Value[StockOpen] != int.MinValue) { Point pt1 = new Point(x - BarWidth / 2, y2); Point pt2 = new Point(pt1.X + BarWidth / 2, pt1.Y); RenderHiLoWhisker(g, rd, pt1, pt2, ostyle, HiLoBarSegment.OpenWhisker); } if (rd.Value[StockClose] != int.MinValue) { Point pt1 = new Point(x + 1, y3); Point pt2 = new Point(pt1.X + BarWidth / 2, pt1.Y); RenderHiLoWhisker(g, rd, pt1, pt2, cstyle, HiLoBarSegment.CloseWhisker); } NormalizeHiLoDir(rd, ref y2, ref y3, ref ostyle, ref cstyle); if ((rd.IsAlternate == false && _RenderFullDefRange == true) || (rd.IsAlternate == true && _RenderFullAltRange == true)) { RenderHiLoRange(g, rd, new Point(x, y1), new Point(x, y4), HiLoBarSegment.FullRange); } else { if (y1 == y2 && y3 != y4) y2 = y3; // High segment if (y2 > y1) { int n = (ostyle != null) ? ostyle.LineWidth / 2 : 0; RenderHiLoRange(g, rd, new Point(x, y1), new Point(x, y2 - n), HiLoBarSegment.HighWhisker); } // Low segment if (y3 < y4) { int n = 0; if (y3 == y1) n = -cstyle.LineWidth / 2; else if (y3 != y2) n = (cstyle.LineWidth + 1) / 2; RenderHiLoRange(g, rd, new Point(x, y3 + n), new Point(x, y4), HiLoBarSegment.LowWhisker); } // Center segment. if (y2 < y3 || (y1 == y2 && y3 == y4)) { ChartLineVisualStyle y2Style = (y2 == rd.Value[StockOpen]) ? ostyle : cstyle; ChartLineVisualStyle y3Style = (y3 == rd.Value[StockOpen]) ? ostyle : cstyle; if (y2Style != null) y2 -= (y2Style.LineWidth / 2); if (y3Style != null) y3 += ((y3Style.LineWidth + 1) / 2); RenderHiLoRange(g, rd, new Point(x, y2), new Point(x, y3), HiLoBarSegment.CenterLine); } } } #endregion #endregion #endregion #region GetHStockValues internal int[] GetHStockValues(ChartXy chartXy, SeriesPoint sp) { ChartAxis axis = AxisX ?? chartXy.AxisX; int[] values = new int[Math.Max(4, sp.ValueY.Length)]; for (int i = 0; i < sp.ValueY.Length; i++) values[i] = chartXy.GetDataPointX(axis, sp.ValueY[i]); NormalizeStockValues(sp, values); return (values); } #endregion #region GetVStockValues internal int[] GetVStockValues(ChartXy chartXy, SeriesPoint sp) { ChartAxis axis = AxisY ?? chartXy.AxisY; int[] values = new int[Math.Max(4, sp.ValueY.Length)]; for (int i = 0; i < sp.ValueY.Length; i++) values[i] = chartXy.GetDataPointY(axis, sp.ValueY[i]); NormalizeStockValues(sp, values); return (values); } #endregion #region NormalizeStockValues private void NormalizeStockValues(SeriesPoint sp, int[] values) { for (int i = sp.ValueY.Length; i < values.Length; i++) values[i] = int.MinValue; if (values[StockLow] == int.MinValue) values[StockLow] = values[StockHigh]; if ((IsRotated == true && values[StockLow] > values[StockHigh]) || (IsRotated == false && values[StockLow] < values[StockHigh])) { int temp = values[StockLow]; values[StockLow] = values[StockHigh]; values[StockHigh] = temp; } } #endregion #region NormalizeHiLoValues private void NormalizeHiLoValues( HiLoRenderData rd, out int v1, out int v2, out int v3, out int v4) { v1 = rd.Value[StockHigh]; v4 = rd.Value[StockLow]; v2 = (rd.Value[StockOpen] != int.MinValue) ? rd.Value[StockOpen] : v1; v3 = (rd.Value[StockClose] != int.MinValue) ? rd.Value[StockClose] : v4; if (v1 > v4) { if (v1 < v2) v1 = v2; if (v4 > v3) v4 = v3; rd.IsAlternate = (v2 > v3); } else { if (v1 > v2) v1 = v2; if (v4 < v3) v4 = v3; rd.IsAlternate = (v2 < v3); } } #endregion #region NormalizeHiLoDir private void NormalizeHiLoDir(HiLoRenderData rd, ref int v1, ref int v2, ref ChartLineVisualStyle style1, ref ChartLineVisualStyle style2) { if (rd.IsAlternate == false) { int y = v1; v1 = v2; v2 = y; ChartLineVisualStyle style = style1; style1 = style2; style2 = style1; } } #endregion #region NormalizeHiLoStyles private void NormalizeHiLoStyles(HiLoRenderData rd, out ChartLineVisualStyle ostyle, out ChartLineVisualStyle cstyle) { ostyle = (rd.Value[StockOpen] != int.MinValue) ? GetSegLineStyle(rd, HiLoBarSegment.OpenWhisker) : null; cstyle = (rd.Value[StockClose] != int.MinValue) ? GetSegLineStyle(rd, HiLoBarSegment.CloseWhisker) : null; rd.EndDelta = GetHiLoEndDelta(ostyle, cstyle); } #region GetHiLoEndDelta private int GetHiLoEndDelta( ChartLineVisualStyle ostyle, ChartLineVisualStyle cstyle) { int delta = 0; if (ostyle != null) { if (ostyle.LineWidth > 1) { if (ostyle.LinePattern != LinePattern.None) delta = (ostyle.LineWidth + 1) / 2; } } if (cstyle != null) { if (cstyle.LineWidth > 1) { if (cstyle.LinePattern != LinePattern.None) delta = Math.Max(delta, (cstyle.LineWidth + 1) / 2); } } return (delta); } #endregion #endregion #region RenderBoxWhisker private void RenderBoxWhisker(Graphics g, HiLoRenderData rd, Point pt1, Point pt2, HiLoBarSegment segment) { ChartXy chartXy = rd.ChartXy; ChartControl chartControl = ChartControl; SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.None; if (chartControl.DoPreRenderSeriesHiloBarEvent(g, chartXy, this, rd, pt1, pt2, segment) == false) { ChartLineVisualStyle lstyle = GetSegLineStyle(rd, segment); if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; Point pt3 = pt2; if (lstyle.LineWidth == 1) { if (pt1.X == pt2.X) pt3.Y--; else pt3.X--; } g.DrawLine(pen, pt1, pt3); } } chartControl.DoPostRenderSeriesHiLoBarEvent(g, chartXy, this, rd, pt1, pt2, segment); } if (rd.SeriesStyle.HiLoBarVisualStyle.ShowWhiskerCaps == Tbool.True) RenderWhiskerCap(g, rd, pt1, pt2, segment); g.SmoothingMode = sm; } #region RenderWhiskerCap private void RenderWhiskerCap(Graphics g, HiLoRenderData rd, Point pt1, Point pt2, HiLoBarSegment segment) { if (segment == HiLoBarSegment.HighWhisker || segment == HiLoBarSegment.LowWhisker) { HiLoBarSegment capSegment = (segment == HiLoBarSegment.HighWhisker) ? HiLoBarSegment.HighWhiskerCap : HiLoBarSegment.LowWhiskerCap; GetWhiskerCapPoints(segment, ref pt1, ref pt2); ChartControl chartControl = ChartControl; if (chartControl.DoPreRenderSeriesHiloBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, capSegment) == false) { ChartLineVisualStyle lstyle = GetSegLineStyle(rd, capSegment); if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, lstyle.LineWidth)) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; if (lstyle.LineWidth == 1) { if (pt1.X == pt2.X) pt2.Y--; else pt2.X--; } g.DrawLine(pen, pt1, pt2); } } chartControl.DoPostRenderSeriesHiLoBarEvent( g, rd.ChartXy, this, rd, pt1, pt2, capSegment); } } } #region GetWhiskerCapPoints private void GetWhiskerCapPoints( HiLoBarSegment segment, ref Point pt1, ref Point pt2) { int n = BarWidth / 3; switch (segment) { case HiLoBarSegment.HighWhisker: if (pt1.X == pt2.X) { pt1.X -= n; pt2.X += n + 1; pt2.Y = pt1.Y; } else { pt1.Y -= n; pt2.Y += n + 1; pt1.X = pt2.X; } break; case HiLoBarSegment.LowWhisker: if (pt1.X == pt2.X) { pt1.X -= n; pt2.X += n + 1; pt1.Y = pt2.Y; } else { pt1.Y -= n; pt2.Y += n + 1; pt2.X = pt1.X; } break; } } #endregion #endregion #endregion #region RenderStockBox private int RenderStockBox( Graphics g, HiLoRenderData rd, Point pt1, Point pt2) { int lineWidth = 0; Rectangle r = new Rectangle(pt1.X, pt1.Y, pt2.X - pt1.X, pt2.Y - pt1.Y); if (r.Width > 0 && r.Height > 0) { ChartXy chartXy = rd.ChartXy; ChartControl chartControl = ChartControl; SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.None; if (chartControl.DoPreRenderSeriesHiloBarEvent( g, chartXy, this, rd, pt1, pt2, HiLoBarSegment.Box) == false) { if (HiLoBarType == HiLoBarType.Box) RenderStockBoxBackground(g, rd, r); else RenderStockCandleBackground(g, rd, r); ChartLineVisualStyle lstyle = rd.DefaultStyle.BoxBorder; if (CanUseAlternateSegmentStyle(rd) == true) { if (rd.IsAlternate == true && rd.AlternateStyle.BoxBorder.IsEmpty == false) lstyle = rd.AlternateStyle.BoxBorder; } if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { lineWidth = (int)pen.Width; if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; if (pt1.X == pt2.X || pt1.Y == pt2.Y) { g.DrawLine(pen, pt1, pt2); } else { pen.Alignment = PenAlignment.Inset; if (lstyle.LineWidth == 1) { r.Width--; r.Height--; } if (r.Width > 0 && r.Height > 0) g.DrawRectangle(pen, r); } } } chartControl.DoPostRenderSeriesHiLoBarEvent( g, chartXy, this, rd, pt1, pt2, HiLoBarSegment.Box); } if (ShowHiLoBarMedianLines == true) { if (IsRotated == false) RenderVStockBoxMedian(g, rd, r.X, r.Y, r.Bottom); else RenderHStockBoxMedian(g, rd, r.Y, r.X, r.Right); } g.SmoothingMode = sm; } return (lineWidth); } #region RenderStockCandleBackground private void RenderStockCandleBackground( Graphics g, HiLoRenderData rd, Rectangle r) { Background bk = GetBoxBackground(rd, rd.AlternateStyle.BoxBackground, rd.DefaultStyle.BoxBackground); if (bk.IsEmpty == false) { using (Brush br = bk.GetBrush(r)) g.FillRectangle(br, r); } } #endregion #region RenderStockBoxBackground private void RenderStockBoxBackground( Graphics g, HiLoRenderData rd, Rectangle r) { Background bkDef = rd.DefaultStyle.BoxBackground; Background bkAlt = rd.AlternateStyle.BoxBackground; if (bkAlt.IsEmpty == true) bkAlt = bkDef; if (rd.IsAlternate == true) { Background bkSave = bkDef; bkDef = bkAlt; bkAlt = bkSave; } if ((ShowHiLoBarMedianLines == true) && (rd.Value.Length > StockMedian)) { if (bkAlt.IsEmpty == false) { if (IsRotated == false) r = RenderVBox(g, rd.Value[StockMedian], bkAlt, r); else r = RenderHBox(g, rd.Value[StockMedian], bkAlt, r); } } if (r.Width > 0 && r.Height > 0) { if (bkDef.IsEmpty == false) { using (Brush br = bkDef.GetBrush(r)) g.FillRectangle(br, r); } } } #region RenderVBox private Rectangle RenderVBox(Graphics g, int y, Background bk, Rectangle r) { if ((y > r.Y && y < r.Bottom) && bk.IsEmpty == false) { int ry = r.Y; r.Height = r.Bottom - y; r.Y = y; using (Brush br = bk.GetBrush(r)) g.FillRectangle(br, r); r.Y = ry; r.Height = y - ry; } return (r); } #endregion #region RenderHBox private Rectangle RenderHBox(Graphics g, int x, Background bk, Rectangle r) { if (x > r.X && x < r.Right) { int rw = r.Width; r.Width = x - r.X; using (Brush br = bk.GetBrush(r)) g.FillRectangle(br, r); r.X = r.Right; r.Width = rw - r.Width; } return (r); } #endregion #endregion #endregion #region RenderHiLoWhisker private ChartLineVisualStyle RenderHiLoWhisker(Graphics g, HiLoRenderData rd, Point pt1, Point pt2, ChartLineVisualStyle style, HiLoBarSegment segment) { ChartXy chartXy = rd.ChartXy; ChartControl chartControl = ChartControl; SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.None; if (chartControl.DoPreRenderSeriesHiloBarEvent(g, chartXy, this, rd, pt1, pt2, segment) == false) { if (style.LinePattern != LinePattern.None) { using (Pen pen = new Pen(style.LineColor, Dpi.Width(style.LineWidth))) { if (style.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)style.LinePattern; if (style.LineWidth == 1) { if (pt1.X == pt2.X) pt2.Y--; else pt2.X--; } g.DrawLine(pen, pt1, pt2); } } chartControl.DoPostRenderSeriesHiLoBarEvent(g, chartXy, this, rd, pt1, pt2, segment); } g.SmoothingMode = sm; return (style); } #endregion #region RenderHiLoRange private void RenderHiLoRange( Graphics g, HiLoRenderData rd, Point pt1, Point pt2, HiLoBarSegment segment) { ChartXy chartXy = rd.ChartXy; ChartControl chartControl = ChartControl; if (pt1.X == pt2.X) { if (segment == HiLoBarSegment.HighWhisker || segment == HiLoBarSegment.FullRange) pt1.Y -= rd.EndDelta; if (segment == HiLoBarSegment.LowWhisker || segment == HiLoBarSegment.FullRange) pt2.Y += rd.EndDelta; } else { if (segment == HiLoBarSegment.LowWhisker || segment == HiLoBarSegment.FullRange) pt2.X -= rd.EndDelta; if (segment == HiLoBarSegment.HighWhisker || segment == HiLoBarSegment.FullRange) pt1.X += rd.EndDelta; } SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.None; if (chartControl.DoPreRenderSeriesHiloBarEvent(g, chartXy, this, rd, pt1, pt2, segment) == false) { ChartLineVisualStyle lstyle = GetSegLineStyle(rd, segment); if (lstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth))) { if (lstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)lstyle.LinePattern; g.DrawLine(pen, pt1, pt2); } } } if (ShowHiLoBarMedianLines == true) { if (segment == HiLoBarSegment.CenterLine || segment == HiLoBarSegment.FullRange) { if (IsRotated == false) RenderVStockBoxMedian(g, rd, pt1.X - BarWidth / 2, pt1.Y, pt2.Y); else RenderHStockBoxMedian(g, rd, pt1.Y - BarWidth / 2, pt2.X, pt1.X); } } chartControl.DoPostRenderSeriesHiLoBarEvent(g, chartXy, this, rd, pt1, pt2, segment); g.SmoothingMode = sm; } #endregion #region GetSegLineStyle private ChartLineVisualStyle GetSegLineStyle(HiLoRenderData rd, HiLoBarSegment segment) { ChartLineVisualStyle style = rd.DefaultStyle.Default; if (CanUseAlternateSegmentStyle(rd) == true) { if (rd.IsAlternate == true && rd.AlternateStyle.Default.IsEmpty == false) style = rd.AlternateStyle.Default; } switch (segment) { case HiLoBarSegment.FullRange: break; case HiLoBarSegment.Box: if (rd.IsAlternate == true && rd.AlternateStyle.BoxBorder.IsEmpty == false) { style = rd.AlternateStyle.BoxBorder; } else { if (rd.DefaultStyle.BoxBorder.IsEmpty == false) style = rd.DefaultStyle.BoxBorder; } break; case HiLoBarSegment.MedianLine: if (rd.IsAlternate == true && rd.AlternateStyle.MedianLine.IsEmpty == false) { style = rd.AlternateStyle.MedianLine; } else { if (rd.DefaultStyle.MedianLine.IsEmpty == false) style = rd.DefaultStyle.MedianLine; } break; case HiLoBarSegment.HighWhiskerCap: if (rd.IsAlternate == true && rd.AlternateStyle.HighWhiskerCap.IsEmpty == false) { style = rd.AlternateStyle.HighWhiskerCap; } else { if (rd.DefaultStyle.HighWhiskerCap.IsEmpty == false) style = rd.DefaultStyle.HighWhiskerCap; } break; case HiLoBarSegment.LowWhiskerCap: if (rd.IsAlternate == true && rd.AlternateStyle.LowWhiskerCap.IsEmpty == false) { style = rd.AlternateStyle.LowWhiskerCap; } else { if (rd.DefaultStyle.LowWhiskerCap.IsEmpty == false) style = rd.DefaultStyle.LowWhiskerCap; } break; case HiLoBarSegment.HighWhisker: if (rd.IsAlternate == true && rd.AlternateStyle.HighWhisker.IsEmpty == false) { style = rd.AlternateStyle.HighWhisker; } else { if (rd.DefaultStyle.HighWhisker.IsEmpty == false) style = rd.DefaultStyle.HighWhisker; } break; case HiLoBarSegment.LowWhisker: if (rd.IsAlternate == true && rd.AlternateStyle.LowWhisker.IsEmpty == false) { style = rd.AlternateStyle.LowWhisker; } else { if (rd.DefaultStyle.LowWhisker.IsEmpty == false) style = rd.DefaultStyle.LowWhisker; } break; case HiLoBarSegment.OpenWhisker: if (rd.IsAlternate == true && rd.AlternateStyle.OpenWhisker.IsEmpty == false) { style = rd.AlternateStyle.OpenWhisker; } else { if (rd.DefaultStyle.OpenWhisker.IsEmpty == false) style = rd.DefaultStyle.OpenWhisker; } break; case HiLoBarSegment.CloseWhisker: if (rd.IsAlternate == true && rd.AlternateStyle.CloseWhisker.IsEmpty == false) { style = rd.AlternateStyle.CloseWhisker; } else { if (rd.DefaultStyle.CloseWhisker.IsEmpty == false) style = rd.DefaultStyle.CloseWhisker; } break; case HiLoBarSegment.CenterLine: if (rd.IsAlternate == true && rd.AlternateStyle.CenterLine.IsEmpty == false) { style = rd.AlternateStyle.CenterLine; } else { if (rd.DefaultStyle.CenterLine.IsEmpty == false) style = rd.DefaultStyle.CenterLine; } break; } return (style); } #region CanUseAlternateSegmentStyle private bool CanUseAlternateSegmentStyle(HiLoRenderData rd) { Tbool uas = rd.SeriesStyle.HiLoBarVisualStyle.UseAlternateSegmentStyle; if (uas == Tbool.NotSet) return (HiLoBarType == HiLoBarType.Candle); return (uas == Tbool.True); } #endregion #endregion #region GetBoxBackground private Background GetBoxBackground(HiLoRenderData rd, Background abk, Background sbk) { if (rd.IsAlternate == true && abk.IsEmpty == false) return (abk); return (sbk); } #endregion #endregion #region HighLightPoints private bool HighLightPoints(ChartXy chartXy) { if (chartXy.ChartCrosshair.Visible == false) return (false); if (CrosshairHighlightPoints != Tbool.NotSet) return (CrosshairHighlightPoints == Tbool.True); return (chartXy.ChartCrosshair.HighlightPoints); } #endregion #region HighLightSinglePoint private bool HighLightSinglePoint(ChartXy chartXy) { if (chartXy.ChartCrosshair.Visible == false) return (false); if (CrosshairHighlightSinglePoint != Tbool.NotSet) return (CrosshairHighlightSinglePoint == Tbool.True); return (chartXy.ChartCrosshair.HighlightSinglePoint); } #endregion #region GetHighlightStyle private PointMarkerVisualStyle GetHighlightStyle( ChartXy chartXy, ChartSeriesVisualStyle sstyle) { if (HighLightPoints(chartXy) == true) { PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle; PointMarkerVisualStyle hstyle = pstyle.Copy(); if (sstyle.MarkerHighlightVisualStyle.IsEmpty == false) { hstyle.ApplyStyle(sstyle.MarkerHighlightVisualStyle); } else { Size size = hstyle.Size; size.Width += 4; size.Height += 4; hstyle.Size = size; } return (hstyle); } return (null); } #endregion #region GetPointMarkerImage private Image GetPointMarkerImage( Graphics g, ChartXy chartXy, PointMarkerVisualStyle style) { Image image = PointMarkerImage; if (image == null) { image = chartXy.GetPointMarker(g, style); PointMarkerImage = image; } return (image); } #endregion #region GetHighlightImage private Image GetHighlightImage( Graphics g, ChartXy chartXy, PointMarkerVisualStyle style) { Image image = PointMarkerHighlightImage; if (image == null) { image = chartXy.GetPointMarker(g, style); PointMarkerHighlightImage = image; } return (image); } #endregion #region GetEmptyMarkerImage private Image GetEmptyMarkerImage( Graphics g, ChartXy chartXy, PointMarkerVisualStyle style) { Image image = PointMarkerEmptyImage; if (image == null) { image = chartXy.GetPointMarker(g, style); PointMarkerEmptyImage = image; } return (image); } #endregion #region GatherSeriesPoints private PointData GatherSeriesPoints( ChartXy chartXy, SortedSeriesPoints ssp, int index, int count, bool allArgs) { if (_PointData == null) _PointData = GatherSeriesPointsEx(chartXy, ssp, index, count, allArgs); return (_PointData); } private PointData GatherSeriesPointsEx( ChartXy chartXy, SortedSeriesPoints ssp, int index, int count, bool allArgs) { PointData pd = new PointData(); pd.Points = new List(); pd.SeriesPoints = new List(); if (EnableEmptyValues == true) { PointData epd = new PointData(); epd.Points = new List(); epd.SeriesPoints = new List(); int n = 0; bool empty = false; for (int i = 0; i < count; i++) { if (ssp[index + i].IsEmpty != empty) { int cnt = i - n; if (cnt > 0) GetPointList(chartXy, ssp, index + n, cnt, allArgs, empty ? epd : pd); empty = !empty; n = i; } } if (n < count) GetPointList(chartXy, ssp, index + n, count - n, allArgs, empty ? epd : pd); _EmptyPointData = epd; } else { GetPointList(chartXy, ssp, index, count, allArgs, pd); } return (pd); } #endregion #region GetPointList private void GetPointList(ChartXy chartXy, SortedSeriesPoints ssp, int index, int cnt, bool allArgs, PointData pd) { GetPointList(chartXy, ssp, index, cnt, 0, 0, allArgs, pd); } private void GetPointList(ChartXy chartXy, SortedSeriesPoints ssp, int index, int cnt, int skip, int minDistance, bool allArgs, PointData pd) { if (cnt > 0) { Stack stack = new Stack(); skip++; Point lpt = new Point(-5000, -5000); if (allArgs == false) { if (cnt > skip && skip > 1) cnt = (cnt + skip - 1) / skip; for (int i = 0; i < cnt; i++) { int n = index + (i * skip); if (n >= ssp.Count) break; SeriesPoint sp = ssp[n]; if (sp.Visible == true) { Point pt = chartXy.GetDataPointEx(this, sp, 0); if (minDistance <= 0 || DataPointDistanceOk(lpt, pt, minDistance) == true) { stack.Push(sp); stack.Push(pt); lpt = pt; } } } } else { int n = 0; for (int i = 0; i < cnt; i++) n += ssp[index + i].ValueY.Length; n /= (n + skip - 1) / skip; int m = 0; for (int i = 0; i < cnt; i++) { SeriesPoint sp = ssp[index + i]; for (int j = 0; j < sp.ValueY.Length; j++) { if (m % skip == 0) { int w = m / skip; Point pt = chartXy.GetDataPointNa(this, sp, j); if (minDistance <= 0 || DataPointDistanceOk(lpt, pt, minDistance) == true) { stack.Push(sp); stack.Push(pt); lpt = pt; } } m++; } } } if (stack.Count > 0) { int n = stack.Count / 2; Point[] points = new Point[n]; SeriesPoint[] seriesPoints = new SeriesPoint[n]; for (int i = n - 1; i >= 0; i--) { points[i] = (Point)stack.Pop(); seriesPoints[i] = (SeriesPoint)stack.Pop(); } pd.Points.Add(points); pd.SeriesPoints.Add(seriesPoints); } } } #region DataPointDistanceOk private bool DataPointDistanceOk(Point lpt, Point pt, int minDistance) { int dx = (lpt.X - pt.X); int dy = (lpt.Y - pt.Y); int h = (int)MathHelper.Sqrt(dx * dx + dy * dy); return (h >= minDistance); } #endregion #endregion #endregion #region Render internal override void Render(ChartRenderInfo renderInfo) { if (Displayed == true) { Rectangle bounds = BoundsRelative; if (renderInfo.ClipRectangle.IntersectsWith(bounds)) RenderOverride(renderInfo); } } #endregion #region RenderIndicators internal void RenderIndicators(ChartRenderInfo renderInfo, bool onTop) { if (SeriesType != SeriesType.HorizontalDot || SeriesType != SeriesType.VerticalDot) { if (SeriesPoints.Count > 0) { Graphics g = renderInfo.Graphics; ChartXy chartXy = Parent as ChartXy; ChartSeriesVisualStyle sstyle = EffectiveChartSeriesStyle; SortedSeriesPoints ssp = GetSortedSeriesPoints(chartXy); foreach (ChartIndicator indicator in ChartIndicators) { if (indicator.DisplayOnTop == onTop) { if (indicator.IsDisplayed == true) { ssp.SlopeIndex = indicator.ValueYIndex; switch (indicator.IndicatorType) { case ChartIndicatorType.RegressionLine: RenderRegressionLine(g, chartXy, ssp, (RegressionLine)indicator); break; case ChartIndicatorType.TrendLine: RenderTrendLine(g, chartXy, ssp, (TrendLine)indicator); break; } } } } } } } #region RenderRegressionLine private void RenderRegressionLine(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, RegressionLine regline) { double m = regline.Slope; double b = regline.Intercept; if (m.Equals(double.NaN) == false && b.Equals(double.NaN) == false) { ChartAxis axis = AxisX ?? chartXy.AxisX; double x1, x2; switch (ActualScaleTypeX) { case ScaleType.DateTime: x1 = chartXy.GetDateTimePointValue(axis, axis.TickmarkLayout, (DateTime)MinValueX); x2 = chartXy.GetDateTimePointValue(axis, axis.TickmarkLayout, (DateTime)MaxValueX); break; default: x1 = Convert.ToDouble(MinValueX); x2 = Convert.ToDouble(MaxValueX); break; } Point pt1 = chartXy.GetPointFromValue(this, MinValueX, m * x1 + b); Point pt2 = chartXy.GetPointFromValue(this, MaxValueX, m * x2 + b); if (SeriesType == SeriesType.VerticalBar || SeriesType == SeriesType.VerticalHiLoBar) { pt1.X += BarOffset; pt2.X += BarOffset; } else if (SeriesType == SeriesType.HorizontalBar || SeriesType == SeriesType.HorizontalHiLoBar) { pt1.Y += BarOffset; pt2.Y += BarOffset; } RegressionLineVisualStyle rstyle = regline.RegressionLineVisualStyle; Color color = rstyle.LineColor; if (color.IsEmpty) color = DefaultPaletteColor; using (Pen pen = new Pen(color, Dpi.Width(rstyle.LineWidth))) { if (rstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)rstyle.LinePattern; if (rstyle.StartCap != ChartLineCap.NotSet) pen.StartCap = (LineCap)rstyle.StartCap; if (rstyle.EndCap != ChartLineCap.NotSet) pen.EndCap = (LineCap)rstyle.EndCap; g.DrawLine(pen, pt1, pt2); } } } #endregion #region RenderTrendLine private void RenderTrendLine(Graphics g, ChartXy chartXy, SortedSeriesPoints ssp, TrendLine trendLine) { SeriesPoint sp1 = ssp.GetSeriesPoint(trendLine.ValueX1); SeriesPoint sp2 = ssp.GetSeriesPoint(trendLine.ValueX2); if (sp1 != null && sp2 != null) { Point pt1 = chartXy.GetDataPointEx(this, sp1, trendLine.ValueYIndex); Point pt2 = chartXy.GetDataPointEx(this, sp2, trendLine.ValueYIndex); if (SeriesType == SeriesType.VerticalBar || SeriesType == SeriesType.VerticalHiLoBar) { pt1.X += BarOffset; pt2.X += BarOffset; } else if (SeriesType == SeriesType.HorizontalBar || SeriesType == SeriesType.HorizontalHiLoBar) { pt1.Y += BarOffset; pt2.Y += BarOffset; } if (pt1.X >= chartXy.ContentBounds.X && pt2.X < chartXy.ContentBounds.Right) { TrendLineVisualStyle tstyle = trendLine.TrendLineVisualStyle; Color color = tstyle.LineColor; if (color.IsEmpty) color = DefaultPaletteColor; using (Pen pen = new Pen(color, Dpi.Width(tstyle.LineWidth))) { if (tstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)tstyle.LinePattern; if (tstyle.StartCap != ChartLineCap.NotSet) pen.StartCap = (LineCap)tstyle.StartCap; if (tstyle.EndCap != ChartLineCap.NotSet) pen.EndCap = (LineCap)tstyle.EndCap; g.DrawLine(pen, pt1, pt2); } } } } #endregion #endregion #region InvalidatePoints internal void InvalidatePoints() { _PointData = null; _EmptyPointData = null; _ConvexHullPoints = null; _StepPointData = null; } #endregion #region InvalidatePointLabels internal void InvalidatePointLabels() { ChartXy chartXy = Parent as ChartXy; if (chartXy != null) chartXy.InvalidatePointLabelsEx(); } #endregion #region UpdateSeriesRange internal void UpdateSeriesRange() { if (SeriesRangeChanged == true) { if (Parent == null) return; SeriesRangeChanged = false; IsSorted = true; QualitativeXValues.Clear(); QualitativeYValues.Clear(); _MinValueX = null; _MinValueY = null; _MaxValueX = null; _MaxValueY = null; if (SeriesPoints.Count > 0) { BaseChart chart = Parent as BaseChart; Type dataTypeX = null; Type dataTypeY = null; if (ChartControl != null && ChartControl.DesignerHosted == true) { dataTypeX = GetDataTypeX(SeriesPoints); dataTypeY = GetDataTypeY(SeriesPoints); ActualScaleTypeX = GetActualScaleType(dataTypeX, ScaleTypeX); ActualScaleTypeY = GetActualScaleType(dataTypeY, ScaleTypeY); _PlotData = null; } for (int i = 0; i < SeriesPoints.Count; i++) { SeriesPoint sp = SeriesPoints[i]; if (sp.Visible == true) { UpdateXValueRange(chart, sp, ref dataTypeX); switch (SeriesType) { case SeriesType.VerticalDot: case SeriesType.HorizontalDot: ActualScaleTypeY = ScaleType.Quantitative; break; case SeriesType.Bubble: UpdateYBubbleRange(chart, sp, ref dataTypeY); break; default: UpdateYValueRange(chart, sp, ref dataTypeY); break; } } } if (SeriesType == SeriesType.VerticalDot || SeriesType == SeriesType.HorizontalDot) { UpdateStackedYValueRange(); } else { if (QualitativeXValues.Count > 0) { _MinValueX = 0; _MaxValueX = QualitativeXValues.Count - 1; } if (QualitativeYValues.Count > 0) { _MinValueY = 0; _MaxValueY = QualitativeYValues.Count - 1; } } } } } #region GetDataTypeX private Type GetDataTypeX(SeriesPointCollection spc) { Type dataType = null; for (int i = 0; i < spc.Count; i++) { SeriesPoint sp = spc[i]; if (sp.Visible == true) { if (sp.ValueX != null) { dataType = sp.ValueX.GetType(); if (dataType != typeof(int)) break; } } } return (dataType); } #endregion #region GetDataTypeY private Type GetDataTypeY(SeriesPointCollection spc) { Type dataType = null; for (int i = 0; i < spc.Count; i++) { SeriesPoint sp = spc[i]; if (sp.Visible == true) { if (sp.ValueY != null && sp.ValueY.Length > 0) { for (int j = 0; j < sp.ValueY.Length; j++) { object valueY = sp.ValueY[j]; if (valueY != null) { dataType = valueY.GetType(); if (dataType != typeof(int)) return (dataType); } } } } } return (dataType); } #endregion #region UpdateXValueRange private int _CmpLast; private void UpdateXValueRange(BaseChart chart, SeriesPoint sp, ref Type dataType) { object value = sp.ValueX; if (value != null) { if (dataType == null) { dataType = value.GetType(); ActualScaleTypeX = GetActualScaleType(dataType, ScaleTypeX); } else { if (value.GetType() != dataType) { if (ChartControl.DesignerHosted == true) { try { sp.ValueX = Convert.ChangeType(value, dataType); } catch { sp.ValueX = null; } value = sp.ValueX; } else { throw new Exception("Cannot mix ValueX data types (" + dataType + "," + value.GetType() + ")."); } } } switch (_ActualScaleTypeX) { case ScaleType.Qualitative: if (QualitativeXValues.Contains(value) == false) QualitativeXValues.Add(value); break; default: if (_MinValueX == null) { _MinValueX = value; _MaxValueX = value; _CmpLast = 0; } else { if (chart.DataCompare(value, _MaxValueX) >= 0) { _MaxValueX = value; if (_CmpLast == 0) _CmpLast = 1; else if (_CmpLast < 0) IsSorted = false; } else { if (chart.DataCompare(value, _MinValueX) <= 0) _MinValueX = value; if (_CmpLast == 0) _CmpLast = -1; else if (_CmpLast > 0) IsSorted = false; } } break; } } } #endregion #region UpdateYBubbleRange private void UpdateYBubbleRange(BaseChart chart, SeriesPoint sp, ref Type dataType) { if (sp.ValueY == null || sp.ValueY.Length < 1) throw new Exception("Invalid Bubble Chart 'Y' arguments."); if (_PlotData == null) _PlotData = new BubblePlotData(); BubblePlotData bdata = (BubblePlotData)_PlotData; object value = sp.ValueY[0]; sp.IsEmptyValue = IsEmptyValue(value); if (sp.IsEmpty == false) { if (dataType == null) { bdata.Clear(); dataType = value.GetType(); ActualScaleTypeY = GetActualScaleType(dataType, ScaleTypeY); } else { if (value.GetType() != dataType) { if (ChartControl.DesignerHosted == true) { sp.ValueY[0] = Convert.ChangeType(value, dataType); value = sp.ValueY[0]; } else { throw new Exception("Cannot mix ValueY data types (" + dataType + "," + value.GetType() + ")."); } } } ProcessYValueRange(chart, value); if (sp.ValueY.Length > 1) { double bvalue = GetDoubleValue(sp.ValueY[1]); bvalue = Math.Abs(bvalue); if (bvalue < bdata.MinSize) bdata.MinSize = bvalue; if (bvalue > bdata.MaxSize) bdata.MaxSize = bvalue; bdata.TotalSize += bvalue; if (sp.ValueY.Length > 2) { double ivalue = GetDoubleValue(sp.ValueY[2]); if (ivalue < bdata.MinIntensity) bdata.MinIntensity = ivalue; if (ivalue > bdata.MaxIntensity) bdata.MaxIntensity = ivalue; } } } } #endregion #region UpdateYValueRange private void UpdateYValueRange(BaseChart chart, SeriesPoint sp, ref Type dataType) { if (sp.ValueY != null) { for (int j = 0; j < sp.ValueY.Length; j++) { object value = sp.ValueY[j]; sp.IsEmptyValue = IsEmptyValue(value); if (sp.IsEmpty == false) { if (dataType == null) { dataType = value.GetType(); ActualScaleTypeY = GetActualScaleType(dataType, ScaleTypeY); } else { if (value.GetType() != dataType) { if (ChartControl.DesignerHosted == true) { try { sp.ValueY[j] = Convert.ChangeType(value, dataType); } catch { sp.ValueY[j] = null; } value = sp.ValueY[j]; } else { throw new Exception("Cannot mix ValueY data types (" + dataType + "," + value.GetType() + ")."); } } } ProcessYValueRange(chart, value); } } } else { sp.IsEmptyValue = true; } } #region IsEmptyValue private bool IsEmptyValue(object value) { if (value == null) return (true); if (EmptyValues != null) { Type dataType = value.GetType(); for (int i = 0; i < EmptyValues.Length; i++) { if (EmptyValues[i] != null) { if (dataType == EmptyValues[i].GetType()) { if (value.Equals(EmptyValues[i]) == true) return (true); } } } } return (false); } #endregion #endregion #region UpdateStackedYValueRange private void UpdateStackedYValueRange() { if (QualitativeXValues.Count > 0 || QualitativeYValues.Count > 0) throw new Exception("Dot plots can not contain Qualitative values."); Dictionary pd = new Dictionary(); for (int i = 0; i < SeriesPoints.Count; i++) { SeriesPoint sp = SeriesPoints[i]; if (sp.Visible == true) { object ox = sp.ValueX; double count = 0; if (sp.ValueY != null && sp.ValueY.Length > 0) { foreach (object oy in sp.ValueY) { sp.IsEmptyValue = IsEmptyValue(oy); if (sp.IsEmpty == false) count += GetDoubleValue(oy); } } else { if (sp.IsEmpty == false) count++; } if (sp.IsEmpty == false) { if (pd.ContainsKey(ox) == true) pd[ox] += count; else pd.Add(ox, count); } } } double maxValue = 0; foreach (KeyValuePair kvp in pd) { if (kvp.Value > maxValue) maxValue = kvp.Value; } _MinValueY = 0.0; _MaxValueY = maxValue; } #endregion #region ProcessYValueRange private void ProcessYValueRange(BaseChart chart, object value) { switch (_ActualScaleTypeY) { case ScaleType.Qualitative: if (QualitativeYValues.Contains(value) == false) QualitativeYValues.Add(value); break; default: if (_MinValueY == null) { _MinValueY = value; _MaxValueY = value; } else { int cmpMax = chart.DataCompare(value, _MaxValueY); if (cmpMax >= 0) { _MaxValueY = value; } else { int cmpMin = chart.DataCompare(value, _MinValueY); if (cmpMin <= 0) _MinValueY = value; } } break; } } #endregion #region GetActualScaleType private ScaleType GetActualScaleType(Type dataType, ScaleType scaleType) { ScaleType autoType = SeriesPoint.GetScaleType(dataType); if (scaleType == ScaleType.NotSet || scaleType == ScaleType.Auto) return (autoType); if (scaleType == autoType) return (scaleType); if (scaleType == ScaleType.Qualitative) return (scaleType); throw new Exception("Set ScaleType is incompatible with series data."); } #endregion #endregion #region ResetSortedPoints internal void ResetSortedPoints() { if (IsSorted == false) _SortedSeriesPoints = null; } #endregion #region GetValueX internal object GetValueX(SeriesPoint sp) { if (IsRotated == false) return (sp.ValueX); if (sp.ValueY != null && sp.ValueY.Length > 0) return (sp.ValueY[0]); return (null); } #endregion #region GetValueY internal object GetValueY(SeriesPoint sp, int index) { if (IsRotated == true) return (sp.ValueX); if (sp.ValueY != null && sp.ValueY.Length > index) return (sp.ValueY[index]); return (null); } #endregion #region GetQualitativeValueX internal object GetQualitativeValueX(int index) { if (IsRotated == false) { if (QualitativeXValues != null && QualitativeXValues.Count > index) return (QualitativeXValues[index]); } else { if (QualitativeYValues != null && QualitativeYValues.Count > index) return (QualitativeYValues[index]); } return (null); } #endregion #region GetQualitativeValueY internal object GetQualitativeValueY(int index) { if (IsRotated == true) { if (QualitativeXValues != null && QualitativeXValues.Count > index) return (QualitativeXValues[index]); } else { if (QualitativeYValues != null && QualitativeYValues.Count > index) return (QualitativeYValues[index]); } return (null); } #endregion #region GetDoubleValue private double GetDoubleValue(object value) { if (value is double) return (double)value; return (Convert.ToDouble(value)); } #endregion #region AddSeriesPoint internal override void AddSeriesPoint(object valueX, object[] valuesY, object dataItem) { SeriesPoint sp = new SeriesPoint(valueX, valuesY); sp.DataItem = dataItem; SeriesPoints.Add(sp); } #endregion #region ClearSeriesPoints internal override void ClearSeriesPoints() { SeriesPoints.Clear(); } #endregion #region GetBarWidthRatio internal double GetBarWidthRatio(ChartXy chartXy) { return (_BarWidthRatio > 0 ? _BarWidthRatio : (chartXy.BarWidthRatio > 0 ? chartXy.BarWidthRatio : 1)); } #endregion #region GetPointLabels internal List GetPointLabels(Graphics g) { ChartXy chartXy = Parent as ChartXy; PointLabelDisplayMode plmode = GetPointLabelDisplayType(chartXy); if (plmode != PointLabelDisplayMode.None) { ChartSeriesVisualStyle sstyle = EffectiveChartSeriesStyle; SortedSeriesPoints ssp = GetSortedSeriesPoints(chartXy); ssp.SeriesLayoutCount = chartXy.SeriesLayoutCount; ChartAxis axisX = (IsRotated == true) ? AxisY ?? chartXy.AxisY : AxisX ?? chartXy.AxisX; ChartAxis axisY = (IsRotated == true) ? AxisX ?? chartXy.AxisX : AxisY ?? chartXy.AxisY; if (ssp.Count > 0) { DataLabelVisualStyle dstyle = EffectiveDataLabelStyle; PointData pd = GetLabelPoints(chartXy, ssp, 0, ssp.Count, plmode); List plabels = new List(); if (pd.Points.Count > 0) { for (int i = 0; i < pd.Points.Count; i++) { Point[] pts = pd.Points[i]; SeriesPoint[] spts = pd.SeriesPoints[i]; for (int j = 0; j < pts.Length; j++) { SeriesPoint sp = spts[j]; Point pt = pts[j]; if (IsBarSeries == true && ShowOriginValueLabels == false) { if (IsBarOrigin(chartXy, sp) == true) continue; } string text = GetPointLabelText(sp, axisX, axisY, dstyle); PointLabel pl = new PointLabel(sp, pt, text); pl.LabelSize = MeasurePointLabel(g, pl); plabels.Add(pl); } } } if ((plmode & PointLabelDisplayMode.DataLabels) == PointLabelDisplayMode.DataLabels) GetDataLabels(g, plabels, chartXy, axisX, axisY, dstyle); return (plabels); } } return (null); } #region GetPointLabelDisplayType private PointLabelDisplayMode GetPointLabelDisplayType(ChartXy chartXy) { PointLabelDisplayMode ptype = PointLabelDisplayMode; if (ptype != PointLabelDisplayMode.NotSet) return (ptype); ptype = chartXy.PointLabelDisplayMode; return (ptype != PointLabelDisplayMode.NotSet ? ptype : PointLabelDisplayMode.None); } #endregion #region GetLabelPoints /// /// Gets the collection of series PointData for the given PointLabelDisplayType. /// /// /// public PointData GetLabelPoints(PointLabelDisplayMode displayType) { ChartXy chartXy = Parent as ChartXy; if (chartXy != null) { SortedSeriesPoints ssp = GetSortedSeriesPoints(chartXy); return (GetLabelPoints(chartXy, ssp, 0, ssp.Count, displayType)); } return (null); } private PointData GetLabelPoints(ChartXy chartXy, SortedSeriesPoints ssp, int index, int count, PointLabelDisplayMode displayType) { PointData pd = new PointData(); pd.Points = new List(); pd.SeriesPoints = new List(); if ((displayType & PointLabelDisplayMode.AllSeriesPoints) == PointLabelDisplayMode.AllSeriesPoints) GetPointList(chartXy, ssp, index, count, _PointLabelSkip, _PointLabelMinDistance, false, pd); else if ((displayType & ~PointLabelDisplayMode.AllSeriesPoints) != 0) { List lmmsp = new List(); if ((displayType & PointLabelDisplayMode.MinValueX) == PointLabelDisplayMode.MinValueX) { int n; if (IsRotated == true) { if (QualitativeYValues.Count > 0) n = (int)MinValueX; else n = ssp.SearchY(MinValueX); } else { if (QualitativeXValues.Count > 0) n = (int)MinValueX; else n = (ssp.IsSorted == true) ? 0 : ssp.SearchX(MinValueX); } if (n >= 0) lmmsp.Add(ssp[n]); } if ((displayType & PointLabelDisplayMode.MaxValueX) == PointLabelDisplayMode.MaxValueX) { int n; if (IsRotated == true) { if (QualitativeYValues.Count > 0) n = (int)MaxValueX; else n = ssp.SearchY(MaxValueX); } else { if (QualitativeXValues.Count > 0) n = (int)MaxValueX; else n = (ssp.IsSorted == true) ? ssp.Count - 1 : ssp.SearchX(MaxValueX); } if (n >= 0 && lmmsp.Contains(ssp[n]) == false) lmmsp.Add(ssp[n]); } if ((displayType & PointLabelDisplayMode.MinValueY) == PointLabelDisplayMode.MinValueY) { int n; if (IsRotated == true) { if (QualitativeXValues.Count > 0) n = (int)MinValueY; else n = (ssp.IsSorted == true) ? 0 : ssp.SearchX(MinValueY); } else { if (QualitativeYValues.Count > 0) n = (int)MinValueY; else n = ssp.SearchY(MinValueY); } if (n >= 0 && lmmsp.Contains(ssp[n]) == false) lmmsp.Add(ssp[n]); } if ((displayType & PointLabelDisplayMode.MaxValueY) == PointLabelDisplayMode.MaxValueY) { int n; if (IsRotated == true) { if (QualitativeXValues.Count > 0) n = (int)MaxValueY; else n = ssp.SearchX(MaxValueY); } else { if (QualitativeYValues.Count > 0) n = (int)MaxValueY; else n = ssp.SearchY(MaxValueY); } if (n >= 0 && lmmsp.Contains(ssp[n]) == false) lmmsp.Add(ssp[n]); } if (lmmsp.Count > 0) { SeriesPoint[] mmsp = new SeriesPoint[lmmsp.Count]; Point[] mmpt = new Point[lmmsp.Count]; for (int i = 0; i < lmmsp.Count; i++) { mmsp[i] = lmmsp[i]; mmpt[i] = chartXy.GetDataPointNa(this, lmmsp[i], 0); } pd.SeriesPoints.Add(mmsp); pd.Points.Add(mmpt); } } return (pd); } #endregion #region GetDataLabels private void GetDataLabels(Graphics g, List plabels, ChartXy chartXy, ChartAxis axisX, ChartAxis axisY, DataLabelVisualStyle dstyle) { foreach (DataLabel dlabel in DataLabels) { DataLabelVisualStyle xstyle = dlabel.EffectiveDataLabelStyle; PointLabel pl = FindPointLabel(plabels, dlabel); if (pl != null) { if (string.IsNullOrEmpty(dlabel.Text) == false) pl.Label = dlabel.Text; pl.DataLabelVisualStyle = xstyle; pl.BarLabelPosition = dlabel.BarLabelPosition; pl.LabelSize = MeasurePointLabel(g, pl); } else { SeriesPoint sp = new SeriesPoint(dlabel.ValueX, dlabel.ValueY); string label = (string.IsNullOrEmpty(dlabel.Text) == false) ? dlabel.Text : GetPointLabelText(sp, axisX, axisY, xstyle); Point pt = chartXy.GetDataPointNa(this, sp, 0); pl = new PointLabel(sp, pt, label); pl.IsDataLabel = true; pl.DataLabelVisualStyle = xstyle; pl.BarLabelPosition = dlabel.BarLabelPosition; pl.LabelSize = MeasurePointLabel(g, pl); plabels.Add(pl); } } } #region FindPointLabel private PointLabel FindPointLabel(List plabels, DataLabel dlabel) { for (int i = 0; i < plabels.Count; i++) { SeriesPoint sp = plabels[i].SeriesPoint; if ((sp.ValueX != null) && (sp.ValueY != null && sp.ValueY.Length > 0) && (sp.ValueX.Equals(dlabel.ValueX) && sp.ValueY[0].Equals(dlabel.ValueY))) { return (plabels[i]); } } return (null); } #endregion #endregion #region IsBarOrigin internal bool IsBarOrigin(ChartXy chartXy, SeriesPoint sp) { object value = ((sp.ValueY != null && sp.ValueY.Length > 1) ? sp.ValueY[1] : (chartXy.BarOrigin ?? 0)); ChartAxis axis = AxisY ?? chartXy.AxisY; switch (axis.ScaleType) { case ScaleType.Quantitative: double d1 = Convert.ToDouble(value); double d2 = Convert.ToDouble(sp.ValueY[0]); return (d1.Equals(d2)); case ScaleType.Qualitative: string s1 = axis.QualitativeValues[0] as string; string s2 = sp.ValueY[0] as string; if (s1 != null) return (s1.Equals(s2)); break; } return (false); } #endregion #region GetPointLabelText private string GetPointLabelText(SeriesPoint sp, ChartAxis axisX, ChartAxis axisY, DataLabelVisualStyle dstyle) { string pattern = dstyle.TextFormat; if (string.IsNullOrEmpty(pattern) == true) return (GetDefaultPointLabelText(sp, axisX, axisY, dstyle)); pattern = pattern.Replace("\\n", "\n"); pattern = pattern.Replace("\\r", "\r"); Regex regex = new Regex("{([^}]*)}"); MatchCollection mc = regex.Matches(pattern); StringBuilder sb = new StringBuilder(); int index = 0; foreach (Match ma in mc) { if (ma.Index > index) sb.Append(pattern.Substring(index, ma.Index - index)); sb.Append(ProcessFormatSpecifier(sp, axisX, axisY, ma.Value)); index = ma.Index + ma.Length; } if (index < pattern.Length) sb.Append(pattern.Substring(index)); return (sb.ToString()); } #region ProcessFormatSpecifier private string ProcessFormatSpecifier( SeriesPoint sp, ChartAxis axisX, ChartAxis axisY, string pattern) { string s = pattern.Substring(1, pattern.Length - 2); int n = s.IndexOf(':'); if ((uint)n > s.Length - 1) n = s.Length; string placeHolder = s.Substring(0, n).Trim().ToUpper(); string formatSpecifier = (n + 1 < s.Length) ? s.Substring(n + 1) : ""; try { switch (placeHolder) { case "X": return (GetPointLabelText(sp.ValueX, axisX, formatSpecifier)); case "Y": case "Y0": if (sp.ValueY != null && sp.ValueY.Length > 0) return (GetPointLabelText(sp.ValueY[0], axisY, formatSpecifier)); return (""); case "S": case "SNAME": if (string.IsNullOrEmpty(formatSpecifier) == false) return (String.Format(formatSpecifier, Name)); return (Name); default: if (placeHolder.StartsWith("Y") == true) { int index = int.Parse(placeHolder.Substring(1)); if (sp.ValueY != null && sp.ValueY.Length > index) return (GetPointLabelText(sp.ValueY[index], axisY, formatSpecifier)); } return (s); } } catch { } return (s); } #endregion #region GetDefaultPointLabelText private string GetDefaultPointLabelText(SeriesPoint sp, ChartAxis axisX, ChartAxis axisY, DataLabelVisualStyle dstyle) { String text = string.Empty; if (IsBarSeries == true) { text = GetPointLabelText(sp.ValueY[0], axisY, string.Empty); } else { text = GetPointLabelText(sp.ValueX, axisX, string.Empty); if (sp.ValueY != null) text += " : " + GetPointLabelText(sp.ValueY[0], axisY, string.Empty); } return (text); } #endregion #region GetPointLabelText private string GetPointLabelText( object value, ChartAxis axis, string format) { switch (axis.ScaleType) { case ScaleType.DateTime: if (string.IsNullOrEmpty(format) == false) { if (value is DateTime) { DateTime date = (DateTime)value; return (date.ToString(format)); } } return (GetDateTimeLabelText(axis, (DateTime)value)); case ScaleType.Qualitative: if (string.IsNullOrEmpty(format) == false) return (string.Format(format, value)); return (value.ToString()); default: double d = Convert.ToDouble(value); if (string.IsNullOrEmpty(format) == false) return (d.ToString(format)); return (d.ToString("F3")); } } #region GetDateTimeLabelText internal string GetDateTimeLabelText(ChartAxis axis, DateTime dt) { switch (axis.ActualDateTimeUnits) { case DateTimeUnits.Ticks: return (dt.Ticks.ToString()); case DateTimeUnits.Milliseconds: return (dt.Millisecond.ToString()); case DateTimeUnits.Seconds: return (dt.Second.ToString()); case DateTimeUnits.Minutes: return (dt.Minute.ToString()); case DateTimeUnits.Hours: return (dt.ToShortTimeString()); case DateTimeUnits.Days: return (dt.ToShortDateString()); case DateTimeUnits.Months: return (dt.Year + " " + dt.Month); default: return (dt.Year.ToString()); } } #endregion #endregion #endregion #region MeasurePointLabel internal Size MeasurePointLabel(Graphics g, PointLabel pl) { DataLabelVisualStyle dstyle = GetPointLabelVisualStyle(pl); int width = (dstyle.MaxTextWidth > 0) ? dstyle.MaxTextWidth : 0; using (StringFormat sf = new StringFormat()) { if (dstyle.MaxTextLineCount <= 1) sf.FormatFlags |= StringFormatFlags.NoWrap; Size size = g.MeasureString(pl.Label, dstyle.Font, width, sf).ToSize(); size.Width++; if (dstyle.MaxTextLineCount > 1) { int lineHeight = (int)(Math.Ceiling(dstyle.Font.GetHeight())) * dstyle.MaxTextLineCount; if (size.Height > lineHeight) size.Height = lineHeight; } return (size); } } #region GetPointLabelVisualStyle internal DataLabelVisualStyle GetPointLabelVisualStyle(PointLabel pl) { DataLabelVisualStyle dstyle = EffectiveDataLabelStyle.Copy(); if (pl.DataLabelVisualStyle != null) dstyle.ApplyStyle(pl.DataLabelVisualStyle); else dstyle = EffectiveDataLabelStyle; return (dstyle); } #endregion #endregion #endregion #region GetRotateDegrees internal RotateDegrees GetRotateDegrees(DataLabelVisualStyle dstyle) { RotateDegrees degrees = dstyle.RotateDegrees; if (degrees == RotateDegrees.Auto || degrees == RotateDegrees.NotSet) { switch (SeriesType) { case SeriesType.HorizontalBar: case SeriesType.HorizontalHiLoBar: return (RotateDegrees.None); case SeriesType.VerticalBar: case SeriesType.VerticalHiLoBar: return (RotateDegrees.Rotate270); default: return (RotateDegrees.None); } } return (dstyle.RotateDegrees); } #endregion #region IsConvexHullPoint /// /// Determines whether the given SeriesPoint is a ConvexHull point. /// /// /// public bool IsConvexHullPoint(SeriesPoint sp) { if (sp != null && _ConvexHullPoints != null) { ChartXy chartXy = Parent as ChartXy; if (chartXy != null) { ConvexHullDisplayMode mode = GetConvexHullDisplayMode(chartXy); if (mode != ConvexHullDisplayMode.None) { foreach (Point ptc in _ConvexHullPoints) { if (ptc.Equals(sp.Point[0]) == true) return (true); } } } } return (false); } #endregion #region IsHighLightPoint /// /// Determines if the given SeriesPoint is a HighLight Point (a /// point highlighted by the Crosshair setup). /// /// /// public bool IsHighLightPoint(SeriesPoint sp) { if (sp != null) { ChartXy chartXy = Parent as ChartXy; if (chartXy != null) return (chartXy.IsCrosshairSeriesPoint(this, sp.Point[0])); } return (false); } #endregion #region Style handling #region ApplyStyles public override void ApplyStyles(BaseVisualStyle style) { ChartSeriesVisualStyle sstyle = style as ChartSeriesVisualStyle; if (sstyle != null) { ApplyParentStyles(sstyle, Parent as ChartContainer); sstyle.ApplyStyle(ChartSeriesVisualStyle); ApplyDefaultLineStyles(sstyle.LineStyle); ApplyDefaultLineStyles(sstyle.SplineStyle); ApplyDefaultLineStyles(sstyle.StepLineStyle); ApplyDefaultLineStyles(sstyle.EmptyStyle); ApplyDefaultMarkerStyles(sstyle.MarkerVisualStyle); ApplyDefaultMarkerStyles(sstyle.MarkerEmptyVisualStyle); if (sstyle.EmptyAreaBackground.IsEmpty) sstyle.EmptyAreaBackground = new Background(Color.FromArgb(100, Color.LightGray)); if (SeriesType == SeriesType.Bubble) { if (sstyle.MarkerVisualStyle.Background.IsEmpty) sstyle.MarkerVisualStyle.Background = new Background(DefaultPaletteColor); } ApplyDefaultBarStyles(sstyle.BarVisualStyle); ApplyDefaultOhlcBarStyles(sstyle.HiLoBarVisualStyle); } else if (style is DataLabelVisualStyle) { DataLabelVisualStyle dstyle = (DataLabelVisualStyle)style; ApplyParentStyles(dstyle, Parent as ChartContainer); dstyle.ApplyStyle(_DataLabelVisualStyle); dstyle.ApplyDefaults(); } } #region ApplyParentStyles (ChartSeriesVisualStyle) private void ApplyParentStyles(ChartSeriesVisualStyle pstyle, ChartContainer item) { if (item != null) { ApplyParentStyles(pstyle, item.Parent as ChartContainer); if (item is ChartXy) pstyle.ApplyStyle(((ChartXy)item).ChartSeriesVisualStyle); if (item is ChartPanel) pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.ChartSeriesVisualStyle); } else { pstyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartSeriesVisualStyle); pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartSeriesVisualStyle); } } #endregion #region ApplyParentStyles (DataLabelVisualStyle) private void ApplyParentStyles(DataLabelVisualStyle dstyle, ChartContainer item) { if (item != null) { ApplyParentStyles(dstyle, item.Parent as ChartContainer); if (item is BaseChart) dstyle.ApplyStyle(((ChartXy)item).DataLabelVisualStyle); if (item is ChartPanel) dstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.DataLabelVisualStyle); } else { dstyle.ApplyStyle(ChartControl.BaseVisualStyles.DataLabelVisualStyle); dstyle.ApplyStyle(ChartControl.DefaultVisualStyles.DataLabelVisualStyle); } } #endregion #region ApplyDefaultLineStyles private void ApplyDefaultLineStyles(ChartLineVisualStyle lstyle) { if (lstyle.LineColor.IsEmpty == true) lstyle.LineColor = DefaultPaletteColor; lstyle.ApplyDefaults(); } #endregion #region ApplyDefaultMarkerStyles private void ApplyDefaultMarkerStyles(PointMarkerVisualStyle pstyle) { if (pstyle.Background.IsEmpty && pstyle.BorderColor.IsEmpty) pstyle.BorderColor = DefaultPaletteColor; pstyle.ApplyDefaults(); } #endregion #region ApplyDefaultBarStyles private void ApplyDefaultBarStyles(ChartBarVisualStyle bstyle) { if (bstyle.Background.IsEmpty == true) bstyle.Background = new Background(DefaultPaletteColor); ApplyDefaultLineStyles(bstyle.Border); } #endregion #region ApplyDefaultOhlcBarStyles private void ApplyDefaultOhlcBarStyles(ChartHiLoBarVisualStyle bstyle) { HiLoBarSegmentStyle sstyle = bstyle.DefaultSegmentStyle; if (sstyle.Default.LineColor.IsEmpty == true) sstyle.Default.LineColor = Color.Black; sstyle.Default.ApplyDefaults(); switch (HiLoBarType) { case HiLoBarType.Candle: bool backSet = (sstyle.BoxBackground.IsEmpty == true); if (backSet == true) sstyle.BoxBackground = new Background(DefaultPaletteColor); Background bk = sstyle.BoxBackground; sstyle = bstyle.AlternateSegmentStyle; if (sstyle.BoxBackground.IsEmpty == true) { if (backSet == true) { sstyle.BoxBackground = new Background(Color.Black, DefaultPaletteColor); sstyle.BoxBackground.HatchFillType = HatchFillType.ForwardDiagonal; } else { if (bk.IsSolidBrush == true) { sstyle.BoxBackground = new Background(Color.Black, bk.Color1); sstyle.BoxBackground.HatchFillType = HatchFillType.ForwardDiagonal; } else if (bk.Color1.IsEmpty == false && bk.Color2.IsEmpty == false) { sstyle.BoxBackground = new Background(bk.Color2, bk.Color1); } } } break; case Charts.HiLoBarType.Box: if (sstyle.BoxBackground.IsEmpty == true) sstyle.BoxBackground = new Background(DefaultPaletteColor); break; } sstyle = bstyle.DefaultSegmentStyle; _RenderFullDefRange = sstyle.CenterLine.IsEmpty && sstyle.HighWhisker.IsEmpty && sstyle.LowWhisker.IsEmpty; sstyle = bstyle.AlternateSegmentStyle; _RenderFullAltRange = sstyle.CenterLine.IsEmpty && sstyle.HighWhisker.IsEmpty && sstyle.LowWhisker.IsEmpty; } private bool _RenderFullDefRange; private bool _RenderFullAltRange; #endregion #endregion #region ClearEffectiveStyles protected override void ClearEffectiveStyles() { if (_EffectiveChartSeriesStyle.InvalidateStyle() == true) InvalidateLayout(); if (_EffectiveDataLabelStyle.InvalidateStyle() == true) InvalidateLayout(); foreach (DataLabel dl in DataLabels) dl.InvalidateStyle(); if (LegendItem != null) LegendItem.EffectiveStyles.InvalidateStyles(); PointMarkerImage = null; PointMarkerEmptyImage = null; PointMarkerHighlightImage = null; } #endregion #region StyleChanged protected override void StyleChanged(object sender, PropertyChangedEventArgs e) { base.StyleChanged(sender, e); if (sender is ChartLegendItemVisualStyles && LegendItem != null) InvalidateRender(LegendItem.Bounds); } #endregion #endregion #region ILegendItem #region OnCheckStateChanged internal override void OnCheckStateChanged() { if (IsQualitativeXValues || IsQualitativeYValues) InvalidateLayout(); if (PointLabelDisplayMode != PointLabelDisplayMode.None) InvalidatePointLabels(); base.OnCheckStateChanged(); } #endregion #region AddSubLegendItems internal override void AddSubLegendItems(List list) { foreach (ChartIndicator ci in ChartIndicators) { if (ci.Visible == true) { ChartLegendItem li = ci.GetLegendItem(); if (li != null) list.Add(li); } } } #endregion #region GetLegendItemColorEx internal override Color GetLegendItemColorEx() { ChartXy chartXy = Parent as ChartXy; ChartSeriesVisualStyle sstyle = EffectiveChartSeriesStyle; PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle; if (sstyle.ItemColor.IsEmpty == false) return (sstyle.ItemColor); switch (SeriesType) { case SeriesType.Bubble: case SeriesType.Point: case SeriesType.HorizontalDot: case SeriesType.VerticalDot: return (pstyle.Background.Color1); case SeriesType.Line: ChartLineDisplayMode mode = GetLineDisplayMode(chartXy); if ((mode & ChartLineDisplayMode.DisplayLine) == ChartLineDisplayMode.DisplayLine) { if (sstyle.LineStyle.LineColor.IsEmpty == false) return (sstyle.LineStyle.LineColor); } if ((mode & ChartLineDisplayMode.DisplaySpline) == ChartLineDisplayMode.DisplaySpline) { if (sstyle.SplineStyle.LineColor.IsEmpty == false) return (sstyle.SplineStyle.LineColor); } if ((mode & ChartLineDisplayMode.DisplayStepLine) == ChartLineDisplayMode.DisplayStepLine) { if (sstyle.StepLineStyle.LineColor.IsEmpty == false) return (sstyle.StepLineStyle.LineColor); } return (pstyle.Background.Color1); case SeriesType.HorizontalBar: case SeriesType.VerticalBar: return (sstyle.BarVisualStyle.Background.Color1); case SeriesType.HorizontalHiLoBar: case SeriesType.VerticalHiLoBar: HiLoBarSegmentStyle hstyle = sstyle.HiLoBarVisualStyle.DefaultSegmentStyle; if (HiLoBarType == HiLoBarType.Line) { if (hstyle.Default.LineColor.IsEmpty == false) return (hstyle.Default.LineColor); return (hstyle.CenterLine.LineColor); } return (hstyle.BoxBackground.Color1); } return (Color.Empty); } #endregion #region RenderLegendItemMarkerEx internal override void RenderLegendItemMarkerEx( Graphics g, ChartLegendItem litem, ChartLegendItemVisualStyle style) { ChartXy chartXy = Parent as ChartXy; ChartSeriesVisualStyle sstyle = EffectiveChartSeriesStyle; Rectangle bounds = litem.MarkerBounds; switch (SeriesType) { case SeriesType.HorizontalHiLoBar: case SeriesType.VerticalHiLoBar: RenderHiLoBarMarker(g, bounds, chartXy, sstyle); break; case SeriesType.VerticalBar: case SeriesType.HorizontalBar: RenderBarMarker(g, bounds, chartXy, sstyle); break; case SeriesType.Bubble: RenderBubbleMarker(g, bounds, chartXy, sstyle); break; ; case SeriesType.VerticalDot: case SeriesType.HorizontalDot: case SeriesType.Point: RenderDotMarker(g, bounds, chartXy, sstyle); break; case SeriesType.Line: RenderLineMarker(g, bounds, chartXy, sstyle); break; default: RenderDefaultMarker(g, bounds, sstyle); break; } } #region RenderHiLoBarMarker private void RenderHiLoBarMarker(Graphics g, Rectangle bounds, ChartXy chartXy, ChartSeriesVisualStyle sstyle) { Rectangle r = bounds; r.Inflate(-1, -1); if (r.Width > 0 && r.Height > 0) { SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.None; HiLoBarSegmentStyle hstyle = sstyle.HiLoBarVisualStyle.DefaultSegmentStyle; if (HiLoBarType == HiLoBarType.Line) { Color color = hstyle.Default.LineColor; if (color.IsEmpty == true) color = hstyle.CenterLine.LineColor; if (color.IsEmpty == true) color = DefaultPaletteColor; if (color.IsEmpty == true) color = Color.Black; if (IsRotated == true || r.Width > r.Height) RenderHiLoHBarMarker(g, r, color); else RenderHiLoVBarMarker(g, r, color); } else { Background bk = hstyle.BoxBackground; ChartLineVisualStyle lstyle = hstyle.BoxBorder; if (IsRotated == true || r.Width > r.Height) RenderHBoxMarker(g, r, bk, hstyle, lstyle); else RenderVBoxMarker(g, r, bk, hstyle, lstyle); } g.SmoothingMode = sm; } } #region RenderHBoxMarker private void RenderHBoxMarker(Graphics g, Rectangle r, Background bk, HiLoBarSegmentStyle hstyle, ChartLineVisualStyle lstyle) { int n = r.Height / 4; Rectangle t = r; t.Inflate(-n, -n); if (t.Height % 2 != 0) { t.Y--; t.Height++; } using (Brush br = bk.GetBrush(t)) g.FillRectangle(br, t); Color lineColor = lstyle.LineColor; if (lineColor.IsEmpty == true) lineColor = hstyle.Default.LineColor; if (lineColor.IsEmpty == true) lineColor = Color.Black; using (Pen pen = new Pen(lineColor)) { Point pt1 = new Point(r.X, (r.Y + r.Bottom) / 2); Point pt2 = new Point(t.X, pt1.Y); g.DrawLine(pen, pt1, pt2); pt1.X = t.Right; pt2.X = r.Right; g.DrawLine(pen, pt1, pt2); } using (Pen pen = new Pen(lineColor)) g.DrawRectangle(pen, t); } #endregion #region RenderVBoxMarker private void RenderVBoxMarker(Graphics g, Rectangle r, Background bk, HiLoBarSegmentStyle hstyle, ChartLineVisualStyle lstyle) { int n = r.Width / 4; Rectangle t = r; t.Inflate(-n, -n); if (t.Width % 2 != 0) { t.X--; t.Width++; } using (Brush br = bk.GetBrush(t)) g.FillRectangle(br, t); Color lineColor = lstyle.LineColor; if (lineColor.IsEmpty == true) lineColor = hstyle.Default.LineColor; if (lineColor.IsEmpty == true) lineColor = Color.Black; using (Pen pen = new Pen(lineColor)) { Point pt1 = new Point((r.X + r.Right) / 2, r.Y); Point pt2 = new Point(pt1.X, t.Y); g.DrawLine(pen, pt1, pt2); pt1.Y = t.Bottom; pt2.Y = r.Bottom; g.DrawLine(pen, pt1, pt2); } using (Pen pen = new Pen(lineColor)) g.DrawRectangle(pen, t); } #endregion #region RenderHiLoHBarMarker private void RenderHiLoHBarMarker(Graphics g, Rectangle r, Color color) { Point pt1 = new Point(r.X, (r.Y + r.Bottom) / 2); Point pt2 = new Point(r.Right, pt1.Y); using (Pen pen = new Pen(color)) { g.DrawLine(pen, pt1, pt2); int n = (r.Bottom - r.Top) / 3; pt1.X = r.X + (r.Width / 4); pt1.Y -= n; pt2.X = pt1.X; g.DrawLine(pen, pt1, pt2); pt1.X = r.X + (r.Width / 4) * 3; pt1.Y += (2 * n); pt2.X = pt1.X; g.DrawLine(pen, pt1, pt2); } } #endregion #region RenderHiLoVBarMarker private void RenderHiLoVBarMarker(Graphics g, Rectangle r, Color color) { Point pt1 = new Point((r.X + r.Right) / 2, r.Y); Point pt2 = new Point(pt1.X, r.Bottom); using (Pen pen = new Pen(color)) { g.DrawLine(pen, pt1, pt2); int n = (r.Right - r.Left) / 3; pt1.X -= n; pt1.Y = r.Y + (r.Height / 4); pt2.Y = pt1.Y; g.DrawLine(pen, pt1, pt2); pt1.X += (2 * n); pt1.Y = r.Y + (r.Height / 4) * 3; pt2.Y = pt1.Y; g.DrawLine(pen, pt1, pt2); } } #endregion #endregion #region RenderBarMarker private void RenderBarMarker(Graphics g, Rectangle bounds, ChartXy chartXy, ChartSeriesVisualStyle sstyle) { ChartLineVisualStyle cstyle = sstyle.BarVisualStyle.Border; Background bk = sstyle.BarVisualStyle.Background; Rectangle r = bounds; r.Inflate(-1, -1); using (Brush br = bk.GetBrush(r)) { g.FillRectangle(br, r); if (cstyle.LineColor.IsEmpty == false && cstyle.LinePattern != LinePattern.None) { using (Pen pen = new Pen(cstyle.LineColor, cstyle.LineWidth)) { if (cstyle.LinePattern != LinePattern.NotSet) pen.DashStyle = (DashStyle)cstyle.LinePattern; g.DrawRectangle(pen, r); } } } } #endregion #region RenderBubbleMarker private void RenderBubbleMarker(Graphics g, Rectangle bounds, ChartXy chartXy, ChartSeriesVisualStyle sstyle) { PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle; Background bk = pstyle.Background; Rectangle r = bounds; r.Inflate(-1, -1); using (Brush br = pstyle.Background.GetBrush(r)) { g.FillEllipse(br, r); if (pstyle.BorderColor.IsEmpty == false && pstyle.BorderWidth > 0) { using (Pen pen = new Pen(pstyle.BorderColor, pstyle.BorderWidth)) g.DrawEllipse(pen, r); } } } #endregion #region RenderDotMarker private void RenderDotMarker(Graphics g, Rectangle bounds, ChartXy chartXy, ChartSeriesVisualStyle sstyle) { PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle; Image marker = pstyle.GetPointMarkerImage(); if (marker != null) { g.DrawImage(marker, bounds); } else { marker = chartXy.GetPointMarker(g, pstyle.Type, pstyle.PointCount, bounds.Size, pstyle.Rotation, pstyle.Background, pstyle.BorderColor, pstyle.BorderWidth); if (marker != null) { // Make allowances for the fact that GetPointMarker() adjusts the // size and pos of the image to allow for better anti-aliasing bounds.X--; bounds.Y--; g.DrawImageUnscaled(marker, bounds); } else { RenderDefaultMarker(g, bounds, sstyle); } } } #endregion #region RenderLineMarker private void RenderLineMarker(Graphics g, Rectangle bounds, ChartXy chartXy, ChartSeriesVisualStyle sstyle) { ChartLineDisplayMode mode = GetLineDisplayMode(chartXy); int n = bounds.Height / 2; using (Pen pen = new Pen(GetLegendItemColor())) { g.DrawLine(pen, new Point(bounds.X, bounds.Y + n), new Point(bounds.Right - 1, bounds.Y + n)); } if ((mode & ChartLineDisplayMode.DisplayPoints) == ChartLineDisplayMode.DisplayPoints) { n = Math.Min(bounds.Height, bounds.Width); n = (int)Math.Ceiling((double)n / 2); if (n % 2 == 0) n++; Rectangle r = bounds; r.X += ((r.Width - n) / 2); r.Y += ((r.Height - n) / 2); r.Width = n; r.Height = n; PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle; Image marker2 = chartXy.GetPointMarker(g, pstyle.Type, pstyle.PointCount, r.Size, 0, pstyle.Background, pstyle.BorderColor, pstyle.BorderWidth > 0 ? 1 : 0); if (marker2 != null) { // Make allowances for the fact that GetPointMarker() adjusts the // size and pos of the image to allow for better anti-aliasing r.X--; r.Y--; g.DrawImageUnscaled(marker2, r); } else { RenderDefaultMarker(g, bounds, sstyle); } } } #endregion #endregion #endregion #region Copy/CopyTo public override ChartVisualElement Copy() { ChartSeries copy = new ChartSeries(); CopyTo(copy); return (copy); } public override void CopyTo(ChartVisualElement copy) { ChartSeries c = copy as ChartSeries; if (c != null) { base.CopyTo(c); c.AreaBaseValue = AreaBaseValue; c.AxisX = AxisX; c.AxisY = AxisY; c.BarFillRange = BarFillRange; c.BarLabelPosition = BarLabelPosition; c.BarShadingEnabled = BarShadingEnabled; c.BarWidthRatio = BarWidthRatio; c.BubbleIntensityMode = BubbleIntensityMode; c.BubbleMaxPercentage = BubbleMaxPercentage; c.BubbleMinSize = BubbleMinSize; c.BubbleScaleFactor = BubbleScaleFactor; c.BubbleSizeMode = BubbleSizeMode; foreach (ChartIndicator ci in ChartIndicators) c.ChartIndicators.Add((ChartIndicator)ci.Copy()); c.ChartLineAreaDisplayMode = ChartLineAreaDisplayMode; c.ChartLineDisplayMode = ChartLineDisplayMode; c.ChartSeriesVisualStyle = (_ChartSeriesVisualStyle != null) ? _ChartSeriesVisualStyle.Copy() : null; c.ConvexHullDisplayMode = ConvexHullDisplayMode; c.CrosshairEnabled = CrosshairEnabled; c.CrosshairHighlightPoints = CrosshairHighlightPoints; c.CrosshairShowLabels = CrosshairShowLabels; foreach (DataLabel dl in DataLabels) c.DataLabels.Add((DataLabel)dl.Copy()); c.DataLabelVisualStyle = (_DataLabelVisualStyle != null) ? _DataLabelVisualStyle.Copy() : null; c.DisplayLinePointsOnTop = DisplayLinePointsOnTop; c.DotPlotIndexValue = DotPlotIndexValue; c.EmptyValues = EmptyValues; c.EnableEmptyValues = EnableEmptyValues; c.GroupId = GroupId; c.HiLoBarType = HiLoBarType; c.CrosshairHighlightSinglePoint = CrosshairHighlightSinglePoint; c.PointLabelDisplayMode = PointLabelDisplayMode; c.PointLabelMinDistance = PointLabelMinDistance; c.PointLabelSkip = PointLabelSkip; c.ScaleTypeX = ScaleTypeX; c.ScaleTypeY = ScaleTypeY; foreach (SeriesPoint sp in SeriesPoints) c.SeriesPoints.Add(sp.Copy()); c.SeriesType = SeriesType; c.ShowEmptyLines = ShowEmptyLines; c.ShowEmptyPoints = ShowEmptyPoints; c.ShowHiLoBarMedianLines = ShowHiLoBarMedianLines; c.ShowOriginValueLabels = ShowOriginValueLabels; c.StackQualitativePoints = StackQualitativePoints; c.StepLines = StepLines; c.StepLineMode = StepLineMode; } } #endregion #region GetSerialData internal override SerialElementCollection GetSerialData(string serialName) { SerialElementCollection sec = new SerialElementCollection(); if (serialName != null) { if (serialName.Equals("") == true) serialName = "ChartSeries"; sec.AddStartElement(serialName); } sec.AddDataValue("AreaBaseValue", AreaBaseValue, null); if (AxisX != null && string.IsNullOrEmpty(AxisX.Name) == false) sec.AddValue("AxisX", AxisX.Name); if (AxisY != null && string.IsNullOrEmpty(AxisY.Name) == false) sec.AddValue("AxisY", AxisY.Name); sec.AddValue("BarFillRange", BarFillRange, BarFillRange.NotSet); sec.AddValue("BarLabelPosition", BarLabelPosition, BarLabelPosition.NotSet); sec.AddValue("BarShadingEnabled", BarShadingEnabled, Tbool.NotSet); sec.AddValue("BarWidthRatio", BarWidthRatio, 0d); sec.AddValue("BubbleIntensityMode", BubbleIntensityMode, BubbleIntensityMode.NotSet); sec.AddValue("BubbleMaxPercentage", BubbleMaxPercentage, 0.25d); sec.AddValue("BubbleMinSize", BubbleMinSize, 4); sec.AddValue("BubbleScaleFactor", BubbleScaleFactor, 1.0d); sec.AddValue("BubbleSizeMode", BubbleSizeMode, BubbleSizeMode.NotSet); if (_ChartIndicators != null && _ChartIndicators.Count > 0) { sec.AddStartElement("ChartIndicators count=\"" + _ChartIndicators.Count + "\""); foreach (ChartIndicator ci in _ChartIndicators) sec.AddElement(ci.GetSerialData("")); sec.AddEndElement("ChartIndicators"); } sec.AddValue("ChartLineAreaDisplayMode", ChartLineAreaDisplayMode, ChartLineAreaDisplayMode.NotSet); sec.AddValue("ChartLineDisplayMode", ChartLineDisplayMode, ChartLineDisplayMode.NotSet); if (_ChartSeriesVisualStyle != null) sec.AddElement(_ChartSeriesVisualStyle.GetSerialData("ChartSeriesVisualStyle")); sec.AddValue("ConvexHullDisplayMode", ConvexHullDisplayMode, ConvexHullDisplayMode.NotSet); sec.AddValue("CrosshairEnabled", CrosshairEnabled, Tbool.NotSet); sec.AddValue("CrosshairHighlightPoints", CrosshairHighlightPoints, Tbool.NotSet); sec.AddValue("CrosshairHighlightSinglePoint", CrosshairHighlightSinglePoint, Tbool.NotSet); sec.AddValue("CrosshairShowLabels", CrosshairShowLabels, Tbool.NotSet); if (_DataLabels != null && _DataLabels.Count > 0) { sec.AddStartElement("DataLabels count=\"" + _DataLabels.Count + "\""); foreach (DataLabel dl in _DataLabels) sec.AddElement(dl.GetSerialData("")); sec.AddEndElement("DataLabels"); } if (_DataLabelVisualStyle != null) sec.AddElement(_DataLabelVisualStyle.GetSerialData("DataLabelVisualStyle")); sec.AddValue("DisplayLinePointsOnTop", DisplayLinePointsOnTop, true); sec.AddValue("DotPlotIndexValue", DotPlotIndexValue, 1.0d); if (_EmptyValues != null && _EmptyValues.Length > 0) { sec.AddStartElement("EmptyValues count=\"" + _EmptyValues.Length + "\""); foreach (object value in _EmptyValues) sec.AddValue("EmptyValue", value); sec.AddEndElement("EmptyValues"); } sec.AddValue("EnableEmptyValues", EnableEmptyValues, false); sec.AddValue("GroupId", GroupId, 0); sec.AddValue("HiLoBarType", HiLoBarType, HiLoBarType.Box); sec.AddValue("PointLabelDisplayMode", PointLabelDisplayMode, PointLabelDisplayMode.NotSet); sec.AddValue("PointLabelMinDistance", PointLabelMinDistance, 0); sec.AddValue("PointLabelSkip", PointLabelSkip, 0); sec.AddValue("ScaleTypeX", ScaleTypeX, ScaleType.NotSet); sec.AddValue("ScaleTypeY", ScaleTypeY, ScaleType.NotSet); if (_SeriesPoints != null && _SeriesPoints.Count > 0) { sec.AddStartElement("SeriesPoints count=\"" + _SeriesPoints.Count + "\""); foreach (SeriesPoint sp in _SeriesPoints) sec.AddElement(sp.GetSerialData()); sec.AddEndElement("SeriesPoints"); } sec.AddValue("SeriesType", SeriesType, SeriesType.Point); sec.AddValue("ShowEmptyLines", ShowEmptyLines, false); sec.AddValue("ShowEmptyPoints", ShowEmptyPoints, false); sec.AddValue("ShowHiLoBarMedianLines", ShowHiLoBarMedianLines, false); sec.AddValue("ShowOriginValueLabels", ShowOriginValueLabels, true); sec.AddValue("StackQualitativePoints", StackQualitativePoints, true); sec.AddValue("StepLines", StepLines, StepLines.NotSet); sec.AddValue("StepLineMode", StepLineMode, StepLineMode.NotSet); sec.AddElement(base.GetSerialData(null)); if (serialName != null) sec.AddEndElement(serialName); return (sec); } #endregion #region PutSerialData #region ProcessValue internal override void ProcessValue(SerialElement se) { ChartXy chartXy = Parent as ChartXy; switch (se.Name) { case "AreaBaseValue": AreaBaseValue = se.DataValue; break; case "AxisX": if (chartXy != null) AxisX = GetAncillaryAxis(chartXy.AncillaryAxesX, se.GetValueString()); break; case "AxisY": if (chartXy != null) AxisY = GetAncillaryAxis(chartXy.AncillaryAxesY, se.GetValueString()); break; case "BarFillRange": BarFillRange = (BarFillRange)se.GetValueEnum(typeof(BarFillRange)); break; case "BarLabelPosition": BarLabelPosition = (BarLabelPosition)se.GetValueEnum(typeof(BarLabelPosition)); break; case "BarShadingEnabled": BarShadingEnabled = (Tbool)se.GetValueEnum(typeof(Tbool)); break; case "BarWidthRatio": BarWidthRatio = double.Parse(se.StringValue); break; case "BubbleIntensityMode": BubbleIntensityMode = (BubbleIntensityMode)se.GetValueEnum(typeof(BubbleIntensityMode)); break; case "BubbleMaxPercentage": BubbleMaxPercentage = double.Parse(se.StringValue); break; case "BubbleMinSize": BubbleMinSize = int.Parse(se.StringValue); break; case "BubbleScaleFactor": BubbleScaleFactor = double.Parse(se.StringValue); break; case "BubbleSizeMode": BubbleSizeMode = (BubbleSizeMode)se.GetValueEnum(typeof(BubbleSizeMode)); break; case "ChartLineAreaDisplayMode": ChartLineAreaDisplayMode = (ChartLineAreaDisplayMode)se.GetValueEnum(typeof(ChartLineAreaDisplayMode)); break; case "ChartLineDisplayMode": ChartLineDisplayMode = (ChartLineDisplayMode)se.GetValueEnum(typeof(ChartLineDisplayMode)); break; case "ConvexHullDisplayMode": ConvexHullDisplayMode = (ConvexHullDisplayMode)se.GetValueEnum(typeof(ConvexHullDisplayMode)); break; case "CrosshairEnabled": CrosshairEnabled = (Tbool)se.GetValueEnum(typeof(Tbool)); break; case "CrosshairHighlightPoints": CrosshairHighlightPoints = (Tbool)se.GetValueEnum(typeof(Tbool)); break; case "CrosshairHighlightSinglePoint": CrosshairHighlightSinglePoint = (Tbool)se.GetValueEnum(typeof(Tbool)); break; case "CrosshairShowLabels": CrosshairShowLabels = (Tbool)se.GetValueEnum(typeof(Tbool)); break; case "DisplayLinePointsOnTop": DisplayLinePointsOnTop = bool.Parse(se.StringValue); break; case "DotPlotIndexValue": DotPlotIndexValue = double.Parse(se.StringValue); break; case "EmptyValues": EmptyValues[se.ValueIndex] = se.DataValue; break; case "EnableEmptyValues": EnableEmptyValues = bool.Parse(se.StringValue); break; case "GroupId": GroupId = int.Parse(se.StringValue); break; case "HiLoBarType": HiLoBarType = (HiLoBarType)se.GetValueEnum(typeof(HiLoBarType)); break; case "PointLabelDisplayMode": PointLabelDisplayMode = (PointLabelDisplayMode)se.GetValueEnum(typeof(PointLabelDisplayMode)); break; case "PointLabelMinDistance": PointLabelMinDistance = int.Parse(se.StringValue); break; case "PointLabelSkip": PointLabelSkip = int.Parse(se.StringValue); break; case "ScaleTypeX": ScaleTypeX = (ScaleType)se.GetValueEnum(typeof(ScaleType)); break; case "ScaleTypeY": ScaleTypeY = (ScaleType)se.GetValueEnum(typeof(ScaleType)); break; case "SeriesType": SeriesType = (SeriesType)se.GetValueEnum(typeof(SeriesType)); break; case "ShowEmptyLines": ShowEmptyLines = bool.Parse(se.StringValue); break; case "ShowEmptyPoints": ShowEmptyPoints = bool.Parse(se.StringValue); break; case "ShowHiLoBarMedianLines": ShowHiLoBarMedianLines = bool.Parse(se.StringValue); break; case "ShowOriginValueLabels": ShowOriginValueLabels = bool.Parse(se.StringValue); break; case "StackQualitativePoints": StackQualitativePoints = bool.Parse(se.StringValue); break; case "StepLines": StepLines = (StepLines)se.GetValueEnum(typeof(StepLines)); break; case "StepLineMode": StepLineMode = (StepLineMode)se.GetValueEnum(typeof(StepLineMode)); break; default: base.ProcessValue(se); break; } } #region GetAncillaryAxis private ChartAxis GetAncillaryAxis(ChartAxesCollection axes, string name) { foreach (ChartAxis axis in axes) { if (name.Equals(axis.Name) == true) return (axis); } return (null); } #endregion #endregion #region ProcessCollection internal override void ProcessCollection(SerialElement se) { SerialElementCollection sec = se.Sec; switch (se.Name) { case "ChartIndicators": sec.PutSerialData(this); break; case "ChartSeriesVisualStyle": sec.PutSerialData(ChartSeriesVisualStyle); break; case "DataLabel": sec.PutSerialData(DataLabels[se.ValueIndex]); break; case "DataLabels": sec.PutSerialData(this); break; case "DataLabelVisualStyle": sec.PutSerialData(DataLabelVisualStyle); break; case "EmptyValues": if (se.ArrayCount > 0) { EmptyValues = new object[se.ArrayCount]; sec.PutSerialData(this); } break; case "RegressionLine": string rname = se.Sec.GetItemValue("Name"); RegressionLine reg = ChartIndicators[rname] as RegressionLine; if (reg != null) ChartIndicators.Remove(reg); reg = new RegressionLine(rname); if (reg != null) { sec.PutSerialData(reg); ChartIndicators.Add(reg); } break; case "SeriesPoints": if (se.ArrayCount > 0) { SeriesPoints = new SeriesPointCollection(); sec.PutSerialData(this); } break; case "SeriesPoint": SeriesPoint sp = new SeriesPoint(); sec.PutSerialData(sp); SeriesPoints.Add(sp); break; case "TrendLine": string tname = se.Sec.GetItemValue("Name"); TrendLine trend = ChartIndicators[tname] as TrendLine; if (trend != null) ChartIndicators.Remove(trend); trend = new TrendLine(tname); if (trend != null) { sec.PutSerialData(trend); ChartIndicators.Add(trend); } break; default: base.ProcessCollection(se); break; } } #endregion #endregion #region Series States [Flags] private enum States : uint { FilterIgnoreMatchCase = (1U << 0), CheckedInLegend = (1U << 1), ShowInLegend = (1U << 2), ShowInParentLegend = (1U << 3), ShowCheckBoxInLegend = (1U << 4), ShowMarkerInLegend = (1U << 5), IsSorted = (1U << 6), IsRotated = (1U << 7), StackQualitativePoints = (1U << 8), DisplayLinePointsOnTop = (1U << 9), EnableEmptyValues = (1U << 10), ShowEmptyLines = (1U << 11), ShowEmptyPoints = (1U << 12), ShowOriginValueLabels = (1U << 13), ShowHiLoBarMedianLines = (1U << 14), NeedToUpdateBindings = (1U << 15), IsInnerRingSeries = (1U << 16), IsOuterRingSeries = (1U << 17), IsOffset = (1U << 18), IsDetached = (1U << 19), ShowInnerRingsEx = (1U << 20), } #region TestState private bool TestState(States state) { return ((_States & state) == state); } #endregion #region SetState private void SetState(States state, bool value) { if (value == true) _States |= state; else _States &= ~state; } #endregion #endregion #region IDisposable public override void Dispose() { AxisX = null; AxisY = null; ChartIndicators = null; ChartLegendItemVisualStyles = null; ChartSeriesVisualStyle = null; DataLabels = null; DataLabelVisualStyle = null; SeriesPoints = null; base.Dispose(); } #endregion } #region SortedSeriesPoints public class SortedSeriesPoints { #region Private variables private ChartSeries _ChartSeries; private SeriesPointCollection _Spc; private int[] _IndexArray; private int[] _CountArray; private int _SeriesLayoutCount; private double _Slope = double.NaN; private double _Intercept = double.NaN; private bool _SlopeCalculated; private int _SlopeIndex; #endregion public SortedSeriesPoints(ChartSeries series, bool sortPoints) { _ChartSeries = series; _Spc = series.SeriesPoints; if (sortPoints == true) _IndexArray = CreateIndexArray(_Spc); } #region Public properties #region Count public int Count { get { if (_IndexArray != null) return (_IndexArray.Length); return (_Spc.Count); } } #endregion #region Indexer[int] public SeriesPoint this[int index] { get { if (_IndexArray != null) index = _IndexArray[index]; return (_Spc[index]); } } #endregion #region IsSorted public bool IsSorted { get { return (_ChartSeries.IsSorted); } } #endregion #region SeriesLayoutCount public int SeriesLayoutCount { get { return (_SeriesLayoutCount); } set { if (value != _SeriesLayoutCount) _SeriesLayoutCount = value; } } #endregion #endregion #region Internal properties #region CountArray internal int[] CountArray { get { return (_CountArray); } set { _CountArray = value; } } #endregion #region IndexArray internal int[] IndexArray { get { return (_IndexArray); } set { _IndexArray = value; } } #endregion #region Intercept internal double Intercept { get { if (_SlopeCalculated == false) CalcSeriesSlope(); return (_Intercept); } set { _Intercept = value; } } #endregion #region Slope internal double Slope { get { if (_SlopeCalculated == false) CalcSeriesSlope(); return (_Slope); } set { _Slope = value; } } #endregion #region SlopeIndex internal int SlopeIndex { get { return (_SlopeIndex); } set { if (_SlopeIndex != value) { _SlopeIndex = value; _SlopeCalculated = false; } } } #endregion #endregion #region CreateIndexArray private int[] CreateIndexArray(SeriesPointCollection spc) { int[] indexArray = new int[_Spc.Count]; object[] keyArray = new object[_Spc.Count]; for (int i = 0; i < _Spc.Count; i++) { indexArray[i] = i; keyArray[i] = _Spc[i].ValueX; } Array.Sort(keyArray, indexArray); return (indexArray); } #endregion #region SearchX public int SearchX(object okey) { ChartXy chartXy = _ChartSeries.Parent as ChartXy; if (IsSorted == true) { int min = 0; int max = Count - 1; while (min <= max) { int mid = (min + max) / 2; int cmp = chartXy.DataCompare(okey, this[mid].ValueX); if (cmp > 0) min = mid + 1; else if (cmp < 0) max = mid - 1; else return (mid); } return (-((min > 0) ? min - 1 : 0)); } else { for (int i = 0; i < Count; i++) { if (chartXy.DataCompare(okey, this[i].ValueX) == 0) return (i); } return (-1); } } #endregion #region SearchY public int SearchY(object okey) { ChartXy chartXy = _ChartSeries.Parent as ChartXy; for (int i = 0; i < _Spc.Count; i++) { if (_Spc[i].ValueY[0].Equals(okey)) return (i); } return (0); } #endregion #region GetQualitativeXIndex internal int GetQualitativeXIndex(object okey) { int index; if (okey is string) index = _ChartSeries.QualitativeXValues.IndexOf((string)okey); else index = Convert.ToInt32(okey); return (index); } #endregion #region GetQualitativeYIndex internal int GetQualitativeYIndex(object okey) { int index; if (okey is string) index = _ChartSeries.QualitativeYValues.IndexOf((string)okey); else index = Convert.ToInt32(okey); return (index); } #endregion #region CalcSeriesSlope private void CalcSeriesSlope() { ChartXy chartXy = _ChartSeries.Parent as ChartXy; if (chartXy != null) { ChartAxis axisX = _ChartSeries.AxisX ?? chartXy.AxisX; ChartAxis axisY = _ChartSeries.AxisY ?? chartXy.AxisY; if (_ChartSeries.ActualScaleTypeX != ScaleType.NotSet) { int n = Count; double sumX = 0; double sumY = 0; double sumXx = 0; double sumXy = 0; int nn = 0; for (int i = 0; i < n; i++) { SeriesPoint sp = this[i]; if (sp.IsEmpty == false && (sp.ValueY.Length > _SlopeIndex)) { nn++; double x; switch (_ChartSeries.ActualScaleTypeX) { case ScaleType.DateTime: x = chartXy.GetDateTimePointValue(axisX, axisX.TickmarkLayout, (DateTime)sp.ValueX, (DateTime)_ChartSeries.MinValueX); break; case ScaleType.Qualitative: x = _ChartSeries.QualitativeXValues.IndexOf(sp.ValueX); break; default: x = Convert.ToDouble(sp.ValueX); break; } double y; switch (_ChartSeries.ActualScaleTypeY) { case ScaleType.DateTime: y = chartXy.GetDateTimePointValue(axisY, axisY.TickmarkLayout, (DateTime)sp.ValueY[_SlopeIndex]); break; case ScaleType.Qualitative: y = _ChartSeries.QualitativeYValues.IndexOf(sp.ValueY[_SlopeIndex]); break; default: y = Convert.ToDouble(sp.ValueY[_SlopeIndex]); break; } sumX += x; sumY += y; sumXx += (x * x); sumXy += (x * y); } } double a = nn * sumXy; double b = sumX * sumY; double c = nn * sumXx; double d = sumX * sumX; double m = (a - b) / (c - d); double yi = (sumY - (m * sumX)) / nn; Slope = m; Intercept = yi; _SlopeCalculated = true; } } } #endregion #region GetSeriesPoint internal SeriesPoint GetSeriesPoint(object key) { if (Count > 0) { int index; if (this[0].IsQuantitativeXValue == true) index = SearchX(key); else index = GetQualitativeXIndex(key) - 1; if (index < 0 && IsSorted == true) index = -index; if ((uint)index < Count) return (this[index]); } return (null); } #endregion } #endregion #region PointData public class PointData { public List Points; public List SeriesPoints; } #endregion #region BubblePlotData internal class BubblePlotData { public double MinSize; public double MaxSize; public double TotalSize; public double MinIntensity; public double MaxIntensity; public void Clear() { MinSize = double.MaxValue; MaxSize = double.MinValue; MinIntensity = double.MaxValue; MaxIntensity = double.MinValue; TotalSize = 0; } } #endregion #region BarRenderData internal class BarRenderData { public ChartAxis Axis; public ChartXy ChartXy; public BarFillRange FillRange; public bool BarShading; public Point Spt; public SeriesPoint Sp; public ChartSeriesVisualStyle SeriesStyle; public BarRenderData(ChartXy chartXy, ChartAxis axis) { ChartXy = chartXy; Axis = axis; } } #endregion #region HiLoRenderData public class HiLoRenderData { #region Private variables private ChartAxis _Axis; private ChartXy _ChartXy; private Point _Spt; private SeriesPoint _Sp; private int _Index; private ChartSeriesVisualStyle _SeriesStyle; private int[] _Value; private bool _IsAlternate; private int _EndDelta; #endregion public HiLoRenderData(ChartXy chartXy, ChartAxis axis) { _ChartXy = chartXy; _Axis = axis; } #region Public properties #region AlternateStyle /// /// Gets the alternate segment style used when Open/Close values are reversed. /// public HiLoBarSegmentStyle AlternateStyle { get { return (SeriesStyle.HiLoBarVisualStyle.AlternateSegmentStyle); } } #endregion #region DefaultStyle /// /// Gets the default segment style used when Open/Close values are not reversed. /// public HiLoBarSegmentStyle DefaultStyle { get { return (SeriesStyle.HiLoBarVisualStyle.DefaultSegmentStyle); } } #endregion #region IsAlternate /// /// Gets whether the segment is to be render as 'Alternate'. /// public bool IsAlternate { get { return (_IsAlternate); } internal set { _IsAlternate = value; } } #endregion #region SeriesStyle /// /// Gets the associated series visual style. /// public ChartSeriesVisualStyle SeriesStyle { get { return (_SeriesStyle); } internal set { _SeriesStyle = value; } } #endregion #region Value /// /// Gets an array of specified HiLo coordinate data values (x or y, /// depending upon the bar orientation). The values are specified /// in [High=0, Low=1, Close=2, Open=3, Median=4] order, followed /// by any 'extra' user supplied bar values. /// public int[] Value { get { return (_Value); } internal set { _Value = value; } } #endregion #endregion #region Internal properties #region Axis internal ChartAxis Axis { get { return (_Axis); } set { _Axis = value; } } #endregion #region ChartXy internal ChartXy ChartXy { get { return (_ChartXy); } set { _ChartXy = value; } } #endregion #region EndDelta public int EndDelta { get { return (_EndDelta); } set { _EndDelta = value; } } #endregion #region Index internal int Index { get { return (_Index); } set { _Index = value; } } #endregion #region Sp internal SeriesPoint Sp { get { return (_Sp); } set { _Sp = value; } } #endregion #region Spt internal Point Spt { get { return (_Spt); } set { _Spt = value; } } #endregion #endregion } #endregion #region enums #region BarLabelPosition /// /// Specifies the position for Bar series labels. /// public enum BarLabelPosition { /// /// Not set (default is Center). /// NotSet = -1, /// /// Labels will be positioned in the center of the bar. /// Center, /// /// Labels will be positioned outside the bar, relative to its origin. /// Near, /// /// Labels will be positioned inside the bar, relative to its origin. /// NearInside, /// /// Labels will be positioned outside the bar, opposite to its origin. /// Far, /// /// Labels will be positioned inside the bar, opposite to its origin. /// FarInside, } #endregion #region BarSegment public enum BarSegment { /// /// Top portion of Vertical bar (full area). /// Top, /// /// Partial Top area of Vertical bar. /// TopPartial, /// /// Bottom portion of Vertical bar (full area). /// Bottom, /// /// Partial Bottom area of Vertical bar. /// BottomPartial, /// /// Left portion of Horizontal bar (full area). /// Left, /// /// Partial Left area of Horizontal bar. /// LeftPartial, /// /// Right portion of Horizontal bar (full area). /// Right, /// /// Partial Right area of Horizontal bar. /// RightPartial, } #endregion #region ConvexHullDisplayMode /// /// Specifies the ConvexHull display mode /// [Flags] public enum ConvexHullDisplayMode { /// /// Not set (default is None). /// NotSet = 0, /// /// No Convex Hull processing will take place. /// None = (1 << 0), /// /// Convex Hull border will be displayed. /// DisplayBorder = (1 << 1), /// /// Convex Hull background area will be displayed. /// DisplayBackground = (1 << 2), } #endregion #region PointLabelDisplayMode /// /// Specifies which PointLabels are to be displayed /// [Flags] public enum PointLabelDisplayMode { /// /// Not set (default is None). /// NotSet, /// /// No labels will be displayed. /// None = (1 << 0), /// /// All series points will display a label. /// AllSeriesPoints = (1 << 1), /// /// User defined DataLabels will be displayed. /// DataLabels = (1 << 2), /// /// Minimum 'X' Value label will be displayed. /// MinValueX = (1 << 3), /// /// Minimum 'Y' Value label will be displayed. /// MinValueY = (1 << 4), /// /// Maximum 'X' Value label will be displayed. /// MaxValueX = (1 << 5), /// /// Maximum 'Y' Value label will be displayed. /// MaxValueY = (1 << 6), } #endregion #region StepLineMode /// /// Specifies the mode used to render "Step Lines" in /// a given Line series. /// public enum StepLineMode { /// /// Not set (default is HorizontalThenVertical). /// NotSet = -1, /// /// No Step Lines will be rendered. /// None, /// /// Step lines will be displayed between consecutive /// series points, by first displaying the horizontal step /// line, followed by the connecting vertical step line. /// HorizontalThenVertical, /// /// Step lines will be displayed between consecutive /// series points, by first displaying the vertical step /// line, followed by the connecting horizontal step line. /// VerticalThenHorizontal, /// /// Step lines will be displayed between consecutive /// series points, by first displaying the midPoint horizontal /// step line, followed by the connecting vertical step line. /// MidPoint, } #endregion #region StepLines /// /// Specifies the mode used to render "Stepped Lines" in /// a given Line series. /// public enum StepLines { /// /// Not set (default is StepHv). /// NotSet = -1, /// /// No step lines will be displayed. /// None, /// /// Horizontal step lines will be displayed. /// Horizontal, /// /// Vertical step lines will be displayed. /// Vertical, /// /// Both horizontal and vertical step lines will be displayed. /// Both, } #endregion #region ScaleType /// /// Specifies the scale type for the series points /// public enum ScaleType { /// /// ScaleType is NotSet (default is 'Auto'). /// NotSet, /// /// ScaleType is Automatic. Scale type will be determined /// by the underlying, assigned data. /// Auto, /// /// DateTime data scale. Points will be treated as /// DateTime values and will be shown as such on the axis. /// DateTime, /// /// Numerical data scale. Points will be treated as /// numerical values and will be shown on the axis as numbers. /// Quantitative, /// /// Qualitative data scale. Points will be treated as /// qualitative values and will be shown on the axis as text. /// Qualitative, } #endregion #region HiLoBarType /// /// Specifies the HiloBar series display type. /// public enum HiLoBarType { /// /// Box Plot display. Display is identical to 'Candle' except: /// 1. Median separated segments are separately rendered using both /// default and alternate box backgrounds. /// 2. UseAlternateSegmentStyle defaults to false. /// Box, /// /// Candle Plot display. Display is identical to 'Box' except: /// 1. Mmedian separated segments are both rendered using either /// the default or alternate box background. /// 2. UseAlternateSegmentStyle defaults to true. /// Candle, /// /// Line plot display. /// Line, } #endregion #region HiLoBarSegment public enum HiLoBarSegment { /// /// Box (Box plot). /// Box, /// /// High whisker (Box, Candle, Line). /// HighWhisker, /// /// High whisker cap (Box, Candle, Line). /// HighWhiskerCap, /// /// Low whisker (Box, Candle, Line). /// LowWhisker, /// /// Low whisker cap (Box, Candle, Line). /// LowWhiskerCap, /// /// Open whisker (Line plot). /// OpenWhisker, /// /// Close whisker (Line Plot). /// CloseWhisker, /// /// Center line (Line plot). /// CenterLine, /// /// Full range (Line plot). /// FullRange, /// /// Median line (Box, Candle, Line). /// MedianLine, /// /// Bar shading (Box, Candle). /// BarShading, } #endregion #endregion #region AxisTypeConverter /// /// AxisTypeConverter /// public class AxisTypeConverter : TypeConverter { /// /// ConvertTo /// /// /// /// /// /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) { ChartAxis axis = value as ChartAxis; if (axis != null) { if (string.IsNullOrEmpty(axis.Name) == false) return (axis.Name); return ("No Axis Name"); } } return (base.ConvertTo(context, culture, value, destinationType)); } } #endregion }