10638 lines
316 KiB
C#
10638 lines
316 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Drawing.Design;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Globalization;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows.Forms;
|
|
using DevComponents.DotNetBar.Charts.Style;
|
|
|
|
namespace DevComponents.DotNetBar.Charts
|
|
{
|
|
/// <summary>
|
|
/// Represents the collection of ChartSeries.
|
|
/// </summary>
|
|
[Editor("DevComponents.Charts.Design.ChartSeriesCollectionEditor, DevComponents.Charts.Design, " +
|
|
"Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
|
|
public class ChartSeriesCollection : CustomNamedCollection<ChartSeries>
|
|
{
|
|
#region GetUniqueName
|
|
|
|
public string GetUniqueName()
|
|
{
|
|
return (GetUniqueName("Series"));
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
public class ChartSeries : ChartVisualElement, ILegendItem
|
|
{
|
|
#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 SeriesType _SeriesType = SeriesType.Point;
|
|
private SeriesPointCollection _SeriesPoints;
|
|
|
|
private PointData _PointData;
|
|
private PointData _EmptyPointData;
|
|
private PointData _StepPointData;
|
|
|
|
private object _DataSource;
|
|
private string _DataMember;
|
|
private DataBinder _DataBinder;
|
|
|
|
private string _DataPropertyNameSeries;
|
|
private string _DataPropertyNameX;
|
|
private CustomCollection<string> _DataPropertyNamesY;
|
|
|
|
private int _SeriesId;
|
|
private object _SeriesKey;
|
|
|
|
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 ChartLegendItemVisualStyles _ChartLegendItemVisualStyles;
|
|
|
|
private ChartSeriesVisualStyle _ChartSeriesVisualStyle;
|
|
private EffectiveStyle<ChartSeriesVisualStyle> _EffectiveChartSeriesStyle;
|
|
|
|
private DataLabelVisualStyle _DataLabelVisualStyle;
|
|
private EffectiveStyle<DataLabelVisualStyle> _EffectiveDataLabelStyle;
|
|
|
|
private Tbool _CrosshairEnabled = Tbool.NotSet;
|
|
private Tbool _CrosshairHighlightPoints = 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 string _LegendText;
|
|
private ChartLegendItem _LegendItem;
|
|
|
|
private object _MinValueX;
|
|
private object _MinValueY;
|
|
|
|
private object _MaxValueX;
|
|
private object _MaxValueY;
|
|
|
|
private object _AreaBaseValue;
|
|
|
|
private bool _SeriesRangeChanged = true;
|
|
private SortedSeriesPoints _SortedSeriesPoints;
|
|
private object[] _EmptyValues;
|
|
|
|
private List<object> _QualitativeXValues;
|
|
private List<object> _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 Color _DefaultPaletteColor = Color.Empty;
|
|
|
|
private DataLabelCollection _DataLabels;
|
|
private int _PointLabelSkip;
|
|
private int _PointLabelMinDistance;
|
|
|
|
private HiLoBarType _HiLoBarType = HiLoBarType.Box;
|
|
private Rectangle _RenderBounds;
|
|
|
|
#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<ChartSeriesVisualStyle>(this);
|
|
_EffectiveDataLabelStyle = new EffectiveStyle<DataLabelVisualStyle>(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);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
#region ActualScaleTypeX
|
|
|
|
///<summary>
|
|
/// Gets the Actual X axis Scale Type (may be
|
|
/// different than XScaleType when XScaleType is 'Auto').
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public ScaleType ActualScaleTypeX
|
|
{
|
|
get
|
|
{
|
|
if (IsRotated == false)
|
|
return (_ActualScaleTypeX);
|
|
|
|
return (_ActualScaleTypeY);
|
|
}
|
|
|
|
internal set { _ActualScaleTypeX = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ActualScaleTypeY
|
|
|
|
///<summary>
|
|
/// Gets the Actual Y axis Scale Type (may be
|
|
/// different than YScaleType when YScaleType is 'Auto').
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public ScaleType ActualScaleTypeY
|
|
{
|
|
get
|
|
{
|
|
if (IsRotated == true)
|
|
return (_ActualScaleTypeX);
|
|
|
|
return (_ActualScaleTypeY);
|
|
}
|
|
|
|
internal set { _ActualScaleTypeY = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AreaBaseValue
|
|
|
|
///<summary>
|
|
/// Gets or sets the base, reference value for displaying Line/Spline/Step Areas.
|
|
///</summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the X-Axis associated with the series.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the Y-Axis associated with the series.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets how series bars are filled (either according to
|
|
/// each individual bar range, or the entire series range).
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the position of bar series labels (default is Center).
|
|
/// </summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets whether Bar shading is enabled for Horizontal and Vertical Bar series.
|
|
///</summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// 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).
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the mode used to determine bubble intensities.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the max percentage of the display
|
|
/// area used to calculate series bubble sizes (default is .25).
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the minimum series bubble size (in pixels) Default is 4.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Scale Factor used to calculate series bubble sizes.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the mode used to calculate series bubble sizes.
|
|
/// </summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets a reference to the Chart Indicators collection.
|
|
///</summary>
|
|
[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 ChartLegendItemVisualStyles
|
|
|
|
/// <summary>
|
|
/// Gets or sets the visual styles for the Legend item.
|
|
/// </summary>
|
|
[Category("Style")]
|
|
[Description("Indicates the visual styles for the Legend item.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public ChartLegendItemVisualStyles ChartLegendItemVisualStyles
|
|
{
|
|
get
|
|
{
|
|
if (_ChartLegendItemVisualStyles == null)
|
|
{
|
|
_ChartLegendItemVisualStyles = new ChartLegendItemVisualStyles();
|
|
|
|
StyleVisualChangeHandler(null, _ChartLegendItemVisualStyles);
|
|
}
|
|
|
|
return (_ChartLegendItemVisualStyles);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_ChartLegendItemVisualStyles != value)
|
|
{
|
|
ChartLegendItemVisualStyles oldValue = _ChartLegendItemVisualStyles;
|
|
|
|
_ChartLegendItemVisualStyles = value;
|
|
|
|
OnStyleChanged("ChartLegendItemVisualStyles", oldValue, value);
|
|
|
|
if (oldValue != null)
|
|
oldValue.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ChartLineAreaDisplayMode
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Line 'Area' display mode.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Line ChartType display mode.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the visual style for the series.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the ConvexHull display mode.
|
|
/// </summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets whether Crosshair support is enabled for the series.
|
|
///</summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets whether Crosshair Point highlighting is enabled for the series.
|
|
///</summary>
|
|
[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 CrosshairShowLabels
|
|
|
|
///<summary>
|
|
/// Gets or sets whether Crosshair labels are shown for the series.
|
|
///</summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets the list of instance Data Labels.
|
|
///</summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the visual style for the data labels.
|
|
/// </summary>
|
|
[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 DataPropertyNameSeries
|
|
|
|
///<summary>
|
|
/// Gets or sets the name of the data field to which the Series Name is bound.
|
|
///</summary>
|
|
[DefaultValue(null), Category("Data")]
|
|
[Description("Indicates the name of the data field to which the Series Name is bound.")]
|
|
public string DataPropertyNameSeries
|
|
{
|
|
get { return (_DataPropertyNameSeries); }
|
|
|
|
set
|
|
{
|
|
if (value != _DataPropertyNameSeries)
|
|
{
|
|
_DataPropertyNameSeries = value;
|
|
|
|
if (NeedToUpdateBindings == false)
|
|
{
|
|
NeedToUpdateBindings = true;
|
|
|
|
InvalidateLayout();
|
|
}
|
|
|
|
OnPropertyChangedEx("DataPropertyNameSeries", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DataPropertyNameX
|
|
|
|
///<summary>
|
|
/// Gets or sets the name of the data field to which the X-Axis data is bound.
|
|
///</summary>
|
|
[DefaultValue(null), Category("Data")]
|
|
[Description("Indicates the name of the data field to which the X-Axis data is bound.")]
|
|
public string DataPropertyNameX
|
|
{
|
|
get { return (_DataPropertyNameX); }
|
|
|
|
set
|
|
{
|
|
if (value != _DataPropertyNameX)
|
|
{
|
|
_DataPropertyNameX = value;
|
|
|
|
if (NeedToUpdateBindings == false)
|
|
{
|
|
NeedToUpdateBindings = true;
|
|
|
|
InvalidateLayout();
|
|
}
|
|
|
|
OnPropertyChangedEx("DataPropertyNameX", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DataPropertyNamesY
|
|
|
|
///<summary>
|
|
/// Gets or sets the names of the data fields to which the Y-Axis data is bound.
|
|
///</summary>
|
|
[DefaultValue(null), Category("Data")]
|
|
[Description("Indicates the names of the data fields to which the Y-Axis data is bound.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public CustomCollection<string> DataPropertyNamesY
|
|
{
|
|
get
|
|
{
|
|
if (_DataPropertyNamesY == null)
|
|
{
|
|
_DataPropertyNamesY = new CustomCollection<string>();
|
|
|
|
_DataPropertyNamesY.CollectionChanged += DataPropertyNamesY_CollectionChanged;
|
|
}
|
|
|
|
return (_DataPropertyNamesY);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != _DataPropertyNamesY)
|
|
{
|
|
if (_DataPropertyNamesY != null)
|
|
{
|
|
_DataPropertyNamesY.Clear();
|
|
|
|
_DataPropertyNamesY.CollectionChanged -= DataPropertyNamesY_CollectionChanged;
|
|
}
|
|
|
|
_DataPropertyNamesY = value;
|
|
|
|
if (_DataPropertyNamesY != null)
|
|
_DataPropertyNamesY.CollectionChanged += DataPropertyNamesY_CollectionChanged;
|
|
|
|
OnPropertyChangedEx("DataPropertyNamesY", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DataPropertyNamesY_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
if (NeedToUpdateBindings == false)
|
|
{
|
|
NeedToUpdateBindings = true;
|
|
|
|
InvalidateLayout();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DataMember
|
|
|
|
///<summary>
|
|
/// Gets or sets the name of the list or table
|
|
/// in the data source that the Series is bound to.
|
|
///</summary>
|
|
[DefaultValue(null), Category("Data")]
|
|
[Description("Indicates the name of the list or table in the data source that the Series is bound to.")]
|
|
public string DataMember
|
|
{
|
|
get { return (_DataMember); }
|
|
|
|
set
|
|
{
|
|
if (_DataBinder != null)
|
|
_DataBinder.Clear();
|
|
|
|
_DataMember = value;
|
|
|
|
NeedToUpdateBindings = true;
|
|
|
|
OnPropertyChangedEx("DataMember", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DataSource
|
|
|
|
///<summary>
|
|
/// Gets or sets the data source that the Series is bound to.
|
|
///</summary>
|
|
[DefaultValue(null), AttributeProvider(typeof(IListSource)), Category("Data")]
|
|
[Description("Indicates the data source that the Series is bound to.")]
|
|
public object DataSource
|
|
{
|
|
get { return (_DataSource); }
|
|
|
|
set
|
|
{
|
|
if (_DataBinder != null)
|
|
_DataBinder.Clear();
|
|
|
|
_DataSource = value;
|
|
|
|
NeedToUpdateBindings = true;
|
|
|
|
OnPropertyChangedEx("DataSource", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DefaultPaletteColor
|
|
|
|
/// <summary>
|
|
/// Gets the default palette color assigned to the series when it
|
|
/// is added to the chart.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[Description("Indicates the default palette color assigned to the series when it is added to the chart.")]
|
|
public Color DefaultPaletteColor
|
|
{
|
|
get { return (_DefaultPaletteColor); }
|
|
|
|
internal set
|
|
{
|
|
if (value != _DefaultPaletteColor)
|
|
{
|
|
_DefaultPaletteColor = value;
|
|
|
|
InvalidateStyle();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DisplayLinePointsOnTop
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether series points are displayed on top of series line.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the value used to index between DotPlot points. Default is 1.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the DataLabel effective (cached, composite) style.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public DataLabelVisualStyle EffectiveDataLabelStyle
|
|
{
|
|
get { return (_EffectiveDataLabelStyle.Style); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EffectiveSeriesStyle
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the Series's effective (cached, composite) style.
|
|
/// </summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets the value(s) used to determine if
|
|
/// a series point is empty or missing.
|
|
///</summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether EmptyValues are processed in the series
|
|
/// </summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets the logical grouping Id used to group qualitative series.
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public int GroupId
|
|
{
|
|
get { return (_GroupId); }
|
|
|
|
set
|
|
{
|
|
if (value != _GroupId)
|
|
{
|
|
_GroupId = value;
|
|
|
|
OnPropertyChangedEx("GroupId", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region HiLoBarType
|
|
|
|
///<summary>
|
|
/// Gets or sets the Series HiLoBar Type.
|
|
///</summary>
|
|
[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 IsDisplayed
|
|
|
|
///<summary>
|
|
/// Gets whether the series is displayed (based upon Visibility and Legend state).
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public bool IsDisplayed
|
|
{
|
|
get
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
ItemCheckAction ica = (chartXy != null)
|
|
? chartXy.Legend.ItemCheckAction : ItemCheckAction.ShowItem;
|
|
|
|
return ((Visible == true) &&
|
|
(ica == ItemCheckAction.None ||
|
|
(ShowCheckBoxInLegend == false || CheckedInLegend == true)));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MaxValueX
|
|
|
|
///<summary>
|
|
/// Gets the series Maximum X value.
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public object MaxValueX
|
|
{
|
|
get
|
|
{
|
|
UpdateSeriesRange();
|
|
|
|
if (IsRotated == true)
|
|
return (_MaxValueY);
|
|
|
|
return (_MaxValueX);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MaxValueY
|
|
|
|
///<summary>
|
|
/// Gets the series Maximum Y value.
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public object MaxValueY
|
|
{
|
|
get
|
|
{
|
|
UpdateSeriesRange();
|
|
|
|
if (IsRotated == true)
|
|
return (_MaxValueX);
|
|
|
|
return (_MaxValueY);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinValueX
|
|
|
|
///<summary>
|
|
/// Gets the series minimum X value.
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public object MinValueX
|
|
{
|
|
get
|
|
{
|
|
UpdateSeriesRange();
|
|
|
|
if (IsRotated == true)
|
|
return (_MinValueY);
|
|
|
|
return (_MinValueX);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinValueY
|
|
|
|
///<summary>
|
|
/// Gets the series minimum Y value.
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public object MinValueY
|
|
{
|
|
get
|
|
{
|
|
UpdateSeriesRange();
|
|
|
|
if (IsRotated == true)
|
|
return (_MinValueX);
|
|
|
|
return (_MinValueY);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PointLabelDisplayMode
|
|
|
|
/// <summary>
|
|
/// Gets or sets the display mode for the chart PointLabels.
|
|
/// </summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets the minimum distance between label data points.
|
|
///</summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets the number of inter-label points to skip.
|
|
///</summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets the X axis Scale Type.
|
|
///</summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets the Y axis Scale Type.
|
|
///</summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets the series point data collection
|
|
///</summary>
|
|
[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
|
|
|
|
///<summary>
|
|
/// Gets or sets the Series Type.
|
|
///</summary>
|
|
[DefaultValue(SeriesType.Point), Category("Appearance")]
|
|
[Description("Indicates the Series Type.")]
|
|
public SeriesType SeriesType
|
|
{
|
|
get { return (_SeriesType); }
|
|
|
|
set
|
|
{
|
|
if (value != _SeriesType)
|
|
{
|
|
_SeriesType = value;
|
|
|
|
IsRotated = (
|
|
SeriesType == SeriesType.HorizontalDot ||
|
|
SeriesType == SeriesType.HorizontalBar ||
|
|
SeriesType == SeriesType.HorizontalHiLoBar);
|
|
|
|
BaseChart chart = Parent as BaseChart;
|
|
|
|
if (chart != null)
|
|
{
|
|
SeriesRangeChanged = true;
|
|
chart.SeriesRangeChanged = true;
|
|
}
|
|
|
|
OnPropertyChangedEx("SeriesType", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowHiLoBarMedianLines
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether defined HiLoBar Median lines are shown.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether EmptyLines are shown in the series.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether EmptyPoints are shown in the series.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether labels are shown for 'Origin' data values.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether Qualitative points are
|
|
/// stacked or spread across the associated grouped column.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets which 'Step lines' are displayed.
|
|
/// </summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// Gets or sets the mode used to render "Step Lines" in
|
|
/// the defined Line series.
|
|
/// </summary>
|
|
[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 DataBinder
|
|
|
|
internal DataBinder DataBinder
|
|
{
|
|
get
|
|
{
|
|
if (_DataBinder == null)
|
|
_DataBinder = new DataBinder(this);
|
|
|
|
return (_DataBinder);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_DataBinder != null)
|
|
_DataBinder.Clear();
|
|
|
|
_DataBinder = 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 NeedToUpdateBindings
|
|
|
|
internal bool NeedToUpdateBindings
|
|
{
|
|
get { return (TestState(States.NeedToUpdateBindings)); }
|
|
set { SetState(States.NeedToUpdateBindings, 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<object> QualitativeXValues
|
|
{
|
|
get
|
|
{
|
|
if (_QualitativeXValues == null)
|
|
_QualitativeXValues = new List<object>();
|
|
|
|
return (_QualitativeXValues);
|
|
}
|
|
|
|
set { _QualitativeXValues = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region QualitativeYValues
|
|
|
|
internal List<object> QualitativeYValues
|
|
{
|
|
get
|
|
{
|
|
if (_QualitativeYValues == null)
|
|
_QualitativeYValues = new List<object>();
|
|
|
|
return (_QualitativeYValues);
|
|
}
|
|
|
|
set { _QualitativeYValues = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SeriesId
|
|
|
|
internal int SeriesId
|
|
{
|
|
get { return (_SeriesId); }
|
|
set { _SeriesId = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SeriesKey
|
|
|
|
internal object SeriesKey
|
|
{
|
|
get { return (_SeriesKey); }
|
|
set { _SeriesKey = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SeriesRangeChanged
|
|
|
|
internal bool SeriesRangeChanged
|
|
{
|
|
get { return (_SeriesRangeChanged); }
|
|
|
|
set
|
|
{
|
|
if (value != _SeriesRangeChanged)
|
|
{
|
|
_SeriesRangeChanged = value;
|
|
|
|
if (value == true)
|
|
{
|
|
BaseChart chart = Parent as BaseChart;
|
|
|
|
if (chart != null)
|
|
chart.SeriesRangeChanged = true;
|
|
|
|
_SortedSeriesPoints = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
UpdateDataBindings();
|
|
UpdateMarkerImage(layoutInfo.Graphics);
|
|
}
|
|
|
|
#region UpdateDataBindings
|
|
|
|
internal void UpdateDataBindings()
|
|
{
|
|
if (NeedToUpdateBindings == true)
|
|
{
|
|
BaseChart chart = Parent as BaseChart;
|
|
|
|
object dataSource = DataSource ?? chart.DataSource;
|
|
string dataMember = (string.IsNullOrEmpty(DataMember) == false) ? DataMember : chart.DataMember;
|
|
|
|
if (dataSource != null)
|
|
{
|
|
SeriesPoints.Clear();
|
|
|
|
DataBinder dataBinder = DataBinder;
|
|
|
|
dataBinder.Clear();
|
|
|
|
dataBinder.DataConnect(dataSource, dataMember);
|
|
dataBinder.LoadSeriesData(this);
|
|
}
|
|
|
|
NeedToUpdateBindings = false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#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 : AMath.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
|
|
: (AMath.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)
|
|
{
|
|
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;
|
|
|
|
_RenderBounds = chartXy.ContentBounds;
|
|
_RenderBounds.Location = chartXy.GetGlobalAdjustedPoint(_RenderBounds.Location);
|
|
|
|
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<int> cList = new List<int>();
|
|
List<int> iList = new List<int>();
|
|
|
|
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
|
|
{
|
|
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 = (chartXy.IsCrosshairSeriesPoint(this, ppt2))
|
|
? GetHighlightImage(g, chartXy, hstyle) : PointMarkerImage;
|
|
|
|
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<Point[]> 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<PointLabelGroup> 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<Point[]>();
|
|
|
|
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<Point[]> 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#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 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<Point[]>();
|
|
pd.SeriesPoints = new List<SeriesPoint[]>();
|
|
|
|
if (EnableEmptyValues == true)
|
|
{
|
|
PointData epd = new PointData();
|
|
|
|
epd.Points = new List<Point[]>();
|
|
epd.SeriesPoints = new List<SeriesPoint[]>();
|
|
|
|
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<object> stack = new Stack<object>();
|
|
|
|
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)AMath.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 RefreshSeries
|
|
|
|
///<summary>
|
|
/// Causes the series to refresh its display, as the underlying
|
|
/// series data (potentially) has changed in some way.
|
|
///</summary>
|
|
public void RefreshSeries()
|
|
{
|
|
SeriesRangeChanged = true;
|
|
|
|
InvalidateLayout();
|
|
}
|
|
|
|
#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)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
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(chartXy, sp, ref dataTypeX);
|
|
|
|
switch (SeriesType)
|
|
{
|
|
case SeriesType.VerticalDot:
|
|
case SeriesType.HorizontalDot:
|
|
ActualScaleTypeY = ScaleType.Quantitative;
|
|
break;
|
|
|
|
case SeriesType.Bubble:
|
|
UpdateYBubbleRange(chartXy, sp, ref dataTypeY);
|
|
break;
|
|
|
|
default:
|
|
UpdateYValueRange(chartXy, 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(ChartXy chartXy, 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 (chartXy.DataCompare(value, _MaxValueX) >= 0)
|
|
{
|
|
_MaxValueX = value;
|
|
|
|
if (_CmpLast == 0)
|
|
_CmpLast = 1;
|
|
|
|
else if (_CmpLast < 0)
|
|
IsSorted = false;
|
|
}
|
|
else
|
|
{
|
|
if (chartXy.DataCompare(value, _MinValueX) <= 0)
|
|
_MinValueX = value;
|
|
|
|
if (_CmpLast == 0)
|
|
_CmpLast = -1;
|
|
|
|
else if (_CmpLast > 0)
|
|
IsSorted = false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateYBubbleRange
|
|
|
|
private void UpdateYBubbleRange(ChartXy chartXy, 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(chartXy, 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(ChartXy chartXy, 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(chartXy, 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<object, double> pd = new Dictionary<object, double>();
|
|
|
|
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<object, double> kvp in pd)
|
|
{
|
|
if (kvp.Value > maxValue)
|
|
maxValue = kvp.Value;
|
|
}
|
|
|
|
_MinValueY = 0.0;
|
|
_MaxValueY = maxValue;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ProcessYValueRange
|
|
|
|
private void ProcessYValueRange(ChartXy chartXy, 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 = chartXy.DataCompare(value, _MaxValueY);
|
|
|
|
if (cmpMax >= 0)
|
|
{
|
|
_MaxValueY = value;
|
|
}
|
|
else
|
|
{
|
|
int cmpMin = chartXy.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 GetBarWidthRatio
|
|
|
|
internal double GetBarWidthRatio(ChartXy chartXy)
|
|
{
|
|
return (_BarWidthRatio > 0 ? _BarWidthRatio :
|
|
(chartXy.BarWidthRatio > 0 ? chartXy.BarWidthRatio : 1));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetPointLabels
|
|
|
|
internal List<PointLabel> 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<PointLabel> plabels = new List<PointLabel>();
|
|
|
|
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
|
|
|
|
/// <summary>
|
|
/// Gets the collection of series PointData for the given PointLabelDisplayType.
|
|
/// </summary>
|
|
/// <param name="plmode"></param>
|
|
/// <returns></returns>
|
|
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<Point[]>();
|
|
pd.SeriesPoints = new List<SeriesPoint[]>();
|
|
|
|
if ((displayType & PointLabelDisplayMode.AllSeriesPoints) == PointLabelDisplayMode.AllSeriesPoints)
|
|
GetPointList(chartXy, ssp, index, count, _PointLabelSkip, _PointLabelMinDistance, false, pd);
|
|
|
|
else if ((displayType & ~PointLabelDisplayMode.AllSeriesPoints) != 0)
|
|
{
|
|
List<SeriesPoint> lmmsp = new List<SeriesPoint>();
|
|
|
|
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<PointLabel> 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<PointLabel> 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":
|
|
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
|
|
|
|
/// <summary>
|
|
/// Determines whether the given SeriesPoint is a ConvexHull point.
|
|
/// </summary>
|
|
/// <param name="sp"></param>
|
|
/// <returns></returns>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Determines if the given SeriesPoint is a HighLight Point (a
|
|
/// point highlighted by the Crosshair setup).
|
|
/// </summary>
|
|
/// <param name="sp"></param>
|
|
/// <returns></returns>
|
|
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
|
|
|
|
internal 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 BaseChart)
|
|
pstyle.ApplyStyle(((BaseChart)item).ChartSeriesVisualStyle);
|
|
|
|
if (item is ChartPanel)
|
|
pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.ChartSeriesVisualStyle);
|
|
}
|
|
else
|
|
{
|
|
pstyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartPanelVisualStyle);
|
|
pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartPanelVisualStyle);
|
|
}
|
|
}
|
|
|
|
#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(((BaseChart)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 InvalidateStyle
|
|
|
|
///<summary>
|
|
///Invalidate the cached Style definition
|
|
///</summary>
|
|
public void InvalidateStyle()
|
|
{
|
|
if (_EffectiveChartSeriesStyle.InvalidateStyle() == true)
|
|
InvalidateLayout();
|
|
|
|
_EffectiveDataLabelStyle.InvalidateStyle();
|
|
|
|
foreach (DataLabel dl in DataLabels)
|
|
dl.InvalidateStyle();
|
|
|
|
PointMarkerImage = null;
|
|
PointMarkerEmptyImage = null;
|
|
PointMarkerHighlightImage = null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ClearEffectiveStyles
|
|
|
|
protected override void ClearEffectiveStyles()
|
|
{
|
|
_EffectiveChartSeriesStyle.InvalidateStyle();
|
|
_EffectiveDataLabelStyle.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 InvalidateRender
|
|
|
|
public override void InvalidateRender()
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
if (chartXy != null)
|
|
chartXy.InvalidateRender();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ILegendItem
|
|
|
|
#region CheckedInLegend
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether the series is checked in the Legend.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Legend")]
|
|
[Description("Indicates whether the series is checked in the Legend.")]
|
|
public bool CheckedInLegend
|
|
{
|
|
get { return (TestState(States.CheckedInLegend)); }
|
|
|
|
set
|
|
{
|
|
if (value != CheckedInLegend)
|
|
{
|
|
SetState(States.CheckedInLegend, value);
|
|
|
|
if (IsQualitativeXValues || IsQualitativeYValues)
|
|
InvalidateLayout();
|
|
|
|
if (PointLabelDisplayMode != PointLabelDisplayMode.None)
|
|
InvalidatePointLabels();
|
|
|
|
if (LegendItem != null)
|
|
LegendItem.UpdateCheckState();
|
|
|
|
OnPropertyChangedEx("CheckedInLegend", VisualChangeType.Render);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowCheckBoxInLegend
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether a checkbox for the series is shown in the Legend.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Legend")]
|
|
[Description("Indicates whether a checkbox for the series is shown in the Legend.")]
|
|
public bool ShowCheckBoxInLegend
|
|
{
|
|
get { return (TestState(States.ShowCheckBoxInLegend)); }
|
|
|
|
set
|
|
{
|
|
if (value != ShowCheckBoxInLegend)
|
|
{
|
|
SetState(States.ShowCheckBoxInLegend, value);
|
|
|
|
OnPropertyChangedEx("ShowCheckBoxInLegend", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowInLegend
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether the series is shown in the Legend.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Legend")]
|
|
[Description("Indicates whether the series is shown in the Legend.")]
|
|
public bool ShowInLegend
|
|
{
|
|
get { return (TestState(States.ShowInLegend)); }
|
|
|
|
set
|
|
{
|
|
if (value != ShowInLegend)
|
|
{
|
|
SetState(States.ShowInLegend, value);
|
|
|
|
OnPropertyChangedEx("ShowInLegend", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowInParentLegend
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether the series is shown in parent Legend(s).
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Legend")]
|
|
[Description("Indicates whether the series is shown in parent Legend(s).")]
|
|
public bool ShowInParentLegend
|
|
{
|
|
get { return (TestState(States.ShowInParentLegend)); }
|
|
|
|
set
|
|
{
|
|
if (value != ShowInParentLegend)
|
|
{
|
|
SetState(States.ShowInParentLegend, value);
|
|
|
|
OnPropertyChangedEx("ShowInParentLegend", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowMarkerInLegend
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether the series Marker is shown in the Legend.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Legend")]
|
|
[Description("Indicates whether the series Marker is shown in the Legend.")]
|
|
public bool ShowMarkerInLegend
|
|
{
|
|
get { return (TestState(States.ShowMarkerInLegend)); }
|
|
|
|
set
|
|
{
|
|
if (value != ShowMarkerInLegend)
|
|
{
|
|
SetState(States.ShowMarkerInLegend, value);
|
|
|
|
OnPropertyChangedEx("ShowMarkerInLegend", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LegendItem
|
|
|
|
///<summary>
|
|
/// Gets the item's parent LegendItem.
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[Description("Indicates the item's parent LegendItem.")]
|
|
public ChartLegendItem LegendItem
|
|
{
|
|
get { return (_LegendItem); }
|
|
|
|
internal set
|
|
{
|
|
if (_LegendItem != null)
|
|
_LegendItem.Dispose();
|
|
|
|
_LegendItem = value;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LegendText
|
|
|
|
///<summary>
|
|
/// Gets or sets the text to display in the legend.
|
|
///</summary>
|
|
[DefaultValue(null), Category("Legend")]
|
|
[Description("Indicates the text to display in the legend.")]
|
|
public string LegendText
|
|
{
|
|
get { return (_LegendText); }
|
|
|
|
set
|
|
{
|
|
if (value != _LegendText)
|
|
{
|
|
_LegendText = value;
|
|
|
|
OnPropertyChangedEx("LegendText", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetLegendItem
|
|
|
|
public ChartLegendItem GetLegendItem()
|
|
{
|
|
LegendItem = null;
|
|
|
|
if (ShowInLegend == true)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
LegendItem = new ChartLegendItem();
|
|
|
|
if (CheckedInLegend == true)
|
|
_LegendItem.CheckState = CheckState.Checked;
|
|
|
|
_LegendItem.Parent = chartXy.Legend;
|
|
|
|
_LegendItem.Name = Name;
|
|
_LegendItem.ItemText = LegendText;
|
|
|
|
if (string.IsNullOrEmpty(_LegendItem.Name) == true)
|
|
_LegendItem.Name = "(Series)";
|
|
|
|
_LegendItem.ChartItems.Add(this);
|
|
}
|
|
|
|
return (_LegendItem);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetLegendItems
|
|
|
|
public List<ChartLegendItem> GetLegendItems()
|
|
{
|
|
List<ChartLegendItem> list = new List<ChartLegendItem>();
|
|
|
|
ChartLegendItem item = GetLegendItem();
|
|
|
|
if (item != null)
|
|
list.Add(item);
|
|
|
|
foreach (ChartIndicator ci in ChartIndicators)
|
|
{
|
|
if (ci.Visible == true)
|
|
{
|
|
ChartLegendItem li = ci.GetLegendItem();
|
|
|
|
if (li != null)
|
|
list.Add(li);
|
|
}
|
|
}
|
|
|
|
return (list);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetLegendItemColor
|
|
|
|
public Color GetLegendItemColor()
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
ChartLegendItemVisualStyle lstyle = ChartLegendItemVisualStyles[StyleType.Default];
|
|
|
|
if (lstyle.TextColor.IsEmpty == false)
|
|
return (lstyle.TextColor);
|
|
|
|
Color color = Color.Empty;
|
|
|
|
ChartSeriesVisualStyle sstyle = EffectiveChartSeriesStyle;
|
|
|
|
if (sstyle.ItemColor.IsEmpty == false)
|
|
return (sstyle.ItemColor);
|
|
|
|
PointMarkerVisualStyle pstyle = sstyle.MarkerVisualStyle;
|
|
|
|
switch (SeriesType)
|
|
{
|
|
case SeriesType.Bubble:
|
|
case SeriesType.Point:
|
|
case SeriesType.HorizontalDot:
|
|
case SeriesType.VerticalDot:
|
|
color = pstyle.Background.Color1;
|
|
break;
|
|
|
|
case SeriesType.Line:
|
|
ChartLineDisplayMode mode = GetLineDisplayMode(chartXy);
|
|
|
|
if ((mode & ChartLineDisplayMode.DisplayLine) == ChartLineDisplayMode.DisplayLine)
|
|
color = sstyle.LineStyle.LineColor;
|
|
|
|
else if ((mode & ChartLineDisplayMode.DisplaySpline) == ChartLineDisplayMode.DisplaySpline)
|
|
color = sstyle.SplineStyle.LineColor;
|
|
|
|
else if ((mode & ChartLineDisplayMode.DisplayStepLine) == ChartLineDisplayMode.DisplayStepLine)
|
|
color = sstyle.StepLineStyle.LineColor;
|
|
|
|
if (color.IsEmpty == true)
|
|
color = pstyle.Background.Color1;
|
|
break;
|
|
|
|
case SeriesType.HorizontalBar:
|
|
case SeriesType.VerticalBar:
|
|
ChartBarVisualStyle bstyle = sstyle.BarVisualStyle;
|
|
color = bstyle.Background.Color1;
|
|
break;
|
|
|
|
case SeriesType.HorizontalHiLoBar:
|
|
case SeriesType.VerticalHiLoBar:
|
|
HiLoBarSegmentStyle hstyle = sstyle.HiLoBarVisualStyle.DefaultSegmentStyle;
|
|
|
|
if (HiLoBarType == HiLoBarType.Line)
|
|
{
|
|
color = hstyle.Default.LineColor;
|
|
|
|
if (color.IsEmpty == true)
|
|
color = hstyle.CenterLine.LineColor;
|
|
}
|
|
else
|
|
{
|
|
color = hstyle.BoxBackground.Color1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (color.IsEmpty == true)
|
|
color = _DefaultPaletteColor;
|
|
|
|
return (color);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderLegendItemMarker
|
|
|
|
public void RenderLegendItemMarker(Graphics g,
|
|
ChartLegendItem litem, ChartLegendItemVisualStyle style)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
ChartSeriesVisualStyle sstyle = EffectiveChartSeriesStyle;
|
|
|
|
Rectangle bounds = litem.MarkerBounds;
|
|
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
|
|
|
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;
|
|
}
|
|
|
|
g.SmoothingMode = sm;
|
|
}
|
|
|
|
#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
|
|
|
|
#region RenderDefaultMarker
|
|
|
|
private void RenderDefaultMarker(Graphics g,
|
|
Rectangle bounds, ChartSeriesVisualStyle sstyle)
|
|
{
|
|
bounds.Width++;
|
|
bounds.Height++;
|
|
|
|
Background background = sstyle.MarkerVisualStyle.Background;
|
|
|
|
if (background.IsEmpty == true)
|
|
{
|
|
g.FillRectangle(Brushes.DimGray, bounds);
|
|
}
|
|
else
|
|
{
|
|
using (Brush br = background.GetBrush(bounds))
|
|
g.FillRectangle(br, bounds);
|
|
}
|
|
}
|
|
|
|
#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.AxisX = AxisX;
|
|
c.AxisY = AxisY;
|
|
|
|
c.AreaBaseValue = AreaBaseValue;
|
|
|
|
c.BarFillRange = BarFillRange;
|
|
c.BarLabelPosition = BarLabelPosition;
|
|
c.BarShadingEnabled = BarShadingEnabled;
|
|
c.BarWidthRatio = BarWidthRatio;
|
|
|
|
c.BubbleIntensityMode = BubbleIntensityMode;
|
|
c.BubbleScaleFactor = BubbleScaleFactor;
|
|
c.BubbleSizeMode = BubbleSizeMode;
|
|
|
|
foreach (ChartIndicator ci in ChartIndicators)
|
|
c.ChartIndicators.Add((ChartIndicator)ci.Copy());
|
|
|
|
c.ChartLegendItemVisualStyles =
|
|
(_ChartLegendItemVisualStyles != null) ? ChartLegendItemVisualStyles.Copy() : null;
|
|
|
|
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.DataPropertyNameSeries = DataPropertyNameSeries;
|
|
c.DataPropertyNameX = DataPropertyNameX;
|
|
c.DataPropertyNamesY = DataPropertyNamesY;
|
|
|
|
c.DataMember = DataMember;
|
|
c.DataSource = DataSource;
|
|
|
|
c.DefaultPaletteColor = DefaultPaletteColor;
|
|
c.DisplayLinePointsOnTop = DisplayLinePointsOnTop;
|
|
c.DotPlotIndexValue = DotPlotIndexValue;
|
|
c.EmptyValues = EmptyValues;
|
|
c.EnableEmptyValues = EnableEmptyValues;
|
|
c.GroupId = GroupId;
|
|
|
|
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;
|
|
|
|
c.CheckedInLegend = CheckedInLegend;
|
|
c.LegendText = LegendText;
|
|
c.ShowCheckBoxInLegend = ShowCheckBoxInLegend;
|
|
c.ShowInLegend = ShowInLegend;
|
|
c.ShowInParentLegend = ShowInParentLegend;
|
|
c.ShowMarkerInLegend = ShowMarkerInLegend;
|
|
}
|
|
}
|
|
|
|
#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);
|
|
}
|
|
|
|
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.AddDataValue("AreaBaseValue", AreaBaseValue, null);
|
|
|
|
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("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");
|
|
}
|
|
|
|
if (_ChartLegendItemVisualStyles != null)
|
|
sec.AddElement(_ChartLegendItemVisualStyles.GetSerialData("ChartLegendItemVisualStyles"));
|
|
|
|
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("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.AddDataValue("DataSource", DataSource, null);
|
|
sec.AddValue("DataMember", DataMember, null);
|
|
|
|
sec.AddValue("DataPropertyNameSeries", DataPropertyNameSeries, null);
|
|
sec.AddValue("DataPropertyNameX", DataPropertyNameX, null);
|
|
|
|
if (_DataPropertyNamesY != null && _DataPropertyNamesY.Count > 0)
|
|
{
|
|
sec.AddStartElement("DataPropertyNamesYs count=\"" + _DataPropertyNamesY.Count + "\"");
|
|
|
|
foreach (string s in _DataPropertyNamesY)
|
|
sec.AddValue("DataPropertyNamesY", s);
|
|
|
|
sec.AddEndElement("DataPropertyNamesYs");
|
|
}
|
|
|
|
sec.AddValue("DefaultPaletteColor", DefaultPaletteColor, Color.Empty);
|
|
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.AddValue("CheckedInLegend", CheckedInLegend, true);
|
|
sec.AddValue("LegendText", LegendText, null);
|
|
sec.AddValue("ShowCheckBoxInLegend", ShowCheckBoxInLegend, true);
|
|
sec.AddValue("ShowInLegend", ShowInLegend, true);
|
|
sec.AddValue("ShowInParentLegend", ShowInParentLegend, true);
|
|
sec.AddValue("ShowMarkerInLegend", ShowMarkerInLegend, true);
|
|
|
|
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 "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 "CheckedInLegend":
|
|
CheckedInLegend = bool.Parse(se.StringValue);
|
|
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 "CrosshairShowLabels":
|
|
CrosshairShowLabels = (Tbool)se.GetValueEnum(typeof(Tbool));
|
|
break;
|
|
|
|
case "DataMember":
|
|
DataMember = se.StringValue;
|
|
break;
|
|
|
|
case "DataPropertyNameSeries":
|
|
DataPropertyNameSeries = se.StringValue;
|
|
break;
|
|
|
|
case "DataPropertyNameX":
|
|
DataPropertyNameX = se.StringValue;
|
|
break;
|
|
|
|
case "DataPropertyNamesY":
|
|
DataPropertyNamesY.Add(se.StringValue);
|
|
break;
|
|
|
|
case "DataSource":
|
|
DataSource = se.DataValue;
|
|
break;
|
|
|
|
case "DefaultPaletteColor":
|
|
DefaultPaletteColor = se.GetValueColor();
|
|
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 "LegendText":
|
|
LegendText = se.StringValue;
|
|
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 "ShowCheckBoxInLegend":
|
|
ShowCheckBoxInLegend = bool.Parse(se.StringValue);
|
|
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 "ShowInLegend":
|
|
ShowInLegend = bool.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "ShowInParentLegend":
|
|
ShowInParentLegend = bool.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "ShowMarkerInLegend":
|
|
ShowMarkerInLegend = 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 "ChartLegendItemVisualStyles":
|
|
sec.PutSerialData(ChartLegendItemVisualStyles);
|
|
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 "DataPropertyNamesYs":
|
|
if (se.ArrayCount > 0)
|
|
{
|
|
DataPropertyNamesY = new CustomCollection<string>(se.ArrayCount);
|
|
|
|
sec.PutSerialData(this);
|
|
}
|
|
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),
|
|
}
|
|
|
|
#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 int _FirstDisplayIndex = -1;
|
|
private int _LastDisplayIndex = -1;
|
|
|
|
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;
|
|
|
|
_FirstDisplayIndex = -1;
|
|
_LastDisplayIndex = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#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<Point[]> Points;
|
|
public List<SeriesPoint[]> 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
|
|
|
|
/// <summary>
|
|
/// Gets the alternate segment style used when Open/Close values are reversed.
|
|
/// </summary>
|
|
public HiLoBarSegmentStyle AlternateStyle
|
|
{
|
|
get { return (SeriesStyle.HiLoBarVisualStyle.AlternateSegmentStyle); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DefaultStyle
|
|
|
|
/// <summary>
|
|
/// Gets the default segment style used when Open/Close values are not reversed.
|
|
/// </summary>
|
|
public HiLoBarSegmentStyle DefaultStyle
|
|
{
|
|
get { return (SeriesStyle.HiLoBarVisualStyle.DefaultSegmentStyle); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsAlternate
|
|
|
|
/// <summary>
|
|
/// Gets whether the segment is to be render as 'Alternate'.
|
|
/// </summary>
|
|
public bool IsAlternate
|
|
{
|
|
get { return (_IsAlternate); }
|
|
internal set { _IsAlternate = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SeriesStyle
|
|
|
|
/// <summary>
|
|
/// Gets the associated series visual style.
|
|
/// </summary>
|
|
public ChartSeriesVisualStyle SeriesStyle
|
|
{
|
|
get { return (_SeriesStyle); }
|
|
internal set { _SeriesStyle = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Value
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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 AMath (approximate math)
|
|
|
|
internal class AMath
|
|
{
|
|
public static double ToScalar(double x)
|
|
{
|
|
return (AMath.Sqrt((float)(x / Math.PI)) * 2);
|
|
}
|
|
|
|
public static float Sqrt(float x)
|
|
{
|
|
if (x != 0)
|
|
{
|
|
FloatIntUnion u;
|
|
|
|
u.tmp = 0;
|
|
u.f = x;
|
|
|
|
u.tmp -= 1 << 23; // Subtract 2^m
|
|
u.tmp >>= 1; // Divide by 2
|
|
u.tmp += 1 << 29; // Add ((b + 1) / 2) * 2^m
|
|
|
|
return (u.f);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Explicit)]
|
|
private struct FloatIntUnion
|
|
{
|
|
[FieldOffset(0)]
|
|
public float f;
|
|
|
|
[FieldOffset(0)]
|
|
public int tmp;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region enums
|
|
|
|
#region BarLabelPosition
|
|
|
|
/// <summary>
|
|
/// Specifies the position for Bar series labels.
|
|
/// </summary>
|
|
public enum BarLabelPosition
|
|
{
|
|
/// <summary>
|
|
/// Not set (default is Center).
|
|
/// </summary>
|
|
NotSet = -1,
|
|
|
|
/// <summary>
|
|
/// Labels will be positioned in the center of the bar.
|
|
/// </summary>
|
|
Center,
|
|
|
|
/// <summary>
|
|
/// Labels will be positioned outside the bar, relative to its origin.
|
|
/// </summary>
|
|
Near,
|
|
|
|
/// <summary>
|
|
/// Labels will be positioned inside the bar, relative to its origin.
|
|
/// </summary>
|
|
NearInside,
|
|
|
|
/// <summary>
|
|
/// Labels will be positioned outside the bar, opposite to its origin.
|
|
/// </summary>
|
|
Far,
|
|
|
|
/// <summary>
|
|
/// Labels will be positioned inside the bar, opposite to its origin.
|
|
/// </summary>
|
|
FarInside,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region BarSegment
|
|
|
|
public enum BarSegment
|
|
{
|
|
/// <summary>
|
|
/// Top portion of Vertical bar (full area).
|
|
/// </summary>
|
|
Top,
|
|
|
|
/// <summary>
|
|
/// Partial Top area of Vertical bar.
|
|
/// </summary>
|
|
TopPartial,
|
|
|
|
/// <summary>
|
|
/// Bottom portion of Vertical bar (full area).
|
|
/// </summary>
|
|
Bottom,
|
|
|
|
/// <summary>
|
|
/// Partial Bottom area of Vertical bar.
|
|
/// </summary>
|
|
BottomPartial,
|
|
|
|
/// <summary>
|
|
/// Left portion of Horizontal bar (full area).
|
|
/// </summary>
|
|
Left,
|
|
|
|
/// <summary>
|
|
/// Partial Left area of Horizontal bar.
|
|
/// </summary>
|
|
LeftPartial,
|
|
|
|
/// <summary>
|
|
/// Right portion of Horizontal bar (full area).
|
|
/// </summary>
|
|
Right,
|
|
|
|
/// <summary>
|
|
/// Partial Right area of Horizontal bar.
|
|
/// </summary>
|
|
RightPartial,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SeriesType
|
|
|
|
/// <summary>
|
|
/// Defines available Series types
|
|
/// </summary>
|
|
public enum SeriesType
|
|
{
|
|
Bubble,
|
|
|
|
HorizontalBar,
|
|
VerticalBar,
|
|
|
|
Line,
|
|
Point,
|
|
|
|
HorizontalDot, // Wilkinson dotplot
|
|
VerticalDot,
|
|
|
|
HorizontalHiLoBar, // Box, Candle, HiLo
|
|
VerticalHiLoBar,
|
|
|
|
//Bullet,
|
|
|
|
//Pie,
|
|
//Polar,
|
|
//Radar,
|
|
|
|
//TreeMap,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ConvexHullDisplayMode
|
|
|
|
/// <summary>
|
|
/// Specifies the ConvexHull display mode
|
|
/// </summary>
|
|
[Flags]
|
|
public enum ConvexHullDisplayMode
|
|
{
|
|
/// <summary>
|
|
/// Not set (default is None).
|
|
/// </summary>
|
|
NotSet = 0,
|
|
|
|
/// <summary>
|
|
/// No Convex Hull processing will take place.
|
|
/// </summary>
|
|
None = (1 << 0),
|
|
|
|
/// <summary>
|
|
/// Convex Hull border will be displayed.
|
|
/// </summary>
|
|
DisplayBorder = (1 << 1),
|
|
|
|
/// <summary>
|
|
/// Convex Hull background area will be displayed.
|
|
/// </summary>
|
|
DisplayBackground = (1 << 2),
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PointLabelDisplayMode
|
|
|
|
/// <summary>
|
|
/// Specifies which PointLabels are to be displayed
|
|
/// </summary>
|
|
[Flags]
|
|
public enum PointLabelDisplayMode
|
|
{
|
|
/// <summary>
|
|
/// Not set (default is None).
|
|
/// </summary>
|
|
NotSet,
|
|
|
|
/// <summary>
|
|
/// No labels will be displayed.
|
|
/// </summary>
|
|
None = (1 << 0),
|
|
|
|
/// <summary>
|
|
/// All series points will display a label.
|
|
/// </summary>
|
|
AllSeriesPoints = (1 << 1),
|
|
|
|
/// <summary>
|
|
/// User defined DataLabels will be displayed.
|
|
/// </summary>
|
|
DataLabels = (1 << 2),
|
|
|
|
/// <summary>
|
|
/// Minimum 'X' Value label will be displayed.
|
|
/// </summary>
|
|
MinValueX = (1 << 3),
|
|
|
|
/// <summary>
|
|
/// Minimum 'Y' Value label will be displayed.
|
|
/// </summary>
|
|
MinValueY = (1 << 4),
|
|
|
|
/// <summary>
|
|
/// Maximum 'X' Value label will be displayed.
|
|
/// </summary>
|
|
MaxValueX = (1 << 5),
|
|
|
|
/// <summary>
|
|
/// Maximum 'Y' Value label will be displayed.
|
|
/// </summary>
|
|
MaxValueY = (1 << 6),
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region StepLineMode
|
|
|
|
/// <summary>
|
|
/// Specifies the mode used to render "Step Lines" in
|
|
/// a given Line series.
|
|
/// </summary>
|
|
public enum StepLineMode
|
|
{
|
|
/// <summary>
|
|
/// Not set (default is HorizontalThenVertical).
|
|
/// </summary>
|
|
NotSet = -1,
|
|
|
|
/// <summary>
|
|
/// No Step Lines will be rendered.
|
|
/// </summary>
|
|
None,
|
|
|
|
/// <summary>
|
|
/// Step lines will be displayed between consecutive
|
|
/// series points, by first displaying the horizontal step
|
|
/// line, followed by the connecting vertical step line.
|
|
/// </summary>
|
|
HorizontalThenVertical,
|
|
|
|
/// <summary>
|
|
/// Step lines will be displayed between consecutive
|
|
/// series points, by first displaying the vertical step
|
|
/// line, followed by the connecting horizontal step line.
|
|
/// </summary>
|
|
VerticalThenHorizontal,
|
|
|
|
/// <summary>
|
|
/// Step lines will be displayed between consecutive
|
|
/// series points, by first displaying the midPoint horizontal
|
|
/// step line, followed by the connecting vertical step line.
|
|
/// </summary>
|
|
MidPoint,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region StepLines
|
|
|
|
/// <summary>
|
|
/// Specifies the mode used to render "Stepped Lines" in
|
|
/// a given Line series.
|
|
/// </summary>
|
|
public enum StepLines
|
|
{
|
|
/// <summary>
|
|
/// Not set (default is StepHv).
|
|
/// </summary>
|
|
NotSet = -1,
|
|
|
|
/// <summary>
|
|
/// No step lines will be displayed.
|
|
/// </summary>
|
|
None,
|
|
|
|
/// <summary>
|
|
/// Horizontal step lines will be displayed.
|
|
/// </summary>
|
|
Horizontal,
|
|
|
|
/// <summary>
|
|
/// Vertical step lines will be displayed.
|
|
/// </summary>
|
|
Vertical,
|
|
|
|
/// <summary>
|
|
/// Both horizontal and vertical step lines will be displayed.
|
|
/// </summary>
|
|
Both,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ScaleType
|
|
|
|
/// <summary>
|
|
/// Specifies the scale type for the series points
|
|
/// </summary>
|
|
public enum ScaleType
|
|
{
|
|
/// <summary>
|
|
/// ScaleType is NotSet (default is 'Auto').
|
|
/// </summary>
|
|
NotSet,
|
|
|
|
/// <summary>
|
|
/// ScaleType is Automatic. Scale type will be determined
|
|
/// by the underlying, assigned data.
|
|
/// </summary>
|
|
Auto,
|
|
|
|
/// <summary>
|
|
/// DateTime data scale. Points will be treated as
|
|
/// DateTime values and will be shown as such on the axis.
|
|
/// </summary>
|
|
DateTime,
|
|
|
|
/// <summary>
|
|
/// Numerical data scale. Points will be treated as
|
|
/// numerical values and will be shown on the axis as numbers.
|
|
/// </summary>
|
|
Quantitative,
|
|
|
|
/// <summary>
|
|
/// Qualitative data scale. Points will be treated as
|
|
/// qualitative values and will be shown on the axis as text.
|
|
/// </summary>
|
|
Qualitative,
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region HiLoBarType
|
|
|
|
/// <summary>
|
|
/// Specifies the HiloBar series display type.
|
|
/// </summary>
|
|
public enum HiLoBarType
|
|
{
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
Box,
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
Candle,
|
|
|
|
/// <summary>
|
|
/// Line plot display.
|
|
/// </summary>
|
|
Line,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region HiLoBarSegment
|
|
|
|
public enum HiLoBarSegment
|
|
{
|
|
/// <summary>
|
|
/// Box (Box plot).
|
|
/// </summary>
|
|
Box,
|
|
|
|
/// <summary>
|
|
/// High whisker (Box, Candle, Line).
|
|
/// </summary>
|
|
HighWhisker,
|
|
|
|
/// <summary>
|
|
/// High whisker cap (Box, Candle, Line).
|
|
/// </summary>
|
|
HighWhiskerCap,
|
|
|
|
/// <summary>
|
|
/// Low whisker (Box, Candle, Line).
|
|
/// </summary>
|
|
LowWhisker,
|
|
|
|
/// <summary>
|
|
/// Low whisker cap (Box, Candle, Line).
|
|
/// </summary>
|
|
LowWhiskerCap,
|
|
|
|
/// <summary>
|
|
/// Open whisker (Line plot).
|
|
/// </summary>
|
|
OpenWhisker,
|
|
|
|
/// <summary>
|
|
/// Close whisker (Line Plot).
|
|
/// </summary>
|
|
CloseWhisker,
|
|
|
|
/// <summary>
|
|
/// Center line (Line plot).
|
|
/// </summary>
|
|
CenterLine,
|
|
|
|
/// <summary>
|
|
/// Full range (Line plot).
|
|
/// </summary>
|
|
FullRange,
|
|
|
|
/// <summary>
|
|
/// Median line (Box, Candle, Line).
|
|
/// </summary>
|
|
MedianLine,
|
|
|
|
/// <summary>
|
|
/// Bar shading (Box, Candle).
|
|
/// </summary>
|
|
BarShading,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region AxisTypeConverter
|
|
|
|
///<summary>
|
|
/// AxisTypeConverter
|
|
///</summary>
|
|
public class AxisTypeConverter : TypeConverter
|
|
{
|
|
///<summary>
|
|
/// ConvertTo
|
|
///</summary>
|
|
///<param name="context"></param>
|
|
///<param name="culture"></param>
|
|
///<param name="value"></param>
|
|
///<param name="destinationType"></param>
|
|
///<returns></returns>
|
|
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
|
|
}
|