using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DevComponents.DotNetBar.Charts.Style;
namespace DevComponents.DotNetBar.Charts
{
///
/// Represents an X/Y oriented chart.
/// pi
public class ChartXy : BaseChart
{
#region Private variables
private States _States;
private ChartAxisX _AxisX;
private ChartAxisY _AxisY;
private ChartAxesXCollection _AncillaryAxesX;
private ChartAxesYCollection _AncillaryAxesY;
private ChartSeriesCollection _ChartSeries;
private SeriesType _AutoGenSeriesChartType = SeriesType.Point;
private int _BarSpacing;
private double _BarSpacingRatio = 0.2d;
private double _BarWidthRatio;
private object _BarOrigin;
private Tbool _BarShadingEnabled = Tbool.NotSet;
private Tbool _BarShowAsHistogram = Tbool.NotSet;
private BarFillRange _BarFillRange = BarFillRange.NotSet;
private BarLabelPosition _BarLabelPosition = BarLabelPosition.NotSet;
private DataLabelOverlapMode _DataLabelOverlapMode = DataLabelOverlapMode.NotSet;
private DataLabelVisualStyle _DataLabelVisualStyle;
private EffectiveStyle _EffectiveDataLabelStyle;
private ChartXyVisualStyle _ChartVisualStyle;
private EffectiveStyle _EffectiveChartStyle;
private ChartSeriesVisualStyle _ChartSeriesVisualStyle;
private EffectiveStyle _EffectiveChartSeriesStyle;
private ChartCrosshair _ChartCrosshair;
private List _CrosshairSeriesPoints;
private CrosshairPoint _NearestCrosshairPoint;
private bool _CanShowCrosshairLabel;
private object _MinValueX;
private object _MaxValueX;
private object _MinValueY;
private object _MaxValueY;
private Size _MinQualitativeSize;
private PointMarker _PointMarker;
private ChartLineDisplayMode _ChartLineDisplayMode = ChartLineDisplayMode.NotSet;
private ChartLineAreaDisplayMode _ChartLineAreaDisplayMode = ChartLineAreaDisplayMode.NotSet;
private BubbleSizeMode _BubbleSizeMode = BubbleSizeMode.NotSet;
private BubbleIntensityMode _BubbleIntensityMode = BubbleIntensityMode.NotSet;
private ConvexHullDisplayMode _ConvexHullDisplayMode = ConvexHullDisplayMode.NotSet;
private PointLabelDisplayMode _PointLabelDisplayType = PointLabelDisplayMode.NotSet;
private StepLines _StepLines = StepLines.NotSet;
private StepLineMode _StepLineMode = StepLineMode.NotSet;
private List _PointLabels;
#endregion
public ChartXy(string name)
: this()
{
Name = name;
}
public ChartXy()
{
InitDefaultStates();
_EffectiveChartStyle = new EffectiveStyle(this);
_EffectiveChartSeriesStyle = new EffectiveStyle(this);
_EffectiveDataLabelStyle = new EffectiveStyle(this);
}
#region InitDefaultStates
private void InitDefaultStates()
{
}
#endregion
#region Public properties
#region AncillaryAxesX
///
/// Gets a reference to the collection of Ancillary X Axes (Axes that
/// can be presented in addition to the default X Axis)
///
[Category("Axis")]
[Description("Indicates the collection of Ancillary X Axes (Axes that can be presented in addition to the default X Axis.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartAxesXCollection AncillaryAxesX
{
get
{
if (_AncillaryAxesX == null)
{
_AncillaryAxesX = new ChartAxesXCollection();
_AncillaryAxesX.CollectionChanged += AncillaryAxesCollectionChanged;
}
return (_AncillaryAxesX);
}
internal set
{
if (_AncillaryAxesX != null)
_AncillaryAxesX.CollectionChanged -= AncillaryAxesCollectionChanged;
_AncillaryAxesX = value;
if (_AncillaryAxesX != null)
_AncillaryAxesX.CollectionChanged += AncillaryAxesCollectionChanged;
}
}
#region AncillaryAxesCollectionChanged
private void AncillaryAxesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ChartAxesCollection cac = sender as ChartAxesCollection;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
AddAxisItems(e, cac.AxisOrientation);
break;
case NotifyCollectionChangedAction.Replace:
RemoveAxisItems(e);
AddAxisItems(e, cac.AxisOrientation);
break;
case NotifyCollectionChangedAction.Remove:
RemoveAxisItems(e);
break;
}
InvalidateLayout();
}
#region AddAxisItems
private void AddAxisItems(
NotifyCollectionChangedEventArgs e, AxisOrientation axisOrientation)
{
foreach (ChartAxis axis in e.NewItems)
{
if (axis.AxisOrientation != axisOrientation)
{
if (axisOrientation == AxisOrientation.X)
throw new Exception("Cannot add Y-Axis element to X-Axis collection.");
else
throw new Exception("Cannot add X-Axis element to Y-Axis collection.");
}
axis.Parent = this;
}
}
#endregion
#region RemoveAxisItems
private void RemoveAxisItems(NotifyCollectionChangedEventArgs e)
{
foreach (ChartAxis axis in e.OldItems)
axis.Parent = null;
}
#endregion
#endregion
#endregion
#region AncillaryAxesY
///
/// Gets a reference to the collection of Ancillary Y Axes (Axes that
/// can be presented in addition to the default Y Axis)
///
[Category("Axis")]
[Description("Indicates the collection of Ancillary Y Axes (Axes that can be presented in addition to the default Y Axis.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartAxesYCollection AncillaryAxesY
{
get
{
if (_AncillaryAxesY == null)
{
_AncillaryAxesY = new ChartAxesYCollection();
_AncillaryAxesY.CollectionChanged += AncillaryAxesCollectionChanged;
}
return (_AncillaryAxesY);
}
internal set
{
if (_AncillaryAxesY != null)
_AncillaryAxesY.CollectionChanged -= AncillaryAxesCollectionChanged;
_AncillaryAxesY = value;
if (_AncillaryAxesY != null)
_AncillaryAxesY.CollectionChanged += AncillaryAxesCollectionChanged;
}
}
#endregion
#region AutoGenSeriesType
///
/// Gets or sets the default SeriesType assigned to auto-generated Series.
///
[DefaultValue(SeriesType.Point), Category("Behavior")]
[Description("Indicates the default SeriesType assigned to auto-generated Series.")]
public SeriesType AutoGenSeriesType
{
get { return (_AutoGenSeriesChartType); }
set
{
if (value != _AutoGenSeriesChartType)
{
_AutoGenSeriesChartType = value;
OnPropertyChanged("AutoGenSeriesType");
}
}
}
#endregion
#region AxisX
///
/// Gets a reference to the default, primary X Axis.
///
[Category("Axis")]
[Description("Indicates the reference to the default, primary X Axis.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartAxisX AxisX
{
get
{
if (_AxisX == null)
{
_AxisX = new ChartAxisX();
_AxisX.Parent = this;
_AxisX.IsPrimaryAxis = true;
}
return (_AxisX);
}
internal set
{
if (_AxisX != null)
_AxisX.Parent = null;
_AxisX = value;
if (_AxisX != null)
{
_AxisX.Parent = this;
_AxisX.IsPrimaryAxis = true;
}
}
}
#endregion
#region AxisY
///
/// Gets a reference to the default, primary Y Axis.
///
[Category("Axis")]
[Description("Indicates the reference to the default, primary Y Axis.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartAxisY AxisY
{
get
{
if (_AxisY == null)
{
_AxisY = new ChartAxisY();
_AxisY.Parent = this;
_AxisY.IsPrimaryAxis = true;
}
return (_AxisY);
}
internal set
{
if (_AxisY != null)
_AxisY.Parent = null;
_AxisY = value;
if (_AxisY != null)
{
_AxisY.Parent = this;
_AxisY.IsPrimaryAxis = true;
}
}
}
#endregion
#region BarFillRange
///
/// Gets or sets how series bars are filled by default (either according to
/// each individual bar range, or the entire series range).
///
[DefaultValue(BarFillRange.NotSet), Category("Bar Display")]
[Description("Indicates how series bars are filled by default(either according to each individual bar range, or the entire series range).")]
public BarFillRange BarFillRange
{
get { return (_BarFillRange); }
set
{
if (value != _BarFillRange)
{
_BarFillRange = value;
OnPropertyChangedEx("BarFillRange", VisualChangeType.Render);
}
}
}
#endregion
#region BarLabelPosition
///
/// Gets or sets the default position of bar series labels (default is Center).
///
[DefaultValue(BarLabelPosition.NotSet), Category("Bar Display")]
[Description("Indicates the default 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 BarOrigin
///
/// Gets or sets the bar 'origin'. This value is used as the base, or
/// starting Value, from which each bar originates.
///
[DefaultValue(null), Category("Bar Display")]
[Description("Indicates the bar 'origin'. This value is used as the base, or starting Value, from which each bar originates.")]
[TypeConverter("DevComponents.Charts.Design.PointValueConverter, DevComponents.Charts.Design," +
"Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf")]
public object BarOrigin
{
get { return (_BarOrigin); }
set
{
if (value != _BarOrigin)
{
_BarOrigin = value;
OnPropertyChangedEx("BarOrigin", VisualChangeType.Layout);
}
}
}
#endregion
#region BarOverlayEnabled
///
/// Gets or sets whether the intra-bar (or bar grouping) overlay
/// is enabled (bars within a group are positoned overlayed on top of each other).
///
[DefaultValue(false), Category("Bar Display")]
[Description("Indicates whether the intra-bar (or bar grouping) overlay is enabled (bars within a group are positoned overlayed on top of each other).")]
public bool BarOverlayEnabled
{
get { return (TestState(States.BarOverlayEnabled)); }
set
{
if (value != BarOverlayEnabled)
{
SetState(States.BarOverlayEnabled, value);
OnPropertyChangedEx("BarOverlayEnabled", VisualChangeType.Layout);
}
}
}
#endregion
#region BarShadingEnabled
///
/// Gets or sets whether Bar shading is enabled by
/// default for Horizontal and Vertical Bar series.
///
[DefaultValue(Tbool.NotSet), Category("Bar Display")]
[Description("Indicates whether Bar shading is enabled by default for Horizontal and Vertical Bar series.")]
public Tbool BarShadingEnabled
{
get { return (_BarShadingEnabled); }
set
{
if (value != _BarShadingEnabled)
{
_BarShadingEnabled = value;
OnPropertyChangedEx("BarShadingEnabled", VisualChangeType.Render);
}
}
}
#endregion
#region BarShowAsHistogram
///
/// Gets or sets whether the bars will be shown as a Histogram.
/// Note that this will only be honored for single series bar displays.
///
[DefaultValue(Tbool.NotSet), Category("Bar Display")]
[Description("Indicates whether the bars will be shown as a Histogram. Note that this will only be honored for single series bar displays.")]
public Tbool BarShowAsHistogram
{
get { return (_BarShowAsHistogram); }
set
{
if (value != _BarShowAsHistogram)
{
_BarShowAsHistogram = value;
OnPropertyChangedEx("BarShowAsHistogram", VisualChangeType.Layout);
}
}
}
#endregion
#region BarSpacing
///
/// Gets or sets the intra-bar spacing (or spacing between bars
/// within the same group). Value is taken as a fixed pixel size.
/// Setting BarSpacing to 0 (zero) will disable the use of this
/// property, and will enable the use of the set BarSpacingRatio value.
///
[DefaultValue(0), Category("Bar Display")]
[Description("Indicates the intra-bar spacing (or spacing between bars within the same group). Value is taken as a fixed pixel size. Setting BarSpacing to 0 (zero) will disable the use of this property, and will enable the use of the set BarSpacingRatio value.")]
public int BarSpacing
{
get { return (_BarSpacing); }
set
{
if (value != _BarSpacing)
{
_BarSpacing = value;
OnPropertyChangedEx("BarSpacing", VisualChangeType.Layout);
}
}
}
#endregion
#region BarSpacingRatio
///
/// Gets or sets the intra-bar spacing ratio (bar spacing between
/// multiple series bars associated with the same value. Default is .2).
///
[DefaultValue(0.2d), Category("Bar Display")]
[Description("Indicates the intra-bar spacing ratio (bar spacing between multiple series bars associated with the same value. Default is .2).")]
public double BarSpacingRatio
{
get { return (_BarSpacingRatio); }
set
{
if (value != _BarSpacingRatio)
{
if (value < 0)
throw new ArgumentException("Value must be >= 0");
_BarSpacingRatio = value;
OnPropertyChangedEx("BarSpacingRatio", VisualChangeType.Layout);
}
}
}
#endregion
#region BarWidthRatio
///
/// Gets or sets the default ratio of bar width to bar
/// group spacing (defaults to 1 - bar width matches spacing).
///
[DefaultValue(0d), Category("Bar Display")]
[Description("Indicates the default ratio of bar width to bar group spacing (defaults to 1 - bar width matches spacing).")]
public double BarWidthRatio
{
get { return (_BarWidthRatio); }
set
{
if (value != _BarWidthRatio)
{
if (value < 0)
throw new ArgumentException("Value must be >= 0");
_BarWidthRatio = value;
OnPropertyChangedEx("BarWidthRatio", VisualChangeType.Layout);
}
}
}
#endregion
#region BubbleIntensityMode
///
/// Gets or sets the default mode used to determine series bubble intensities.
///
[DefaultValue(BubbleIntensityMode.NotSet), Category("Display")]
[Description("Indicates the default mode used to determine series bubble intensities.")]
public BubbleIntensityMode BubbleIntensityMode
{
get { return (_BubbleIntensityMode); }
set
{
if (value != _BubbleIntensityMode)
{
_BubbleIntensityMode = value;
OnPropertyChangedEx("BubbleIntensityMode", VisualChangeType.Render);
}
}
}
#endregion
#region BubbleSizeMode
///
/// Gets or sets the default mode used to calculate series bubble sizes.
///
[DefaultValue(BubbleSizeMode.NotSet), Category("Display")]
[Description("Indicates the default mode used to calculate series bubble sizes.")]
public BubbleSizeMode BubbleSizeMode
{
get { return (_BubbleSizeMode); }
set
{
if (value != _BubbleSizeMode)
{
_BubbleSizeMode = value;
OnPropertyChangedEx("BubbleSizeMode", VisualChangeType.Layout);
}
}
}
#endregion
#region ChartLineAreaDisplayMode
///
/// Gets or sets the default Line 'Area' display mode.
///
[DefaultValue(ChartLineAreaDisplayMode.NotSet), Category("Display")]
[Description("Indicates the default Line 'Area' display mode.")]
[Editor("DevComponents.Charts.Design.FlagsEnumUIEditor, DevComponents.Charts.Design, " +
"Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public ChartLineAreaDisplayMode ChartLineAreaDisplayMode
{
get { return (_ChartLineAreaDisplayMode); }
set
{
if (value != _ChartLineAreaDisplayMode)
{
_ChartLineAreaDisplayMode = value;
OnPropertyChangedEx("ChartLineAreaDisplayMode", VisualChangeType.Render);
}
}
}
#endregion
#region ChartLineDisplayMode
///
/// Gets or sets the default display mode for SeriesType.Line series.
///
[DefaultValue(ChartLineDisplayMode.NotSet), Category("Display")]
[Description("Indicates the default display mode for SeriesType.Line series.")]
[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)
{
if ((_ChartLineDisplayMode & ChartLineDisplayMode.DisplayUnsorted) !=
(value & ChartLineDisplayMode.DisplayUnsorted))
{
foreach (ChartSeries series in ChartSeries)
series.ResetSortedPoints();
}
_ChartLineDisplayMode = value;
OnPropertyChangedEx("ChartLineDisplayMode", VisualChangeType.Render);
}
}
}
#endregion
#region ChartSeries
///
/// Gets a reference to the collection of Chart Series
///
[Category("Data")]
[Description("Indicates the collection of Chart Series.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartSeriesCollection ChartSeries
{
get
{
if (_ChartSeries == null)
{
_ChartSeries = new ChartSeriesCollection();
_ChartSeries.CollectionChanged += ChartSeriesCollectionChanged;
}
return (_ChartSeries);
}
internal set
{
BaseSeries = null;
if (_ChartSeries != null)
_ChartSeries.CollectionChanged -= ChartSeriesCollectionChanged;
_ChartSeries = value;
if (_ChartSeries != null)
_ChartSeries.CollectionChanged += ChartSeriesCollectionChanged;
}
}
#region ChartSeriesCollectionChanged
void ChartSeriesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
BaseSeries = null;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (ChartSeries item in e.NewItems)
item.Parent = this;
break;
case NotifyCollectionChangedAction.Replace:
foreach (ChartSeries item in e.OldItems)
item.Parent = null;
foreach (ChartSeries item in e.NewItems)
item.Parent = this;
break;
case NotifyCollectionChangedAction.Remove:
foreach (ChartSeries item in e.OldItems)
item.Parent = null;
break;
}
ValidateSeriesCollection();
InvalidateLayout();
}
#endregion
#region ValidateSeriesCollection
private void ValidateSeriesCollection()
{
SeriesRangeChanged = true;
foreach (ChartSeries series in ChartSeries)
{
ChartAxis axis = series.AxisX;
if (axis != null && axis.IsPrimaryAxis == false)
{
if (AncillaryAxesX.Contains(axis) == false)
{
throw new Exception("Cannot set the series YAxis. The axis is not primary " +
"or a member of the chart's AncillaryAxesY collection.");
}
}
axis = series.AxisY;
if (axis != null && axis.IsPrimaryAxis == false)
{
if (AncillaryAxesY.Contains(axis) == false)
{
throw new Exception("Cannot set the series YAxis. The axis is not primary " +
"or a member of the chart's AncillaryAxesY collection.");
}
}
}
}
#endregion
#endregion
#region ChartSeriesVisualStyle
///
/// Gets or sets the default visual style for each chart series.
///
[Category("Style")]
[Description("Indicates the default visual style for each chart 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 ChartVisualStyle
///
/// Gets or sets the visual style for the Chart.
///
[Category("Style")]
[Description("Indicates the visual style for the Chart.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartXyVisualStyle ChartVisualStyle
{
get
{
if (_ChartVisualStyle == null)
{
_ChartVisualStyle = new ChartXyVisualStyle();
StyleVisualChangeHandler(null, _ChartVisualStyle);
}
return (_ChartVisualStyle);
}
set
{
if (_ChartVisualStyle != value)
{
ChartXyVisualStyle oldValue = _ChartVisualStyle;
_ChartVisualStyle = value;
OnStyleChanged("ChartVisualStyle", oldValue, value);
if (oldValue != null)
oldValue.Dispose();
}
}
}
#endregion
#region ChartCrosshair
///
/// Gets a reference to the Crosshair element for the chart.
///
[Category("Appearance")]
[Description("Indicates a reference to the Crosshair element for the chart.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartCrosshair ChartCrosshair
{
get
{
if (_ChartCrosshair == null)
{
_ChartCrosshair = new ChartCrosshair();
_ChartCrosshair.Parent = this;
_ChartCrosshair.PropertyChanged += ChartCrosshair_PropertyChanged;
}
return (_ChartCrosshair);
}
internal set
{
if (_ChartCrosshair != null)
{
_ChartCrosshair.Parent = null;
_ChartCrosshair.PropertyChanged -= ChartCrosshair_PropertyChanged;
}
_ChartCrosshair = value;
if (_ChartCrosshair != null)
{
_ChartCrosshair.Parent = this;
_ChartCrosshair.PropertyChanged += ChartCrosshair_PropertyChanged;
}
}
}
#region ChartCrosshair_PropertyChanged
void ChartCrosshair_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
InvalidateRender();
}
#endregion
#endregion
#region ConvexHullDisplayMode
///
/// Gets or sets the default ConvexHull display mode.
///
[DefaultValue(ConvexHullDisplayMode.NotSet), Category("Display")]
[Description("Indicates the default 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 DataLabelOverlapMode
///
/// Gets or sets the mode for resolving overlapping series data labels.
///
[DefaultValue(DataLabelOverlapMode.NotSet), Category("Display")]
[Description("Indicates the mode for resolving overlapping series data labels.")]
public DataLabelOverlapMode DataLabelOverlapMode
{
get { return (_DataLabelOverlapMode); }
set
{
if (value != _DataLabelOverlapMode)
{
_DataLabelOverlapMode = value;
OnPropertyChangedEx("DataLabelOverlapMode", VisualChangeType.Layout);
}
}
}
#endregion
#region DataLabelVisualStyle
///
/// Gets or sets the default visual style for the chart DataLabel's.
///
[Category("Style")]
[Description("Indicates the default visual style for the chart DataLabel's.")]
[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 EffectiveChartSeriesStyle
///
/// Gets a reference to the ChartSeries effective (cached, composite) style.
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ChartSeriesVisualStyle EffectiveChartSeriesStyle
{
get { return (_EffectiveChartSeriesStyle.Style); }
}
#endregion
#region EffectiveChartStyle
///
/// Gets a reference to the Chart's Effective (cached, composite) style.
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ChartXyVisualStyle EffectiveChartStyle
{
get { return (_EffectiveChartStyle.Style); }
}
#endregion
#region EffectiveDataLabelStyle
///
/// Gets a reference to the DataLabel Effective (cached, composite) style.
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Description("Indicates a reference to the DataLabel Effective (cached, composite) style.")]
public DataLabelVisualStyle EffectiveDataLabelStyle
{
get { return (_EffectiveDataLabelStyle.Style); }
}
#endregion
#region MaxValueX
///
/// Gets the calculated maximum X value (composite value of all associated series).
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public object MaxValueX
{
get
{
UpdateRangeValues();
return (_MaxValueX);
}
}
#endregion
#region MaxValueY
///
/// Gets the calculated maximum Y value (composite value of all associated series).
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public object MaxValueY
{
get
{
UpdateRangeValues();
return (_MaxValueY);
}
}
#endregion
#region MinValueX
///
/// Gets the calculated minimum X value (composite value of all associated series).
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public object MinValueX
{
get
{
UpdateRangeValues();
return (_MinValueX);
}
}
#endregion
#region MinValueY
///
/// Gets the calculated minimum Y value (composite value of all associated series).
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public object MinValueY
{
get
{
UpdateRangeValues();
return (_MinValueY);
}
}
#endregion
#region NearestCrosshairPoint
///
/// Gets the last calculated CrosshairPoint nearest to the mouse cursor.
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public CrosshairPoint NearestCrosshairPoint
{
get { return (_NearestCrosshairPoint); }
}
#endregion
#region PointLabelDisplayMode
///
/// Gets or sets the default display mode for the chart PointLabels.
///
[DefaultValue(PointLabelDisplayMode.NotSet), Category("Display")]
[Description("Indicates the default 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 (_PointLabelDisplayType); }
set
{
if (value != _PointLabelDisplayType)
{
_PointLabelDisplayType = value;
InvalidatePointLabels();
OnPropertyChangedEx("PointLabelDisplayMode", VisualChangeType.Render);
}
}
}
#endregion
#region ScrollBounds
///
/// Gets the Scrollable bounds of the chart.
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override Rectangle ScrollBounds
{
get
{
ChartXyVisualStyle xyStyle = EffectiveChartStyle;
Rectangle cbounds = ContentBounds;
cbounds.X += xyStyle.BorderThickness.Left;
cbounds.Width -= xyStyle.BorderThickness.Horizontal;
cbounds.Y += xyStyle.BorderThickness.Top;
cbounds.Height -= xyStyle.BorderThickness.Vertical;
return (cbounds);
}
}
#endregion
#region ScrollBoundsEx
///
/// Gets the Scrollable, extended bounds of the chart.
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override Rectangle ScrollBoundsEx
{
get
{
ChartXyVisualStyle xyStyle = EffectiveChartStyle;
Rectangle cbounds = ContentBoundsEx;
cbounds.X += xyStyle.BorderThickness.Left;
cbounds.Width -= xyStyle.BorderThickness.Horizontal;
cbounds.Y += xyStyle.BorderThickness.Top;
cbounds.Height -= xyStyle.BorderThickness.Vertical;
return (cbounds);
}
}
#endregion
#region StepLines
///
/// Gets or sets which 'Step lines' are displayed by default.
///
[DefaultValue(StepLines.NotSet), Category("Display")]
[Description("Indicates which 'Step lines' are displayed by default.")]
public StepLines StepLines
{
get { return (_StepLines); }
set
{
if (value != _StepLines)
{
_StepLines = value;
OnPropertyChangedEx("StepLines", VisualChangeType.Render);
}
}
}
#endregion
#region StepLineMode
///
/// Gets or sets the default mode (or order of rendered Step Lines)
/// used to display "Step Lines" in the defined Line series.
///
[DefaultValue(StepLineMode.NotSet), Category("Display")]
[Description("Indicates the default mode (or order of rendered Step Lines) used to display '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 CrosshairSeriesPoints
internal List CrosshairSeriesPoints
{
get { return (_CrosshairSeriesPoints); }
set { _CrosshairSeriesPoints = value; }
}
#endregion
#region DisplayCrosshair
internal bool DisplayCrosshair
{
get { return (TestState(States.DisplayCrosshair)); }
set { SetState(States.DisplayCrosshair, value); }
}
#endregion
#region DropShadowDisplayed
internal bool DropShadowDisplayed
{
get { return (TestState(States.DropShadowDisplayed)); }
set { SetState(States.DropShadowDisplayed, value); }
}
#endregion
#region MinQualitativeSize
internal Size MinQualitativeSize
{
get { return (_MinQualitativeSize); }
set { _MinQualitativeSize = value; }
}
#endregion
#region PointLabels
internal List PointLabels
{
get { return (_PointLabels); }
set { _PointLabels = value; }
}
#endregion
#endregion
#region MeasureOverride
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
{
ContainerVisualStyle cstyle = GetEffectiveContainerStyle();
ChartXyVisualStyle xystyle = EffectiveChartStyle;
BoundsRelative = layoutInfo.LayoutBounds;
MinQualitativeSize = Size.Empty;
UpdateDataBindings();
UpdateRangeValues();
Rectangle oldFrameBounds = FrameBounds;
FrameBounds = GetAdjustedBounds(BoundsRelative, cstyle.Margin);
FrameBounds = GetAdjustedBounds(FrameBounds, cstyle.Padding);
FrameBounds = GetAdjustedBounds(FrameBounds, xystyle.Margin);
if (FrameBounds != oldFrameBounds)
SeriesPointCount++;
ContentBounds = GetAdjustedBounds(FrameBounds, cstyle.BorderThickness);
ContentBounds = GetAdjustedBounds(ContentBounds, xystyle.BorderThickness);
ContentBounds = GetAdjustedBounds(ContentBounds, xystyle.Padding);
layoutInfo.LayoutBounds = ContentBounds;
foreach (ChartTitle title in Titles)
{
if (title.Visible == true)
title.Measure(layoutInfo);
}
if (Legend.Visible == true && Legend.Placement != Placement.Inside)
Legend.Measure(layoutInfo);
DropShadowDisplayed = (xystyle.DropShadow.Enabled == Tbool.True);
MeasureSeries(layoutInfo);
MeasureXyAxes(layoutInfo);
if (DropShadowDisplayed == true)
layoutInfo.LayoutBounds = GetShadowBounds(layoutInfo.LayoutBounds);
if (Legend.Visible == true && Legend.Placement == Placement.Inside)
{
Rectangle t = layoutInfo.LayoutBounds;
if (VScrollBar.Visible == true)
{
t.Width -= (VScrollBar.Width - 1);
layoutInfo.LayoutBounds = t;
}
if (HScrollBar.Visible == true)
{
t.Height -= (HScrollBar.Height - 1);
layoutInfo.LayoutBounds = t;
}
Legend.Measure(layoutInfo);
if (VScrollBar.Visible == true)
{
t.Width += VScrollBar.Width;
layoutInfo.LayoutBounds = t;
}
if (HScrollBar.Visible == true)
{
t.Height += HScrollBar.Height;
layoutInfo.LayoutBounds = t;
}
}
Rectangle oldContentBoundsEx = ContentBoundsEx;
ContentBounds = layoutInfo.LayoutBounds;
ContentBoundsEx = ContentBounds;
Rectangle r = ContentBounds;
r.Size = new Size(
Math.Max(r.Size.Width, Dpi.Width(MinContentSize.Width)),
Math.Max(r.Size.Height, Dpi.Height(MinContentSize.Height)));
if (MinQualitativeSize.Width > r.Width)
r.Width = MinQualitativeSize.Width;
if (MinQualitativeSize.Height > r.Height)
r.Height = MinQualitativeSize.Height;
// Since our vertical scrollbar is reversed, we
// need to adjust the extended content area accordingly
if (r.Height > ContentBounds.Height)
r.Y -= (r.Height - ContentBounds.Height);
ContentBoundsEx = r;
if (ContentBoundsEx.Equals(oldContentBoundsEx) == false)
_PointLabels = null;
FinalizeDataBindings();
}
#region MeasureSeries
private void MeasureSeries(ChartLayoutInfo layoutInfo)
{
ChartSeries[] aseries = new ChartSeries[ChartSeries.Count];
ChartSeries.CopyTo(aseries, 0);
foreach (ChartSeries series in aseries)
{
if (series.Visible == true)
series.Measure(layoutInfo);
}
}
#endregion
#region MeasureXyAxes
private void MeasureXyAxes(ChartLayoutInfo layoutInfo)
{
Rectangle obounds = layoutInfo.LayoutBounds;
SetEdgeAxes(AncillaryAxesX, AxisX);
SetEdgeAxes(AncillaryAxesY, AxisY);
MeasureAxes(layoutInfo, AncillaryAxesX, AxisX);
Rectangle nbounds = layoutInfo.LayoutBounds;
MeasureAxes(layoutInfo, AncillaryAxesY, AxisY);
for (int i = 0; i < 10; i++)
{
if (layoutInfo.LayoutBounds.Width == nbounds.Width)
break;
nbounds = layoutInfo.LayoutBounds;
layoutInfo.LayoutBoundsAdjusted = true;
layoutInfo.LayoutBounds.Y = obounds.Y;
layoutInfo.LayoutBounds.Height = obounds.Height;
MeasureAxes(layoutInfo, AncillaryAxesX, AxisX);
if (layoutInfo.LayoutBounds.Height == nbounds.Height)
break;
layoutInfo.LayoutBounds.X = obounds.X;
layoutInfo.LayoutBounds.Width = obounds.Width;
MeasureAxes(layoutInfo, AncillaryAxesY, AxisY);
}
ValidateAxes();
}
#region MeasureAxes
private void MeasureAxes(
ChartLayoutInfo layoutInfo, ChartAxesCollection axes, ChartAxis axis)
{
for (int i = axes.Count - 1; i >= 0; i--)
{
ChartAxis ca = axes[i];
if (ca != null)
ca.Measure(layoutInfo);
}
axis.Measure(layoutInfo);
}
#endregion
#region ValidateAxes
private void ValidateAxes()
{
if (ValidateAxes(AncillaryAxesX, AxisX) |
ValidateAxes(AncillaryAxesY, AxisY))
{
InvalidateSeriesPoints();
}
}
#region ValidateAxes
private bool ValidateAxes(ChartAxesCollection axes, ChartAxis axis)
{
int visCount = 0;
bool altered = false;
for (int i = axes.Count - 1; i >= 0; i--)
{
ChartAxis ca = axes[i];
if (ca.Visible == true)
{
visCount++;
altered |= ca.ValidateAxis();
}
}
if (axis.Visible == true)
{
visCount++;
altered |= axis.ValidateAxis();
}
return (altered || (visCount == 0));
}
#endregion
#endregion
#region SetEdgeAxes
private void SetEdgeAxes(ChartAxesCollection axes, ChartAxis axis)
{
ChartAxis farEdgeAxis = null;
ChartAxis nearEdgeAxis = null;
for (int i = axes.Count - 1; i >= 0; i--)
{
ChartAxis ca = axes[i];
if (ca.Visible == true)
{
AxisAlignment axisAlignment = ca.GetAxisAlignment();
ca.EdgeAxis = false;
if (axisAlignment == AxisAlignment.Near)
nearEdgeAxis = ca;
else if (axisAlignment == AxisAlignment.Far)
farEdgeAxis = ca;
}
}
if (axis.Visible == true)
{
AxisAlignment axisAlignment = axis.GetAxisAlignment();
if (axisAlignment == AxisAlignment.Near)
nearEdgeAxis = axis;
else if (axisAlignment == AxisAlignment.Far)
farEdgeAxis = axis;
}
if (nearEdgeAxis != null)
nearEdgeAxis.EdgeAxis = true;
if (farEdgeAxis != null)
farEdgeAxis.EdgeAxis = true;
}
#endregion
#endregion
#endregion
#region ArrangeOverride
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
{
int vmax = VScrollBar.LargeChange;
UpdatePaletteColor();
base.ArrangeOverride(layoutInfo);
if (VScrollBar.LargeChange != vmax)
SeriesPointCount++;
ArrangeAxes(layoutInfo, AncillaryAxesX, AxisX);
ArrangeAxes(layoutInfo, AncillaryAxesY, AxisY);
ArrangeSeries(layoutInfo);
SeriesLayoutCount++;
}
#region UpdatePaletteColor
private void UpdatePaletteColor()
{
ChartBaseSeriesCollection baseSeries = BaseSeries;
for (int i = 0; i < baseSeries.Count; i++)
{
BaseSeries series = baseSeries[i];
series.DefaultPaletteColor = GetPaletteColor(i);
}
}
#endregion
#region ArrangeAxes
private void ArrangeAxes(
ChartLayoutInfo layoutInfo, ChartAxesCollection axes, ChartAxis axis)
{
foreach (ChartAxis ca in axes)
{
if (ca.Visible == true)
ca.Arrange(layoutInfo);
}
axis.Arrange(layoutInfo);
}
#endregion
#region ArrangeSeries
private void ArrangeSeries(ChartLayoutInfo layoutInfo)
{
if (ChartSeries.Count > 0)
{
for (int i = 0; i < ChartSeries.Count; i++)
{
ChartSeries series = ChartSeries[i];
series.Arrange(layoutInfo);
if (series.IsBarSeries == true)
{
ChartAxis axis = (series.IsRotated == false)
? (series.AxisX ?? AxisX) : (series.AxisY ?? AxisY);
for (int j = 0; j < axis.AxisBars.Length; j++)
axis.AxisBars[j].Reset();
}
}
for (int i = ChartSeries.Count - 1; i >= 0; i--)
SetBarTotals(i);
for (int i = ChartSeries.Count - 1; i >= 0; i--)
SetBarWidth(i);
if (SeriesDisplayOrder == SeriesDisplayOrder.Reverse)
{
for (int i = ChartSeries.Count - 1; i >= 0; i--)
ArrangeBarSeries(i);
}
else
{
for (int i = 0; i < ChartSeries.Count; i++)
ArrangeBarSeries(i);
}
}
}
#region SetBarTotals
private void SetBarTotals(int i)
{
ChartSeries series = ChartSeries[i];
if (series.IsDisplayed == true)
{
ChartAxis axis = (series.IsRotated == false)
? series.AxisX ?? AxisX : series.AxisY ?? AxisY;
switch (series.SeriesType)
{
case SeriesType.HorizontalBar:
case SeriesType.VerticalBar:
axis.AxisBars[(int)AxisBarType.Bar].BarCount++;
axis.AxisBars[(int)AxisBarType.Bar].BarTotal += series.GetBarWidthRatio(this);
break;
case SeriesType.HorizontalHiLoBar:
case SeriesType.VerticalHiLoBar:
axis.AxisBars[(int)AxisBarType.HiLoBar].BarCount++;
axis.AxisBars[(int)AxisBarType.HiLoBar].BarTotal += series.GetBarWidthRatio(this);
break;
}
}
}
#endregion
#region SetBarWidth
private void SetBarWidth(int i)
{
ChartSeries series = ChartSeries[i];
if (series.IsDisplayed == true)
{
switch (series.SeriesType)
{
case SeriesType.HorizontalBar:
case SeriesType.VerticalBar:
SetBarWidthEx(series, (int)AxisBarType.Bar);
break;
case SeriesType.HorizontalHiLoBar:
case SeriesType.VerticalHiLoBar:
SetBarWidthEx(series, (int)AxisBarType.HiLoBar);
break;
}
}
}
#region SetBarWidthEx
private void SetBarWidthEx(ChartSeries series, int barType)
{
ChartAxis axis = (series.IsRotated == false)
? series.AxisX ?? AxisX : series.AxisY ?? AxisY;
AxisBar axisBar = axis.AxisBars[barType];
double interval = axis.MajorTickmarks.TickmarkLayout.MajorInterval;
double dwidth = interval / axis.MajorTickmarks.TickmarkLayout.MajorSpacing;
double ratio = series.GetBarWidthRatio(this);
if (BarOverlayEnabled == true || axisBar.BarCount == 1)
{
int width = (int)(dwidth * (ratio / (ratio + 1)));
if (ratio > 100)
{
ratio = (ratio - 1) / 100;
width = (int)(dwidth * ratio);
}
width = (width < 0) ? 0 : ((width - 1) | 1);
series.BarWidth = (int)(width / axis.MajorTickmarks.TickmarkLayout.GridSpacing);
axisBar.BarTotalWidth += series.BarWidth;
}
else
{
int spacing = BarSpacing;
if (BarSpacing == 0)
{
double abt = (axisBar.BarTotal + 1) + (axisBar.BarCount - 1) * BarSpacingRatio;
double sr = BarSpacingRatio / abt;
spacing = (int)(Math.Ceiling(dwidth * sr));
}
dwidth -= ((axisBar.BarCount - 1) * spacing);
int width = (int)(dwidth * (ratio / (axisBar.BarTotal + 1)));
if (ratio > 100)
{
ratio = (ratio - 1) / 100;
width = (int)(dwidth * ratio);
}
width = (int)(width / axis.MajorTickmarks.TickmarkLayout.GridSpacing);
width = (width < 0) ? 0 : ((width - 1) | 1);
series.BarWidth = width;
axisBar.BarTotalWidth += (series.BarWidth + spacing);
}
}
#endregion
#endregion
#region ArrangeBarSeries
private void ArrangeBarSeries(int i)
{
ChartSeries series = ChartSeries[i];
if (series.IsDisplayed == true)
{
switch (series.SeriesType)
{
case SeriesType.HorizontalBar:
case SeriesType.VerticalBar:
ArrangeBarSeriesEx(series, (int)AxisBarType.Bar);
break;
case SeriesType.HorizontalHiLoBar:
case SeriesType.VerticalHiLoBar:
ArrangeBarSeriesEx(series, (int)AxisBarType.HiLoBar);
break;
}
}
}
#region ArrangeBarSeriesEx
private void ArrangeBarSeriesEx(ChartSeries series, int barType)
{
ChartAxis axis = (series.IsRotated == false)
? (series.AxisX ?? AxisX) : (series.AxisY ?? AxisY);
AxisBar axisBar = axis.AxisBars[barType];
if (BarOverlayEnabled == true || axisBar.BarCount == 1)
{
series.BarOffset = 0;
axisBar.BarOffset = series.BarWidth;
}
else
{
int spacing = BarSpacing;
if (BarSpacing == 0)
{
double dwidth = axis.MajorTickmarks.TickmarkLayout.MajorInterval;
double abt = (axisBar.BarTotal + 1) + (axisBar.BarCount - 1) * BarSpacingRatio;
spacing = (int)(Math.Ceiling(dwidth * BarSpacingRatio / abt));
}
if (axisBar.BarOffset == int.MinValue)
axisBar.BarOffset = (int)((-axisBar.BarTotalWidth + spacing) / 2);
series.BarOffset = axisBar.BarOffset + series.BarWidth / 2;
axisBar.BarOffset += (series.BarWidth + spacing);
}
}
#endregion
#endregion
#endregion
#endregion
#region RenderOverride
private bool _LastDisplayCrosshair;
protected override void RenderOverride(ChartRenderInfo renderInfo)
{
Graphics g = renderInfo.Graphics;
ChartXyVisualStyle xystyle = EffectiveChartStyle;
ContainerVisualStyle cstyle = GetEffectiveContainerStyle();
Rectangle scFrameBounds = GetScrollBounds(FrameBounds);
Rectangle scContentBounds = GetScrollBounds(ContentBounds);
Rectangle scFigureBounds = GetFigureBounds(scFrameBounds, cstyle);
RenderFrameBackground(g, scFrameBounds, cstyle);
cstyle.RenderBackgroundFigure(g, scFigureBounds);
cstyle.RenderBorder(g, scFrameBounds);
Region clip = g.Clip;
g.SetClip(scContentBounds, CombineMode.Intersect);
RenderContentBackground(renderInfo, scContentBounds, xystyle);
Rectangle imageBounds = GetXyImageBounds(xystyle);
if (xystyle.ImageOverlay != ImageOverlay.Top && xystyle.ImageOverlay != ImageOverlay.Middle)
xystyle.RenderBackgroundFigure(g, scContentBounds, imageBounds);
Point cpt = Point.Empty;
Rectangle cbounds = Rectangle.Empty;
_NearestCrosshairPoint = null;
if (DisplayCrosshair == true)
{
cpt = ChartControl.PointToClient(Control.MousePosition);
cbounds = GetCrosshairBounds(cstyle);
_CrosshairSeriesPoints = GetCrosshairPoints(cbounds, cpt);
}
UpdatePointLabels(g);
RenderGrid(renderInfo, false);
RenderReferences(renderInfo, false);
if (xystyle.ImageOverlay == ImageOverlay.Middle)
xystyle.RenderBackgroundFigure(g, scContentBounds, imageBounds);
RenderChartContent(renderInfo, xystyle);
RenderGrid(renderInfo, true);
RenderReferences(renderInfo, true);
RenderPointLabels(g);
g.Clip = clip;
xystyle.RenderBorder(g, scContentBounds);
if (xystyle.ImageOverlay == ImageOverlay.Top)
xystyle.RenderBackgroundFigure(g, scContentBounds, imageBounds);
RenderAxes(renderInfo, AncillaryAxesX, AxisX);
RenderAxes(renderInfo, AncillaryAxesY, AxisY);
RenderScrollbars(renderInfo);
if (DropShadowDisplayed == true)
xystyle.DropShadow.RenderDropShadow(g, scContentBounds, true, true);
if (cstyle.DropShadow.Enabled == Tbool.True)
cstyle.DropShadow.RenderDropShadow(g, scFrameBounds, true, true);
if (DisplayCrosshair == true)
{
CrosshairVisualStyle chstyle = ChartCrosshair.EffectiveCrosshairStyle;
RenderCrosshairLines(g, cbounds, cpt, chstyle);
base.RenderOverride(renderInfo);
if (_CanShowCrosshairLabel == true)
RenderCrosshairLabels(g, cbounds, cpt, chstyle);
_LastDisplayCrosshair = DisplayCrosshair;
}
else
{
if (_CanShowCrosshairLabel == true)
{
if (DisplayCrosshair != _LastDisplayCrosshair)
RenderCrosshairLabels(g, cbounds, cpt, ChartCrosshair.EffectiveCrosshairStyle);
}
base.RenderOverride(renderInfo);
}
}
#region RenderContentBackground
private void RenderContentBackground(
ChartRenderInfo renderInfo, Rectangle bounds, ChartXyVisualStyle xyStyle)
{
Graphics g = renderInfo.Graphics;
ChartControl chartControl = ChartControl;
if (chartControl.DoPreRenderContentBackgroundEvent(g, this, bounds) == false)
{
xyStyle.RenderBackground(g, bounds);
RenderAxesBackground(renderInfo, bounds, AncillaryAxesX, AxisX);
RenderAxesBackground(renderInfo, bounds, AncillaryAxesY, AxisY);
chartControl.DoPostRenderContentBackgroundEvent(g, this, bounds);
}
}
#region RenderAxesBackground
private void RenderAxesBackground(ChartRenderInfo renderInfo,
Rectangle scContentBounds, ChartAxesCollection axes, ChartAxis axis)
{
foreach (ChartAxis ca in axes)
{
if (ca.Visible == true)
ca.RenderBackground(renderInfo, scContentBounds);
}
axis.RenderBackground(renderInfo, scContentBounds);
foreach (ChartAxis ca in axes)
{
if (ca.Visible == true)
ca.RenderStripes(renderInfo, scContentBounds);
}
axis.RenderStripes(renderInfo, scContentBounds);
}
#endregion
#endregion
#region RenderChartContent
protected virtual void RenderChartContent(
ChartRenderInfo renderInfo, ChartXyVisualStyle xyStyle)
{
Graphics g = renderInfo.Graphics;
if (ChartSeries.Count > 0)
{
SmoothingMode sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
Point pt = GetLocalAdjustedPoint(Point.Empty);
if (pt.IsEmpty == false)
g.TranslateTransform(pt.X, pt.Y);
// Indicators on bottom
if (SeriesDisplayOrder == SeriesDisplayOrder.Reverse)
{
for (int i = ChartSeries.Count - 1; i >= 0; i--)
RenderIndicators(renderInfo, ChartSeries[i], false);
}
else
{
foreach (ChartSeries series in ChartSeries)
RenderIndicators(renderInfo, series, false);
}
// Series data
if (SeriesDisplayOrder == SeriesDisplayOrder.Reverse)
{
for (int i = ChartSeries.Count - 1; i >= 0; i--)
RenderSeries(renderInfo, ChartSeries[i]);
}
else
{
foreach (ChartSeries series in ChartSeries)
RenderSeries(renderInfo, series);
}
// Indicators on top
if (SeriesDisplayOrder == SeriesDisplayOrder.Reverse)
{
for (int i = ChartSeries.Count - 1; i >= 0; i--)
RenderIndicators(renderInfo, ChartSeries[i], true);
}
else
{
foreach (ChartSeries series in ChartSeries)
RenderIndicators(renderInfo, series, true);
}
if (pt.IsEmpty == false)
g.ResetTransform();
g.SmoothingMode = sm;
}
else
{
Rectangle scContentBounds = GetScrollBounds(ContentBounds);
Rectangle scDisplayBounds = GetDisplayBounds(scContentBounds);
RenderEmptyText(g, xyStyle, scDisplayBounds);
}
}
#region RenderIndicators
private void RenderIndicators(
ChartRenderInfo renderInfo, ChartSeries series, bool onTop)
{
if (Visible == true)
{
if (Legend.ItemCheckAction != ItemCheckAction.ShowItem || series.IsDisplayed == true)
series.RenderIndicators(renderInfo, onTop);
}
}
#endregion
#region RenderSeries
private void RenderSeries(ChartRenderInfo renderInfo, ChartSeries series)
{
if (Visible == true)
{
if (Legend.ItemCheckAction != ItemCheckAction.ShowItem || series.IsDisplayed == true)
series.Render(renderInfo);
}
}
#endregion
#endregion
#region GetFigureBounds
private Rectangle GetFigureBounds(Rectangle bounds, ContainerVisualStyle cStyle)
{
bounds = GetAdjustedBounds(bounds, cStyle.BorderThickness);
Rectangle scBounds = GetScrollBounds(bounds);
return (scBounds);
}
#endregion
#region GetXyImageBounds
private Rectangle GetXyImageBounds(ChartXyVisualStyle xyStyle)
{
Rectangle scBbounds = GetScrollBounds(ScrollBounds);
scBbounds = GetAdjustedBounds(scBbounds, xyStyle.BorderThickness);
if (xyStyle.EnableImageScroll != Tbool.False)
{
scBbounds = GetScrollBounds(ScrollBoundsEx);
scBbounds = GetDisplayBounds(scBbounds);
}
if (HScrollBar.Visible == true)
scBbounds.Height -= HScrollBar.Height;
if (VScrollBar.Visible == true)
scBbounds.Width -= VScrollBar.Width;
return (scBbounds);
}
#endregion
#region RenderGrid
private void RenderGrid(ChartRenderInfo renderInfo, bool displayOnTop)
{
Rectangle scContentBounds = GetScrollBounds(ContentBounds);
if (scContentBounds.Width > 0 && scContentBounds.Height > 0)
{
RenderGridLines(renderInfo, displayOnTop, AncillaryAxesX, AxisX);
RenderGridLines(renderInfo, displayOnTop, AncillaryAxesY, AxisY);
}
}
#region RenderGridLines
private void RenderGridLines(ChartRenderInfo renderInfo,
bool displayOnTop, ChartAxesCollection axes, ChartAxis axis)
{
foreach (ChartAxis ca in axes)
{
if (ca.Visible == true)
{
if (ca.MajorGridLines.DisplayOnTop == displayOnTop)
ca.MajorGridLines.Render(renderInfo);
if (ca.MinorGridLines.DisplayOnTop == displayOnTop)
ca.MinorGridLines.Render(renderInfo);
}
}
if (axis.MajorGridLines.DisplayOnTop == displayOnTop)
axis.MajorGridLines.Render(renderInfo);
if (axis.MinorGridLines.DisplayOnTop == displayOnTop)
axis.MinorGridLines.Render(renderInfo);
}
#endregion
#endregion
#region RenderReferences
private void RenderReferences(ChartRenderInfo renderInfo, bool displayOnTop)
{
Rectangle scContentBounds = GetScrollBounds(ContentBounds);
if (scContentBounds.Width > 0 && scContentBounds.Height > 0)
{
RenderReferenceLines(renderInfo, displayOnTop, AncillaryAxesX, AxisX);
RenderReferenceLines(renderInfo, displayOnTop, AncillaryAxesY, AxisY);
}
}
#region RenderReferenceLines
private void RenderReferenceLines(ChartRenderInfo renderInfo,
bool displayOnTop, ChartAxesCollection axes, ChartAxis axis)
{
foreach (ChartAxis ca in axes)
{
foreach (ReferenceLine line in ca.ReferenceLines)
RenderReferenceLine(renderInfo, line, displayOnTop);
}
if (axis.Visible == true)
{
foreach (ReferenceLine line in axis.ReferenceLines)
RenderReferenceLine(renderInfo, line, displayOnTop);
}
}
#region RenderReferenceLine
private void RenderReferenceLine(
ChartRenderInfo renderInfo, ReferenceLine line, bool displayOnTop)
{
if (line.Visible == true)
{
if (line.ShowCheckBoxInLegend == false || line.CheckedInLegend == true)
{
if (line.DisplayLineOnTop == displayOnTop)
line.RenderLine(renderInfo);
if (line.DisplayTextOnTop == displayOnTop)
line.RenderLineText(renderInfo);
}
}
}
#endregion
#endregion
#endregion
#region RenderPointLabels
private void RenderPointLabels(Graphics g)
{
Point pt = GetLocalAdjustedPoint(Point.Empty);
List pointLabels = UpdatePointLabels(g);
if (pointLabels.Count > 0)
{
SmoothingMode sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
RenderPointConnector(g, pt, pointLabels);
RenderPointLabel(g, pt, pointLabels);
g.SmoothingMode = sm;
}
}
#region UpdatePointLabels
private List UpdatePointLabels(Graphics g)
{
if (_PointLabels == null)
{
List labelGroups = new List();
foreach (ChartSeries series in ChartSeries)
{
if (series.IsDisplayed == true)
{
List list = series.GetPointLabels(g);
if (list != null)
{
PointLabelGroup plg = new PointLabelGroup(series, list);
labelGroups.Add(plg);
}
}
}
UpdatePointLabelsEx(g, labelGroups);
FlockAlign falign = new FlockAlign(labelGroups);
ContainerVisualStyle cstyle = GetEffectiveContainerStyle();
Rectangle r = GetAdjustedBounds(ContentBoundsEx, cstyle.BorderThickness);
falign.Iterate(r, DataLabelOverlapMode);
_PointLabels = labelGroups;
}
return (_PointLabels);
}
#region UpdatePointLabelsEx
private void UpdatePointLabelsEx(Graphics g, List labelGroups)
{
ChartControl control = ChartControl;
if (control.IsPointLabelUpdateHooked == true)
{
for (int i = 0; i < labelGroups.Count; i++)
{
PointLabelGroup lg = labelGroups[i];
List lps = lg.PointLabels;
control.DoPointLabelUpdateEvent(this, lg.ChartSeries, lps);
for (int j = 0; j < lps.Count; j++)
{
PointLabel pl = lps[j];
if (pl.IsFixedSize == false && pl.NeedsMeasured == true)
pl.LabelSize = lg.ChartSeries.MeasurePointLabel(g, pl);
}
}
}
}
#endregion
#endregion
#region RenderPointConnector
private void RenderPointConnector(
Graphics g, Point pt, List labelGroups)
{
ChartControl chartControl = ChartControl;
foreach (PointLabelGroup lg in labelGroups)
{
ChartSeries series = lg.ChartSeries;
foreach (PointLabel pl in lg.PointLabels)
{
if (pl.Visible == true &&
pl.SeriesPoint.IsEmpty == false && pl.EdgePoint.IsEmpty == false)
{
DataLabelVisualStyle dstyle = series.GetPointLabelVisualStyle(pl);
ConnectorLineVisualStyle cstyle = dstyle.ConnectorLineStyle;
if (dstyle.DrawConnector == Tbool.True && cstyle.LinePattern != LinePattern.None)
{
if (pl.Bounds.IsEmpty == false)
{
Rectangle r = pl.Bounds;
r.Offset(pt);
Point pt1 = pl.Point;
pt1.Offset(pt);
Point pt2 = pl.EdgePoint;
pt2.Offset(pt);
bool isChpt = IsCrosshairSeriesPoint(null, pt1);
if (cstyle.Origin == ConnectorOrigin.Edge)
{
int offset = Math.Max(
pl.SeriesPoint.PointSize.Width,
pl.SeriesPoint.PointSize.Height) / 2 + 1;
double radians = MathHelper.ToRadians(pl.Angle);
int x = (int)(Math.Cos(radians) * offset);
int y = (int)(Math.Sin(radians) * offset);
pt1.X += (int)(Math.Cos(radians) * offset);
pt1.Y += (int)(Math.Sin(radians) * offset);
}
if (r.Contains(pt1) == false)
{
if (chartControl.DoPreRenderPointConnectorEvent(g, this, series, pl, isChpt, pt1, pt2) == false)
{
using (Pen pen = new Pen(cstyle.LineColor, Dpi.Width(cstyle.LineWidth)))
{
if (cstyle.LinePattern != LinePattern.NotSet)
pen.DashStyle = (DashStyle)cstyle.LinePattern;
g.DrawLine(pen, pt1, pt2);
}
chartControl.DoPostRenderPointConnectorEvent(g, this, series, pl, isChpt, pt1, pt2);
}
}
}
}
}
}
}
}
#endregion
#region RenderPointLabel
private void RenderPointLabel(
Graphics g, Point pt, List labelGroups)
{
ChartControl chartControl = ChartControl;
foreach (PointLabelGroup lg in labelGroups)
{
ChartSeries series = lg.ChartSeries;
foreach (PointLabel pl in lg.PointLabels)
{
if (pl.Visible == true && pl.SeriesPoint.IsEmpty == false)
{
Rectangle r = pl.Bounds;
if (r.IsEmpty == false)
{
DataLabelVisualStyle dstyle = series.GetPointLabelVisualStyle(pl);
Point pt1 = r.Location;
pt1.Offset(pt);
r.Location = pt1;
Point pt2 = pl.Point;
pt2.Offset(pt);
bool isChpt = IsCrosshairSeriesPoint(null, pt2);
if (chartControl.DoPreRenderPointLabelEvent(g, this, series, pl, isChpt, r) == false)
{
using (StringFormat sf = new StringFormat())
{
dstyle.GetStringFormatFlags(sf);
Color textColor = dstyle.TextColor;
Color borderColor = dstyle.BorderColor;
Background background = dstyle.Background;
LinePattern borderPattern = dstyle.BorderPattern;
if (isChpt == true)
{
if (dstyle.HighlightTextColor.IsEmpty == false)
textColor = dstyle.HighlightTextColor;
if (dstyle.HighlightBorderColor.IsEmpty == false)
borderColor = dstyle.HighlightBorderColor;
if (dstyle.HighlightBackground.IsEmpty == false)
background = dstyle.HighlightBackground;
if (dstyle.HighlightBorderPattern != LinePattern.NotSet)
borderPattern = dstyle.HighlightBorderPattern;
}
RenderPointLabelEx(g, lg, pl, r, textColor,
background, borderColor, dstyle.BorderThickness, borderPattern, dstyle, sf);
}
chartControl.DoPostRenderPointLabelEvent(g, this, series, pl, isChpt, r);
}
}
}
}
}
}
#region RenderPointLabelEx
private void RenderPointLabelEx(Graphics g, PointLabelGroup lg, PointLabel pl,
Rectangle r, Color tcolor, Background background, Color bcolor,
int thickness, LinePattern pattern, DataLabelVisualStyle dstyle, StringFormat sf)
{
if (background.IsEmpty == false)
{
using (Brush hbr = background.GetBrush(r))
g.FillRectangle(hbr, r);
}
g.SmoothingMode = SmoothingMode.None;
using (Pen hBorderPen = GetBorderPen(bcolor, thickness, pattern))
{
if (hBorderPen != null)
g.DrawRectangle(hBorderPen, r);
}
if (dstyle.DropShadow.Enabled == Tbool.True)
dstyle.DropShadow.RenderDropShadow(g, r, true, true);
RotateDegrees rotateDegrees = lg.ChartSeries.GetRotateDegrees(dstyle);
float angle = GetRotateAngle(rotateDegrees);
r.Size = pl.LabelSize;
Point ptc = new Point(
r.X + pl.Bounds.Width / 2,
r.Y + pl.Bounds.Height / 2);
if (angle != 0)
{
g.TranslateTransform(ptc.X, ptc.Y);
g.RotateTransform(angle);
r.X = -((r.Width + dstyle.Padding.Horizontal) / 2);
r.Y = -((r.Height + dstyle.Padding.Vertical) / 2);
if (angle == 90)
r.Y--;
else if (angle == 270)
r.X--;
r.X += dstyle.Padding.Left;
r.Y += dstyle.Padding.Top;
}
else
{
if (dstyle.HasBorder == true)
{
r.X += dstyle.BorderThickness;
r.Y += dstyle.BorderThickness;
}
r.X += dstyle.Padding.Left;
r.Y += dstyle.Padding.Top;
}
using (Brush htbr = new SolidBrush(tcolor))
g.DrawString(pl.Label, dstyle.Font, htbr, r, sf);
if (angle != 0)
g.ResetTransform();
}
#region GetRotateAngle
private float GetRotateAngle(RotateDegrees rotateDegrees)
{
switch (rotateDegrees)
{
case RotateDegrees.Rotate90:
return (90);
case RotateDegrees.Rotate180:
return (180);
case RotateDegrees.Rotate270:
return (270);
default:
return (0);
}
}
#endregion
#region GetBorderPen
private Pen GetBorderPen(Color color, int thickness, LinePattern pattern)
{
Pen pen = null;
if (pattern != LinePattern.None && pattern != LinePattern.NotSet &&
color.IsEmpty == false && thickness > 0)
{
pen = new Pen(color, Dpi.Width(thickness));
pen.Alignment = PenAlignment.Inset;
if (pattern != LinePattern.NotSet)
pen.DashStyle = (DashStyle)pattern;
}
return (pen);
}
#endregion
#endregion
#endregion
#endregion
#region RenderAxes
private void RenderAxes(ChartRenderInfo renderInfo,
ChartAxesCollection axes, ChartAxis axis)
{
foreach (ChartAxis ca in axes)
{
if (ca.Visible == true)
ca.Render(renderInfo);
}
if (axis.Visible == true)
axis.Render(renderInfo);
}
#endregion
#region RenderCrosshair
#region GetCrosshairBounds
private Rectangle GetCrosshairBounds(ContainerVisualStyle cstyle)
{
ChartCrosshair crosshair = ChartCrosshair;
Rectangle bounds = GetScrollBounds(ContentBounds);
if (cstyle.BorderThickness.IsEmpty == false)
{
bounds.X += Dpi.Width(cstyle.BorderThickness.Left);
bounds.Width -= Dpi.Width(cstyle.BorderThickness.Horizontal);
bounds.Y += Dpi.Height(cstyle.BorderThickness.Top);
bounds.Height -= Dpi.Height(cstyle.BorderThickness.Vertical);
}
if (HScrollBar.Visible == true)
bounds.Height -= (HScrollBar.Height + 1);
if (VScrollBar.Visible == true)
bounds.Width -= (VScrollBar.Width + 1);
return (bounds);
}
#endregion
#region GetCrosshairPoints
private List GetCrosshairPoints(Rectangle bounds, Point pt)
{
List cps;
if (ChartCrosshair.AxisOrientation == AxisOrientation.X)
cps = GetCrosshairPointsX(pt, bounds);
else
cps = GetCrosshairPointsY(pt, bounds);
_NearestCrosshairPoint = null;
if (cps != null && cps.Count > 0)
{
if (ChartCrosshair.CrosshairLabelMode == CrosshairLabelMode.NearestSeries)
_NearestCrosshairPoint = GetNearestPoint(cps, pt, ChartCrosshair.AxisOrientation);
}
return (cps);
}
#endregion
#region RenderCrosshair
internal void RenderCrosshairLines(Graphics g,
Rectangle bounds, Point pt, CrosshairVisualStyle cstyle)
{
if (ChartCrosshair.AxisOrientation == AxisOrientation.X)
RenderCrosshairX(g, bounds, pt, cstyle);
else
RenderCrosshairY(g, bounds, pt, cstyle);
}
#region RenderCrosshairX
private void RenderCrosshairX(Graphics g,
Rectangle bounds, Point pt, CrosshairVisualStyle cstyle)
{
ChartCrosshair crosshair = ChartCrosshair;
List cps = _CrosshairSeriesPoints;
if (crosshair.ShowValueXLine == true)
RenderCrosshairLineX(g, pt, bounds, cstyle);
if (crosshair.ShowValueXLabels == true)
RenderCrosshairLabelX(g, pt);
if (crosshair.ShowValueYLine == true || crosshair.ShowValueYLabels == true)
{
if (crosshair.CrosshairLabelMode == CrosshairLabelMode.NearestSeries)
{
CrosshairPoint mcp = _NearestCrosshairPoint;
if (mcp != null)
{
if (crosshair.ShowValueYLine == true)
RenderCrosshairLineY(g, mcp.Point, bounds, cstyle);
if (crosshair.ShowValueYLabels == true)
RenderCrosshairLabelY(g, mcp);
}
}
else
{
foreach (CrosshairPoint cp in cps)
{
if (crosshair.ShowValueYLine == true)
RenderCrosshairLineY(g, cp.Point, bounds, cstyle);
if (crosshair.ShowValueYLabels == true)
RenderCrosshairLabelY(g, cp);
}
}
}
}
#region GetCrosshairPointsX
private List GetCrosshairPointsX(Point pt, Rectangle bounds)
{
List cps = new List();
for (int i = 0; i < ChartSeries.Count; i++)
{
ChartSeries series = ChartSeries[i];
if (series.IsDisplayed == true && series.CrosshairEnabled != Tbool.False)
{
if (series.SeriesPoints.Count > 0)
{
SortedSeriesPoints ssp = series.GetSortedSeriesPoints(this);
ChartAxis axis = (series.IsRotated == true)
? series.AxisY ?? AxisY : series.AxisX ?? AxisX;
TickmarkLayout layout = axis.TickmarkLayout;
if (layout.Ticks != null && layout.Ticks.Length > 0)
{
Size msize = GetCrosshairMarkerSize(series);
for (int j = 0; j < ssp.Count; j++)
SetCrosshairPointX(cps, series, ssp, j, msize, pt, bounds);
}
}
}
}
return (cps);
}
#region SetCrosshairPointX
private void SetCrosshairPointX(List cps, ChartSeries series,
SortedSeriesPoints ssp, int index, Size msize, Point pt, Rectangle bounds)
{
SeriesPoint sp = ssp[index];
if (sp.IsEmpty == false)
{
int vindex = 0;
bool descending = false;
Point spt = Point.Empty;
Point lpt = GetLocalAdjustedPoint(spt);
switch (series.SeriesType)
{
case SeriesType.VerticalDot:
spt = GetDataPointEx(series, sp, -1);
spt.Offset(lpt);
spt.Y -= (msize.Height * ssp.CountArray[index]);
spt.Y += (msize.Height / 2);
break;
case SeriesType.HorizontalDot:
object x1 = GetDataPointValueX(series, sp);
spt = GetPointFromValue(series, 0, x1);
spt.Offset(lpt);
spt.X += (msize.Width * ssp.CountArray[index]);
spt.X -= (msize.Width / 2);
break;
case SeriesType.VerticalBar:
spt = GetDataPointEx(series, sp, 0);
spt.Offset(lpt);
spt.X += series.BarOffset;
int yStart = series.GetVBarStart(this, sp) + lpt.Y;
descending = (spt.Y > yStart);
if (sp.ValueY.Length > 1)
{
AddCrosshairPointX(cps, series,
ssp, index, sp, 0, spt, msize, pt, bounds, descending);
spt.Y = yStart;
vindex = 1;
descending = !descending;
}
break;
case SeriesType.HorizontalBar:
spt = GetDataPointEx(series, sp, 0);
spt.Offset(lpt);
spt.Y += series.BarOffset;
int xStart = series.GetHBarStart(this, sp) + lpt.X;
descending = (spt.X < xStart);
if (sp.ValueY.Length > 1)
{
AddCrosshairPointX(cps, series,
ssp, index, sp, 0, spt, msize, pt, bounds, descending);
spt.X = xStart;
vindex = 1;
descending = !descending;
}
break;
case SeriesType.VerticalHiLoBar:
SetCrosshairPointVHiLoX(cps, series, ssp, index, msize, pt, bounds);
return;
case SeriesType.HorizontalHiLoBar:
SetCrosshairPointHHiLoX(cps, series, ssp, index, msize, pt, bounds);
return;
case SeriesType.Point:
for (int i = 0; i < sp.ValueY.Length; i++)
{
spt = GetDataPointEx(series, sp, i);
spt.Offset(lpt);
AddCrosshairPointX(cps, series,
ssp, index, sp, i, spt, msize, pt, bounds, descending);
}
return;
default:
spt = GetDataPoint(series, sp, 0);
break;
}
AddCrosshairPointX(cps, series,
ssp, index, sp, vindex, spt, msize, pt, bounds, descending);
}
}
#region SetCrosshairPointVHiLoX
private void SetCrosshairPointVHiLoX(List cps,
ChartSeries series, SortedSeriesPoints ssp, int index, Size msize, Point pt, Rectangle bounds)
{
Point spt = Point.Empty;
Point lpt = GetLocalAdjustedPoint(spt);
SeriesPoint sp = ssp[index];
spt = GetDataPointEx(series, sp, 0);
spt.X += (series.BarOffset + lpt.X);
int[] values = GetVStockValues(series, sp);
int v0, v1, v2, v3;
NormalizeStockValues(values, out v0, out v1, out v2, out v3);
if (values[v2] != int.MinValue)
{
spt.Y = values[v2] + lpt.Y;
AddCrosshairPointX(cps, series,
ssp, index, sp, v2, spt, msize, pt, bounds, false);
}
if (values[v3] != int.MinValue)
{
spt.Y = values[v3] + lpt.Y;
AddCrosshairPointX(cps, series,
ssp, index, sp, v3, spt, msize, pt, bounds, true);
}
if (values[v2] == int.MinValue || values[v0] < values[v2])
{
spt.Y = values[v0] + lpt.Y;
AddCrosshairPointX(cps, series,
ssp, index, sp, v0, spt, msize, pt, bounds, false);
}
if (values[v3] == int.MinValue || values[v1] > values[v3])
{
spt.Y = values[v1] + lpt.Y;
AddCrosshairPointX(cps, series,
ssp, index, sp, v1, spt, msize, pt, bounds, true);
}
}
#region GetVStockValues
private int[] GetVStockValues(ChartSeries series, SeriesPoint sp)
{
ChartAxis axis = series.AxisY ?? AxisY;
int[] values = new int[4];
for (int i = 0; i < values.Length; i++)
{
if (i < sp.ValueY.Length)
values[i] = GetDataPointY(axis, sp.ValueY[i]);
else
values[i] = int.MinValue;
}
return (values);
}
#endregion
#endregion
#region SetCrosshairPointHHiLoX
private void SetCrosshairPointHHiLoX(List cps,
ChartSeries series, SortedSeriesPoints ssp, int index, Size msize, Point pt, Rectangle bounds)
{
Point spt = Point.Empty;
Point lpt = GetLocalAdjustedPoint(spt);
SeriesPoint sp = ssp[index];
spt = GetDataPointEx(series, sp, 0);
spt.Y += (series.BarOffset + lpt.Y);
int[] values = GetHStockValues(series, sp);
int v0, v1, v2, v3;
NormalizeStockValues(values, out v0, out v1, out v2, out v3);
if (values[v2] != int.MinValue)
{
spt.X = values[v2] + lpt.X;
AddCrosshairPointX(cps, series,
ssp, index, sp, v2, spt, msize, pt, bounds, true);
}
if (values[v3] != int.MinValue)
{
spt.X = values[v3] + lpt.X;
AddCrosshairPointX(cps, series,
ssp, index, sp, v3, spt, msize, pt, bounds, false);
}
if (values[v2] == int.MinValue || values[v0] < values[v2])
{
spt.X = values[v0] + lpt.X;
AddCrosshairPointX(cps, series,
ssp, index, sp, v0, spt, msize, pt, bounds, true);
}
if (values[v3] == int.MinValue || values[v1] > values[v3])
{
spt.X = values[v1] + lpt.X;
AddCrosshairPointX(cps, series,
ssp, index, sp, v1, spt, msize, pt, bounds, false);
}
}
#region GetHStockValues
private int[] GetHStockValues(ChartSeries series, SeriesPoint sp)
{
ChartAxis axis = series.AxisX ?? AxisX;
int[] values = new int[4];
for (int i = 0; i < values.Length; i++)
{
if (i < sp.ValueY.Length)
values[i] = GetDataPointX(axis, sp.ValueY[i]);
else
values[i] = int.MinValue;
}
return (values);
}
#endregion
#endregion
#region NormalizeStockValues
private void NormalizeStockValues(int[] values,
out int v0, out int v1, out int v2, out int v3)
{
v0 = 0;
v1 = 1;
v2 = 2;
v3 = 3;
if (values[1] < values[0])
{
v0 = 1;
v1 = 0;
}
if (values[v3] != int.MinValue && values[v3] < values[v2])
{
v2 = 3;
v3 = 2;
}
if (values[v2] != int.MinValue)
{
if (values[v2] < values[v0])
v0 = v2;
if (values[v2] > values[v1])
v1 = v2;
}
if (values[v3] != int.MinValue)
{
if (values[v3] > values[v1])
v1 = v3;
if (values[v3] < values[v0])
v0 = v3;
}
}
#endregion
#region AddCrosshairPointX
private void AddCrosshairPointX(List cps, ChartSeries series,
SortedSeriesPoints ssp, int index, SeriesPoint sp, int vindex, Point spt,
Size msize, Point pt, Rectangle bounds, bool descending)
{
if (spt != Point.Empty && bounds.Contains(spt))
{
int dx = ChartCrosshair.PointIntersectMargin;
if (ChartCrosshair.PointIntersectMode == PointIntersectMode.Edge)
{
if (sp.PointSize.Width > 0)
dx += (sp.PointSize.Width / 2);
else
dx += (msize.Height / 2);
}
if (spt.X >= pt.X - dx && spt.X <= pt.X + dx)
cps.Add(new CrosshairPoint(series, ssp, index, sp, vindex, spt, descending));
}
}
#endregion
#endregion
#endregion
#endregion
#region RenderCrosshairY
private void RenderCrosshairY(Graphics g,
Rectangle bounds, Point pt, CrosshairVisualStyle cstyle)
{
ChartCrosshair crosshair = ChartCrosshair;
List cps = _CrosshairSeriesPoints;
if (crosshair.ShowValueYLine == true)
RenderCrosshairLineY(g, pt, bounds, cstyle);
if (crosshair.ShowValueYLabels == true)
RenderCrosshairLabelY(g, pt);
if (crosshair.ShowValueXLine == true || crosshair.ShowValueXLabels == true)
{
if (crosshair.CrosshairLabelMode == CrosshairLabelMode.NearestSeries)
{
CrosshairPoint mcp = _NearestCrosshairPoint;
if (mcp != null)
{
if (crosshair.ShowValueXLine == true)
RenderCrosshairLineX(g, mcp.Point, bounds, cstyle);
if (crosshair.ShowValueXLabels == true)
RenderCrosshairLabelX(g, mcp);
}
}
else
{
foreach (CrosshairPoint cp in cps)
{
if (crosshair.ShowValueXLine == true)
RenderCrosshairLineX(g, cp.Point, bounds, cstyle);
if (crosshair.ShowValueXLabels == true)
RenderCrosshairLabelX(g, cp);
}
}
}
}
#region GetCrosshairPointsY
private List GetCrosshairPointsY(Point pt, Rectangle bounds)
{
List cps = new List();
for (int i = 0; i < ChartSeries.Count; i++)
{
ChartSeries series = ChartSeries[i];
if (series.IsDisplayed == true && series.CrosshairEnabled != Tbool.False)
{
if (series.SeriesPoints.Count > 0)
{
SortedSeriesPoints ssp = series.GetSortedSeriesPoints(this);
ChartAxis axis = series.AxisX ?? AxisX;
TickmarkLayout layout = axis.TickmarkLayout;
if (layout.Ticks != null && layout.Ticks.Length > 0)
{
Size msize = GetCrosshairMarkerSize(series);
for (int j = 0; j < ssp.Count; j++)
SetCrosshairPointY(cps, series, ssp, j, msize, pt, bounds);
}
}
}
}
return (cps);
}
#region SetCrosshairPointY
private void SetCrosshairPointY(List cps, ChartSeries series,
SortedSeriesPoints ssp, int index, Size msize, Point pt, Rectangle bounds)
{
SeriesPoint sp = ssp[index];
if (sp.IsEmpty == false)
{
int vindex = 0;
bool descending = false;
Point spt = Point.Empty;
Point lpt = GetLocalAdjustedPoint(spt);
switch (series.SeriesType)
{
case SeriesType.VerticalDot:
spt = GetDataPointEx(series, sp, -1);
spt.Offset(lpt);
spt.Y -= (msize.Height * ssp.CountArray[index] - msize.Height / 2);
break;
case SeriesType.HorizontalDot:
object x1 = GetDataPointValueX(series, sp);
spt = GetPointFromValue(series, 0, x1);
spt.Offset(lpt);
spt.X += (msize.Width * ssp.CountArray[index] - msize.Width / 2);
break;
case SeriesType.VerticalBar:
spt = GetDataPointEx(series, sp, 0);
spt.Offset(lpt);
spt.X += series.BarOffset;
int yStart = series.GetVBarStart(this, sp) + lpt.Y;
descending = (spt.Y > yStart);
if (sp.ValueY.Length > 1)
{
AddCrosshairPointY(cps, series,
ssp, index, sp, 0, spt, msize, pt, bounds, descending);
spt.Y = yStart;
vindex = 1;
descending = !descending;
}
break;
case SeriesType.HorizontalBar:
spt = GetDataPointEx(series, sp, 0);
spt.Offset(lpt);
spt.Y += series.BarOffset;
int xStart = series.GetHBarStart(this, sp) + lpt.X;
descending = (spt.X < xStart);
if (sp.ValueY.Length > 1)
{
AddCrosshairPointX(cps, series,
ssp, index, sp, 0, spt, msize, pt, bounds, descending);
spt.X = xStart;
vindex = 1;
descending = !descending;
}
break;
case SeriesType.VerticalHiLoBar:
SetCrosshairPointVHiLoY(cps, series, ssp, index, msize, pt, bounds);
return;
case SeriesType.HorizontalHiLoBar:
SetCrosshairPointHHiLoY(cps, series, ssp, index, msize, pt, bounds);
return;
case SeriesType.Point:
for (int i = 0; i < sp.ValueY.Length; i++)
{
spt = GetDataPointEx(series, sp, i);
spt.Offset(lpt);
AddCrosshairPointY(cps, series,
ssp, index, sp, i, spt, msize, pt, bounds, descending);
}
return;
default:
spt = GetDataPoint(series, sp, 0);
break;
}
AddCrosshairPointY(cps, series,
ssp, index, sp, vindex, spt, msize, pt, bounds, descending);
}
}
#region SetCrosshairPointVHiLoY
private void SetCrosshairPointVHiLoY(List cps,
ChartSeries series, SortedSeriesPoints ssp, int index, Size msize, Point pt, Rectangle bounds)
{
Point spt = Point.Empty;
Point lpt = GetLocalAdjustedPoint(spt);
SeriesPoint sp = ssp[index];
spt = GetDataPointEx(series, sp, 0);
spt.X += (series.BarOffset + lpt.X);
int[] values = GetVStockValues(series, sp);
int v0, v1, v2, v3;
NormalizeStockValues(values, out v0, out v1, out v2, out v3);
if (values[v2] != int.MinValue)
{
spt.Y = values[v2] + lpt.Y;
AddCrosshairPointY(cps, series,
ssp, index, sp, v2, spt, msize, pt, bounds, false);
}
if (values[v3] != int.MinValue)
{
spt.Y = values[v3] + lpt.Y;
AddCrosshairPointY(cps, series,
ssp, index, sp, v3, spt, msize, pt, bounds, true);
}
if (values[v2] == int.MinValue || values[v0] < values[v2])
{
spt.Y = values[v0] + lpt.Y;
AddCrosshairPointY(cps, series,
ssp, index, sp, v0, spt, msize, pt, bounds, false);
}
if (values[v3] == int.MinValue || values[v1] > values[v3])
{
spt.Y = values[v1] + lpt.Y;
AddCrosshairPointY(cps, series,
ssp, index, sp, v1, spt, msize, pt, bounds, true);
}
}
#endregion
#region SetCrosshairPointHHiLoY
private void SetCrosshairPointHHiLoY(List cps,
ChartSeries series, SortedSeriesPoints ssp, int index, Size msize, Point pt, Rectangle bounds)
{
Point spt = Point.Empty;
Point lpt = GetLocalAdjustedPoint(spt);
SeriesPoint sp = ssp[index];
spt = GetDataPointEx(series, sp, 0);
spt.Y += (series.BarOffset + lpt.Y);
int[] values = GetHStockValues(series, sp);
int v0, v1, v2, v3;
NormalizeStockValues(values, out v0, out v1, out v2, out v3);
if (values[v2] != int.MinValue)
{
spt.X = values[v2] + lpt.X;
AddCrosshairPointY(cps, series,
ssp, index, sp, v2, spt, msize, pt, bounds, true);
}
if (values[v3] != int.MinValue)
{
spt.X = values[v3] + lpt.X;
AddCrosshairPointY(cps, series,
ssp, index, sp, v3, spt, msize, pt, bounds, false);
}
if (values[v2] == int.MinValue || values[v0] < values[v2])
{
spt.X = values[v0] + lpt.X;
AddCrosshairPointY(cps, series,
ssp, index, sp, v0, spt, msize, pt, bounds, true);
}
if (values[v3] == int.MinValue || values[v1] > values[v3])
{
spt.X = values[v1] + lpt.X;
AddCrosshairPointY(cps, series,
ssp, index, sp, v1, spt, msize, pt, bounds, false);
}
}
#endregion
#region AddCrosshairPointY
private void AddCrosshairPointY(List cps, ChartSeries series,
SortedSeriesPoints ssp, int index, SeriesPoint sp, int vindex, Point spt,
Size msize, Point pt, Rectangle bounds, bool descending)
{
if (spt != Point.Empty && bounds.Contains(spt))
{
int dy = ChartCrosshair.PointIntersectMargin;
if (ChartCrosshair.PointIntersectMode == PointIntersectMode.Edge)
{
if (sp.PointSize.Height > 0)
dy += (sp.PointSize.Height / 2);
else
dy += (msize.Height / 2);
}
if (spt.Y >= pt.Y - dy && spt.Y <= pt.Y + dy)
cps.Add(new CrosshairPoint(series, ssp, index, sp, vindex, spt, descending));
}
}
#endregion
#endregion
#endregion
#endregion
#region GetCrosshairMarkerSize
private Size GetCrosshairMarkerSize(ChartSeries series)
{
Size msize = Size.Empty;
if (series.SeriesType == SeriesType.VerticalDot ||
series.SeriesType == SeriesType.HorizontalDot)
{
msize = GetMaxDotPlotMarkerSize();
}
else if (series.IsBarSeries == true)
{
msize = new Size(series.BarWidth, Dpi.Height5);
}
else
{
Image marker = series.PointMarkerImage;
if (marker != null)
msize = marker.Size;
}
return (msize);
}
#endregion
#region RenderCrosshairLineX
private void RenderCrosshairLineX(Graphics g,
Point pt, Rectangle bounds, CrosshairVisualStyle cstyle)
{
Point pt1 = new Point(pt.X, bounds.Y);
Point pt2 = new Point(pt.X, bounds.Bottom - 1);
ChartLineVisualStyle lstyle = cstyle.ValueXLineStyle;
using (Pen pen = new Pen(lstyle.LineColor, Dpi.Width(lstyle.LineWidth)))
{
pen.DashStyle = (DashStyle)lstyle.LinePattern;
g.DrawLine(pen, pt1, pt2);
}
}
#endregion
#region RenderCrosshairLineY
private void RenderCrosshairLineY(Graphics g,
Point pt, Rectangle bounds, CrosshairVisualStyle cstyle)
{
Point pt1 = new Point(bounds.X, pt.Y);
Point pt2 = new Point(bounds.Right - 1, pt.Y);
ChartLineVisualStyle lstyle = cstyle.ValueYLineStyle;
using (Pen pen = new Pen(lstyle.LineColor, Dpi.Height(lstyle.LineWidth)))
{
pen.DashStyle = (DashStyle)lstyle.LinePattern;
g.DrawLine(pen, pt1, pt2);
}
}
#endregion
#region RenderCrosshairLabelX
private void RenderCrosshairLabelX(Graphics g, Point pt)
{
RenderAxesCrosshairLabelXy(g, pt, AncillaryAxesX, AxisX);
}
private void RenderCrosshairLabelX(Graphics g, CrosshairPoint cp)
{
ChartAxis axis = cp.ChartSeries.AxisX ?? AxisX;
if (axis != null)
axis.RenderCrosshairLabel(g, cp);
}
#endregion
#region RenderCrosshairLabelY
private void RenderCrosshairLabelY(Graphics g, Point pt)
{
RenderAxesCrosshairLabelXy(g, pt, AncillaryAxesY, AxisY);
}
private void RenderCrosshairLabelY(Graphics g, CrosshairPoint cp)
{
ChartAxis axis = cp.ChartSeries.AxisY ?? AxisY;
if (axis != null)
axis.RenderCrosshairLabel(g, cp);
}
#endregion
#region RenderAxesCrosshairLabelXy
private void RenderAxesCrosshairLabelXy(Graphics g,
Point pt, ChartAxesCollection axes, ChartAxis axis)
{
foreach (ChartAxis ca in axes)
{
if (ca.Visible == true)
ca.RenderCrosshairLabel(g, pt);
}
if (axis.Visible == true)
axis.RenderCrosshairLabel(g, pt);
}
#endregion
#region GetNearestPoint
private CrosshairPoint GetNearestPoint(
List cps, Point pt, AxisOrientation orientation)
{
CrosshairPoint minPoint = null;
int minValue = int.MaxValue;
int minValue2 = int.MaxValue;
bool comp = (orientation == AxisOrientation.Y);
foreach (CrosshairPoint cp in cps)
{
Point cpt = cp.Point;
int dv = Math.Abs((comp == false) ? (cpt.Y - pt.Y) : (cpt.X - pt.X));
int dv2 = Math.Abs((comp == true) ? (cpt.Y - pt.Y) : (cpt.X - pt.X));
if (dv < minValue)
{
minValue = dv;
minValue2 = dv2;
minPoint = cp;
}
else if (dv == minValue)
{
if (dv2 < minValue2)
{
minValue2 = dv2;
minPoint = cp;
}
}
}
return (minPoint);
}
#endregion
#region GetFirstValue
private object GetFirstValue(TickmarkLayout layout)
{
for (int i = 0; i < layout.Ticks.Length; i++)
{
TickmarkTick tick = layout.Ticks[i];
if (tick.LabelIndex >= 0)
return (tick.Value);
}
return (null);
}
#endregion
#region GetLastValue
private object GetLastValue(TickmarkLayout layout)
{
for (int i = layout.Ticks.Length - 1; i >= 0; i--)
{
TickmarkTick tick = layout.Ticks[i];
if (tick.LabelIndex >= 0)
return (tick.Value);
}
return (null);
}
#endregion
#endregion
#endregion
#region RenderCrosshairLabels
#region RenderCrosshairLabels
private void RenderCrosshairLabels(Graphics g,
Rectangle bounds, Point pt, CrosshairVisualStyle cstyle)
{
if (ChartCrosshair.ShowCrosshairLabels == true)
{
if (ChartControl.DoRenderCrosshairLabelEvent(g, this, _CrosshairSeriesPoints, bounds, pt) == false)
{
if (_CrosshairSeriesPoints != null && _CrosshairSeriesPoints.Count > 0)
{
switch (ChartCrosshair.CrosshairLabelMode)
{
case CrosshairLabelMode.Common:
RenderCrosshairLabelCommon(g, bounds, pt, cstyle);
break;
case CrosshairLabelMode.EachSeries:
RenderCrosshairLabelEach(g, bounds, pt, cstyle);
break;
case CrosshairLabelMode.NearestSeries:
if (_NearestCrosshairPoint != null)
RenderCrosshairLabel(g, bounds, cstyle, _NearestCrosshairPoint);
break;
}
}
}
}
}
#region RenderCrosshairLabelCommon
private void RenderCrosshairLabelCommon(Graphics g,
Rectangle bounds, Point pt, CrosshairVisualStyle cstyle)
{
Hashtable gps = GetCrosshairLabelGroups(_CrosshairSeriesPoints);
MeasureCrosshairLabelGroups(g, gps, bounds, cstyle);
int markerWidth;
Rectangle cbounds = GetCrosshairCommonBounds(gps, bounds, pt, cstyle, out markerWidth);
cbounds = GetAdjustedBounds(cbounds, cstyle.Margin);
if (ChartControl.DoRenderCrosshairCalloutEvent(g, this, cbounds, pt, cstyle) == false)
DrawRoundRectangle(g, cbounds, cstyle);
cbounds = GetAdjustedBounds(cbounds, cstyle.Padding);
RenderCrosshairLabelGroups(g, gps, cbounds, cstyle);
}
#region GetCrosshairLabelGroups
private Hashtable GetCrosshairLabelGroups(List cps)
{
Hashtable gps = new Hashtable();
foreach (CrosshairPoint cp in cps)
{
ChartAxis axis;
if (ChartCrosshair.AxisOrientation == AxisOrientation.X)
axis = cp.ChartSeries.AxisX ?? AxisX;
else
axis = cp.ChartSeries.AxisY ?? AxisY;
CrosshairGroup group = gps[axis] as CrosshairGroup;
if (group == null)
{
group = new CrosshairGroup();
group.Cps = new List();
group.Text = GetCrosshairHeader(cp, cps);
gps[axis] = group;
}
group.Cps.Add(cp);
}
return (gps);
}
#endregion
#region MeasureCrosshairLabelGroups
private void MeasureCrosshairLabelGroups(Graphics g,
Hashtable gps, Rectangle bounds, CrosshairVisualStyle cstyle)
{
bool groupHeader = ChartCrosshair.ShowGroupHeaders;
foreach (DictionaryEntry pair in gps)
{
CrosshairGroup group = (CrosshairGroup)pair.Value;
if (groupHeader == true)
MeasureCrosshairGroupHeader(g, group, bounds, cstyle);
MeasureCrosshairCommonLabels(g, group, bounds, cstyle, groupHeader ? null : group.Text);
}
}
#region MeasureCrosshairGroupHeader
private void MeasureCrosshairGroupHeader(Graphics g,
CrosshairGroup group, Rectangle bounds, CrosshairVisualStyle cstyle)
{
if (string.IsNullOrEmpty(group.Text) == false)
{
SizeF sizef = g.MeasureString(group.Text, cstyle.GroupHeaderFont, bounds.Width);
group.TextSize = new Size((int)sizef.Width + 1, (int)sizef.Height + 1);
}
}
#endregion
#region MeasureCrosshairCommonLabels
private void MeasureCrosshairCommonLabels(Graphics g,
CrosshairGroup group, Rectangle bounds, CrosshairVisualStyle cstyle, string header)
{
group.LabelSize = Size.Empty;
group.MarkerWidth = 0;
foreach (CrosshairPoint cp in group.Cps)
{
Size markerSize = Size.Empty;
Image marker = cp.ChartSeries.PointMarkerImage;
if (marker != null)
{
markerSize = marker.Size;
if (marker.Width > group.MarkerWidth)
group.MarkerWidth = marker.Width;
}
MeasureCrosshairLabel(g, bounds, cp, cstyle, header, false);
if (cp.TextSize.IsEmpty == false)
{
group.LabelSize.Height += Math.Max(markerSize.Height, cp.TextSize.Height);
if (markerSize.Width + cp.TextSize.Width > group.LabelSize.Width)
group.LabelSize.Width = markerSize.Width + cp.TextSize.Width;
}
}
}
#endregion
#endregion
#region GetCrosshairCommonBounds
private Rectangle GetCrosshairCommonBounds(Hashtable gps,
Rectangle bounds, Point pt, CrosshairVisualStyle cstyle, out int markerWidth)
{
markerWidth = 0;
Size totalSize = Size.Empty;
foreach (DictionaryEntry pair in gps)
{
CrosshairGroup group = (CrosshairGroup)pair.Value;
totalSize.Width = Math.Max(totalSize.Width, group.TextSize.Width);
totalSize.Height += (group.TextSize.Height + Dpi.Width4);
foreach (CrosshairPoint cp in group.Cps)
{
Size markerSize = Size.Empty;
Image marker = cp.ChartSeries.PointMarkerImage;
if (marker != null)
markerSize = Dpi.Size(marker.Size);
markerWidth = Math.Max(markerWidth, markerSize.Width);
totalSize.Width = Math.Max(totalSize.Width, cp.TextSize.Width);
totalSize.Height += (Math.Max(markerSize.Height, cp.TextSize.Height) + Dpi.Width4);
}
}
totalSize.Width += markerWidth;
totalSize.Width += (cstyle.Margin.Horizontal + cstyle.Padding.Horizontal + Dpi.Width4);
totalSize.Height += (cstyle.Margin.Horizontal + cstyle.Padding.Horizontal - Dpi.Width4);
return (GetCrosshairLabelBounds(bounds, pt, totalSize));
}
#region GetCrosshairLabelBounds
private Rectangle GetCrosshairLabelBounds(
Rectangle bounds, Point pt, Size size)
{
Rectangle r;
int left = pt.X - bounds.X - Dpi.Width10;
int right = bounds.Right - pt.X - Dpi.Width10;
if ((right >= size.Width) || (right > left))
{
r = new Rectangle(pt.X + 10, pt.Y - size.Height,
size.Width, size.Height);
}
else
{
r = new Rectangle(pt.X - (size.Width + Dpi.Width10),
pt.Y - size.Height, size.Width, size.Height);
}
r.Y -= Dpi.Height10;
if (r.Y < ContentBounds.Y + Dpi.Height2)
r.Y = ContentBounds.Y + Dpi.Height2;
return (r);
}
#endregion
#endregion
#region RenderCrosshairLabelGroups
private void RenderCrosshairLabelGroups(Graphics g,
Hashtable gps, Rectangle bounds, CrosshairVisualStyle cstyle)
{
using (Brush br = new SolidBrush(cstyle.GroupHeaderTextColor))
{
foreach (DictionaryEntry pair in gps)
{
CrosshairGroup group = (CrosshairGroup)pair.Value;
Rectangle r = bounds;
r.Height = group.TextSize.Height;
if (string.IsNullOrEmpty(group.Text) == false)
{
g.DrawString(group.Text, cstyle.GroupHeaderFont, br, r);
bounds.Y += (group.TextSize.Height + Dpi.Height4);
bounds.Height -= (group.TextSize.Height + Dpi.Height4);
}
foreach (CrosshairPoint cp in group.Cps)
{
if (cp.TextSize.IsEmpty == false)
{
RenderCrosshairLabelItem(g, bounds, cp, cstyle);
bounds.Y += (cp.TextSize.Height + Dpi.Height4);
bounds.Height -= (cp.TextSize.Height + Dpi.Height4);
}
}
}
}
}
#endregion
#endregion
#region RenderCrosshairLabelEach
private void RenderCrosshairLabelEach(Graphics g,
Rectangle bounds, Point pt, CrosshairVisualStyle cstyle)
{
List cps = _CrosshairSeriesPoints;
foreach (CrosshairPoint cp in cps)
RenderCrosshairLabel(g, bounds, cstyle, cp);
}
#endregion
#region RenderCrosshairLabel
private void RenderCrosshairLabel(Graphics g,
Rectangle bounds, CrosshairVisualStyle cstyle, CrosshairPoint cp)
{
string arg = GetCrosshairArgument(cp);
MeasureCrosshairLabel(g, bounds, cp, cstyle, arg, true);
if (cp.TextSize.IsEmpty == false)
{
Size markerSize = Size.Empty;
if (ChartCrosshair.ShowCrosshairLabelMarkers == true)
{
Image marker = cp.ChartSeries.PointMarkerImage;
if (marker != null)
markerSize = marker.Size;
}
Size totalSize = new Size((markerSize.Width + cp.TextSize.Width),
Math.Max(markerSize.Height, cp.TextSize.Height) + Dpi.Height4);
totalSize.Width += Dpi.Width(cstyle.Padding.Horizontal + 4);
totalSize.Height += Dpi.Height(cstyle.Padding.Vertical - 4);
Point pt = cp.Point;
if (ChartCrosshair.PointIntersectMode == PointIntersectMode.Edge)
{
if (cp.ChartSeries.SeriesType == SeriesType.VerticalDot)
pt.Y -= (cp.SeriesPoint.PointSize.Height / 2);
else if (cp.ChartSeries.SeriesType == SeriesType.HorizontalDot)
pt.X += (cp.SeriesPoint.PointSize.Width / 2);
}
Rectangle cbounds = GetCrosshairPointBounds(bounds, cp, pt, totalSize);
DrawCrosshairCallout(g, cbounds, pt, cstyle);
cbounds = GetAdjustedBounds(cbounds, cstyle.Padding);
RenderCrosshairLabelItem(g, cbounds, cp, cstyle);
}
}
#region GetCrosshairPointBounds
private Rectangle GetCrosshairPointBounds(
Rectangle bounds, CrosshairPoint cp, Point pt, Size size)
{
Rectangle r;
int n = size.Width / 5;
int left = pt.X - bounds.X + n;
int right = bounds.Right - pt.X + n;
if ((right >= size.Width) || (right > left))
{
r = new Rectangle(pt.X - n, pt.Y - size.Height,
size.Width, size.Height);
}
else
{
r = new Rectangle(pt.X - (size.Width - n),
pt.Y - size.Height, size.Width, size.Height);
}
r.Y -= Dpi.Height20;
if (cp.ChartSeries.SeriesType == SeriesType.VerticalBar ||
cp.ChartSeries.SeriesType == SeriesType.VerticalHiLoBar)
{
if (cp.IsDescending == true)
{
if (pt.Y + 20 + r.Height < Bounds.Bottom)
r.Y = pt.Y + Dpi.Height20;
}
}
else
{
if (r.Y < Bounds.Y + 2)
r.Y = pt.Y + Dpi.Height20;
}
if (cp.ChartSeries.SeriesType == SeriesType.HorizontalBar ||
cp.ChartSeries.SeriesType == SeriesType.HorizontalHiLoBar)
{
if (cp.IsDescending == true)
r.X = pt.X - (size.Width - n);
}
if (r.Right > Bounds.Right - Dpi.Width2)
r.X = Bounds.Right - r.Width - Dpi.Width2;
if (r.Left < Bounds.X + Dpi.Width2)
r.X = Bounds.X + Dpi.Width2;
return (r);
}
#endregion
#endregion
#endregion
#region GetCrosshairHeader
private string GetCrosshairHeader(CrosshairPoint cp, List cps)
{
string text = GetCrosshairArgument(cp);
ChartControl.DoGetCrosshairLabelHeaderEvent(this, cp, cps, ref text);
return (text);
}
#endregion
#region GetCrosshairArgument
private string GetCrosshairArgument(CrosshairPoint cp)
{
AxisOrientation ao = ChartCrosshair.AxisOrientation;
if (cp.ChartSeries.IsRotated == true)
{
ao = (ChartCrosshair.AxisOrientation == AxisOrientation.X)
? AxisOrientation.Y : AxisOrientation.X;
}
if (ao == AxisOrientation.X)
return (GetValueXText(cp.ChartSeries, cp.ValueX));
return (GetValueYText(cp.ChartSeries, cp.ValueY));
}
#endregion
#region GetValueXText
private string GetValueXText(ChartSeries series, object value)
{
ChartAxis axis = (series.IsRotated)
? series.AxisY ?? AxisY : series.AxisX ?? AxisX;
return (axis.GetCrosshairLabel(
value, axis.EffectiveCrosshairLabelStyle));
}
#endregion
#region GetValueYText
private string GetValueYText(ChartSeries series, object value)
{
ChartAxis axis = (series.IsRotated)
? series.AxisX ?? AxisX : series.AxisY ?? AxisY;
return (axis.GetCrosshairLabel(
value, axis.EffectiveCrosshairLabelStyle));
}
#endregion
#region MeasureCrosshairLabel
private void MeasureCrosshairLabel(Graphics g,
Rectangle bounds, CrosshairPoint cp, CrosshairVisualStyle cstyle, string arg, bool multiLine)
{
cp.Text = GetCrosshairItemText(cp, arg, multiLine);
if (string.IsNullOrEmpty(cp.Text) == false)
{
SizeF sizef = g.MeasureString(cp.Text, cstyle.Font, bounds.Width);
cp.TextSize = new Size((int)sizef.Width + 1, (int)sizef.Height + 1);
}
else
{
cp.TextSize = Size.Empty;
}
}
#region GetCrosshairItemText
private string GetCrosshairItemText(CrosshairPoint cp, string arg, bool multiLine)
{
string text = cp.ChartSeries.LegendText ?? cp.ChartSeries.Name ?? "";
if (String.IsNullOrEmpty(text) == false)
text += " ";
if (arg != null)
{
if (multiLine == true && text.Length > 0)
text += "\n";
text += (arg + " : ");
}
text += GetItemText(cp);
ChartControl.DoGetCrosshairLabelItemEvent(this, cp, ref text);
return (text);
}
#region GetItemText
private string GetItemText(CrosshairPoint cp)
{
AxisOrientation ao = ChartCrosshair.AxisOrientation;
if (cp.ChartSeries.IsRotated == true)
{
ao = (ChartCrosshair.AxisOrientation == AxisOrientation.X)
? AxisOrientation.Y : AxisOrientation.X;
}
string text = (ao == AxisOrientation.X)
? GetValueYText(cp.ChartSeries, cp.ValueY)
: GetValueXText(cp.ChartSeries, cp.ValueX);
switch (cp.ChartSeries.SeriesType)
{
case SeriesType.HorizontalBar:
case SeriesType.VerticalBar:
return (GetBarText(cp, text));
case SeriesType.HorizontalHiLoBar:
case SeriesType.VerticalHiLoBar:
return (GetHiLoBarText(cp, text));
default:
return (text);
}
}
#endregion
#region GetBarText
private string GetBarText(CrosshairPoint cp, string s1)
{
if (cp.ChartSeries.IsRotated == (ChartCrosshair.AxisOrientation == AxisOrientation.Y))
{
if (cp.SeriesPoint.ValueY.Length > 1)
{
object v1 = cp.ValueY;
ChartAxis axis = (cp.ChartSeries.IsRotated)
? cp.ChartSeries.AxisX ?? AxisX : cp.ChartSeries.AxisY ?? AxisY;
CrosshairValueVisualStyle lstyle = axis.EffectiveCrosshairLabelStyle;
object v2 = cp.SeriesPoint.ValueY[1];
if (v2 != null)
{
string s2 = axis.GetCrosshairLabel(v2, lstyle);
int y1 = GetDataPointX(axis, v1);
int y2 = GetDataPointX(axis, v2);
if (y1 < y2)
return (s1 + " — " + s2);
return (s2 + " — " + s1);
}
}
}
return (s1);
}
#endregion
#region GetHiLoVBarText
private string GetHiLoBarText(CrosshairPoint cp, string s1)
{
if (cp.ChartSeries.IsRotated == (ChartCrosshair.AxisOrientation == AxisOrientation.Y))
{
if (cp.SeriesPoint.ValueY.Length > 1)
{
ChartAxis axis = (cp.ChartSeries.IsRotated)
? cp.ChartSeries.AxisX ?? AxisX : cp.ChartSeries.AxisY ?? AxisY;
CrosshairValueVisualStyle lstyle = axis.EffectiveCrosshairLabelStyle;
s1 = axis.GetCrosshairLabel(cp.ValueY, lstyle);
}
}
s1 = s1 + " (" + "HLCO"[cp.ValueIndex] + ")";
return (s1);
}
#endregion
#endregion
#endregion
#region RenderCrosshairLabelItem
private void RenderCrosshairLabelItem(Graphics g,
Rectangle bounds, CrosshairPoint cp, CrosshairVisualStyle cstyle)
{
if (ChartControl.DoRenderCrosshairLabelItemEvent(g, this, cp, bounds, cstyle) == false)
{
Rectangle r = RenderCrosshairLabelMarker(g, bounds, cp);
Color color = cstyle.TextColor;
if (color.IsEmpty == true)
{
color = cp.ChartSeries.GetLegendItemColor();
color = Color.FromArgb(255, color);
}
using (Brush lbr = new SolidBrush(color))
g.DrawString(cp.Text, cstyle.Font, lbr, r);
}
}
#region RenderCrosshairLabelMarker
private Rectangle RenderCrosshairLabelMarker(
Graphics g, Rectangle r, CrosshairPoint cp)
{
if (ChartCrosshair.ShowCrosshairLabelMarkers == true)
{
Image image = cp.ChartSeries.PointMarkerImage;
if (image != null)
{
Rectangle t = r;
Size isize = image.Size;
if (cp.TextSize.Height > isize.Height)
t.Y += (cp.TextSize.Height - isize.Height) / 2;
g.DrawImageUnscaled(image, t);
r.X += (isize.Width + Dpi.Width4);
r.Width -= (isize.Width + Dpi.Width4);
}
}
return (r);
}
#endregion
#endregion
#region DrawRoundRectangle
private void DrawRoundRectangle(Graphics g,
Rectangle t, CrosshairVisualStyle cstyle)
{
SmoothingMode sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
using (GraphicsPath path = new GraphicsPath())
{
int dia = Dpi.Width14;
Rectangle r = t;
r.Width = dia;
r.Height = dia;
path.AddArc(r, 180, 90);
r.X += (t.Width - dia);
path.AddArc(r, 270, 90);
r.Y += (t.Height - dia);
path.AddArc(r, 0, 90);
r.X = t.X;
path.AddArc(r, 90, 90);
path.CloseFigure();
using (Brush br = cstyle.Background.GetBrush(r))
g.FillPath(br, path);
using (Pen pen = new Pen(cstyle.BorderColor, cstyle.BorderThickness))
{
pen.DashStyle = (DashStyle)cstyle.BorderPattern;
g.DrawPath(pen, path);
}
}
g.SmoothingMode = sm;
}
#endregion
#region DrawCrosshairCallout
private void DrawCrosshairCallout(Graphics g,
Rectangle t, Point pt, CrosshairVisualStyle cstyle)
{
SmoothingMode sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
using (GraphicsPath path = new GraphicsPath())
{
AddCalloutToPath(path, t, pt);
Rectangle rp = Rectangle.Round(path.GetBounds());
if (pt.Y > t.Y)
rp.Y -= Dpi.Height10;
rp.Height += Dpi.Height10;
using (Brush br = cstyle.Background.GetBrush(rp))
g.FillPath(br, path);
using (Pen pen = new Pen(cstyle.BorderColor, cstyle.BorderThickness))
{
pen.DashStyle = (DashStyle)cstyle.BorderPattern;
g.DrawPath(pen, path);
}
}
g.SmoothingMode = sm;
}
#region AddCalloutToPath
private void AddCalloutToPath(GraphicsPath path, Rectangle t, Point pt)
{
int dia = Dpi.Width10;
Rectangle r = t;
int n = Dpi.Width20;
r.Width = dia;
r.Height = dia;
if (pt.Y > t.Y)
{
if (pt.X < (t.X + t.Width / 2))
{
path.AddLine(new Point(pt.X + n, pt.Y - Dpi.Width20), pt);
path.AddLine(pt, new Point(pt.X + Dpi.Width5, pt.Y - Dpi.Width20));
}
else
{
path.AddLine(new Point(pt.X - Dpi.Width5, pt.Y - Dpi.Width20), pt);
path.AddLine(pt, new Point(pt.X - n, pt.Y - Dpi.Width20));
}
r.Y += (t.Height - dia);
path.AddArc(r, 90, 90);
r.Y = t.Y;
path.AddArc(r, 180, 90);
r.X += (t.Width - dia);
path.AddArc(r, 270, 90);
r.Y += (t.Height - dia);
path.AddArc(r, 0, 90);
}
else
{
if (pt.X < (t.X + t.Width / 2))
{
path.AddLine(new Point(pt.X + Dpi.Width5, pt.Y + Dpi.Width20), pt);
path.AddLine(pt, new Point(pt.X + n, pt.Y + Dpi.Width20));
}
else
{
path.AddLine(new Point(pt.X - n, pt.Y + Dpi.Width20), pt);
path.AddLine(pt, new Point(pt.X - Dpi.Width5, pt.Y + Dpi.Width20));
}
r.X += (t.Width - dia);
path.AddArc(r, 270, 90);
r.Y += (t.Height - dia);
path.AddArc(r, 0, 90);
r.X = t.X;
path.AddArc(r, 90, 90);
r.Y = t.Y;
path.AddArc(r, 180, 90);
}
path.CloseFigure();
}
#endregion
#endregion
#endregion
#endregion
#region Mouse Support
#region OnMouseMove
protected override bool OnMouseMove(MouseEventArgs e)
{
OnMouseMoveEx(e);
if (Legend.Visible == false ||
Legend.ContentBounds.Contains(e.Location) == false)
{
_CanShowCrosshairLabel = true;
}
return (base.OnMouseMove(e));
}
#endregion
#region OnMouseMoveEx
protected override void OnMouseMoveEx(MouseEventArgs e)
{
ChartCrosshair crosshair = ChartCrosshair;
bool displayCrosshair = DisplayCrosshair;
_CanShowCrosshairLabel = false;
if (crosshair.Visible == false ||
(crosshair.ShowCrosshairLabels == false &&
crosshair.ShowValueXLine == false && crosshair.ShowValueYLine == false &&
crosshair.ShowValueXLabels == false && crosshair.ShowValueYLabels == false))
{
DisplayCrosshair = false;
}
else
{
Rectangle bounds = GetScrollBounds(ContentBounds);
if (VScrollBar.Enabled == true)
bounds.Width -= (VScrollBar.Width + 1);
if (HScrollBar.Enabled == true)
bounds.Height -= (HScrollBar.Height + 1);
DisplayCrosshair = bounds.Contains(e.Location);
}
if (DisplayCrosshair == true || displayCrosshair != DisplayCrosshair)
{
if (DisplayCrosshair == false)
_CrosshairSeriesPoints = null;
InvalidateRender();
}
}
#endregion
#region OnMouseLeave
protected override bool OnMouseLeave(EventArgs e)
{
if (DisplayCrosshair == true)
{
DisplayCrosshair = false;
_CrosshairSeriesPoints = null;
InvalidateRender();
}
return (base.OnMouseLeave(e));
}
#endregion
#endregion
#region GetLocalAdjustedPoint
///
/// Gets the local, scroll adjusted point.
///
///
///
public Point GetLocalAdjustedPoint(Point pt)
{
pt.X -= ScrollOffset.X;
pt.X += (HScrollBar.Inverted == true ? HScrollOffset : -HScrollOffset);
pt.Y -= ScrollOffset.Y;
pt.Y += (VScrollBar.Inverted == true ? VScrollOffset : -VScrollOffset);
return (pt);
}
#endregion
#region GetGlobalAdjustedPoint
internal Point GetGlobalAdjustedPoint(Point pt)
{
pt.X -= (HScrollBar.Inverted == true ? HScrollOffset : -HScrollOffset);
pt.Y -= (VScrollBar.Inverted == true ? VScrollOffset : -VScrollOffset);
return (pt);
}
#endregion
#region GetScBorderThickness
internal int GetScBorderThickness(XyAlignment side)
{
ChartXyVisualStyle xyStyle = EffectiveChartStyle;
int n = 0;
switch (side)
{
case XyAlignment.Top:
n = (xyStyle.BorderThickness.Top);
break;
case XyAlignment.Left:
n = (xyStyle.BorderThickness.Left);
break;
case XyAlignment.Bottom:
n = (xyStyle.BorderThickness.Bottom +
((HScrollBar.Visible == true) ? HScrollBar.Height + 1 : 0));
break;
case XyAlignment.Right:
n = (xyStyle.BorderThickness.Right +
((VScrollBar.Visible == true) ? VScrollBar.Width + 1 : 0));
break;
}
return (Dpi.Width(n));
}
#endregion
#region GetPointMarker
internal Image GetPointMarker(Graphics g, PointMarkerVisualStyle style)
{
Image marker = null;
marker = style.GetPointMarkerImage();
return (marker ?? GetPointMarkerEx(g, style));
}
internal Image GetPointMarkerEx(Graphics g, PointMarkerVisualStyle style)
{
return (GetPointMarker(g, style.Type,
style.PointCount, Dpi.Size(style.Size), style.Rotation,
style.Background, style.BorderColor, style.BorderWidth));
}
internal Image GetPointMarker(Graphics g, PointMarkerType markerType, int markerPoints,
Size size, int markerRotation, Background background, Color borderColor, int borderWidth)
{
if (_PointMarker == null)
_PointMarker = new PointMarker();
if (markerType == PointMarkerType.None || markerType == PointMarkerType.NotSet)
markerType = PointMarkerType.Rectangle;
return (_PointMarker.GetMarkerBitmap(g, markerType,
markerPoints, size, markerRotation, background, borderColor, borderWidth));
}
#endregion
#region IsCrosshairSeriesPoint
///
/// Gets whether the given Point is a Crosshair displayed point.
///
///
///
///
public bool IsCrosshairSeriesPoint(ChartSeries series, Point pt)
{
if (_CrosshairSeriesPoints != null)
{
Rectangle r = new Rectangle(pt, Size.Empty);
r.Inflate(2, 2);
foreach (CrosshairPoint chp in _CrosshairSeriesPoints)
{
if (r.Contains(chp.Point) && (series == null || chp.ChartSeries == series))
{
if (chp == _NearestCrosshairPoint)
return (true);
if (ChartCrosshair.CrosshairLabelMode != CrosshairLabelMode.NearestSeries)
return (true);
}
}
}
return (false);
}
#endregion
#region UpdateRangeValues
private void UpdateRangeValues()
{
if (SeriesRangeChanged == true)
{
SeriesRangeChanged = false;
InvalidatePointLabelsEx();
_MinValueX = null;
_MaxValueX = null;
_MinValueY = null;
_MaxValueY = null;
foreach (ChartSeries series in ChartSeries)
{
if (_MinValueX == null)
{
_MinValueX = series.MinValueX;
_MaxValueX = series.MaxValueX;
_MinValueY = series.MinValueY;
_MaxValueY = series.MaxValueY;
}
else
{
if (series.MinValueX != null)
{
if (DataCompare(series.MinValueX, _MinValueX) < 0)
_MinValueX = series.MinValueX;
else if (DataCompare(series.MaxValueX, _MaxValueX) > 0)
_MaxValueX = series.MaxValueX;
if (DataCompare(series.MinValueY, _MinValueY) < 0)
_MinValueY = series.MinValueY;
else if (DataCompare(series.MaxValueY, _MaxValueY) > 0)
_MaxValueY = series.MaxValueY;
}
}
ChartAxis axis = series.AxisX ?? AxisX;
if (axis != null)
axis.SeriesRangeChanged = true;
axis = series.AxisY ?? AxisY;
if (axis != null)
axis.SeriesRangeChanged = true;
}
}
}
#endregion
#region GetPointFromValue
///
/// Gets the chart Point, given the provided SeriesPoint.
///
///
///
///
///
public Point GetPointFromValue(ChartSeries series, SeriesPoint sp)
{
Point pt = GetDataPointNa(series, sp, 0);
return (GetLocalAdjustedPoint(pt));
}
///
/// Gets the chart Point, given the X and Y data point values.
///
///
///
///
///
public Point GetPointFromValue(ChartSeries series, object pointValueX, object pointValueY)
{
Point pt = Point.Empty;
ChartAxis axisX = series.AxisX ?? AxisX;
ChartAxis axisY = series.AxisY ?? AxisY;
pt.X = GetDataPointX(axisX, pointValueX) + series.PointOffset.X;
pt.Y = GetDataPointY(axisY, pointValueY);
return (pt);
}
#endregion
#region GetDataPoint
internal Point GetDataPoint(ChartSeries series, SeriesPoint sp, int dy)
{
Point pt = GetDataPointNa(series, sp, dy);
return (GetLocalAdjustedPoint(pt));
}
internal Point GetDataPointNa(ChartSeries series, SeriesPoint sp, int dy)
{
if (sp.SeriesValidationCount != SeriesPointCount)
{
sp.InvalidatePoints();
sp.SeriesValidationCount = SeriesPointCount;
}
int n = (dy < 0) ? 0 : dy;
if (sp.Point.Length > n)
{
if (sp.Point[n].IsEmpty == true)
{
sp.Point[n] = GetDataPointEx(series, sp, dy);
if (sp.Point[n].IsEmpty == true)
return (Point.Empty);
}
return (sp.Point[n]);
}
return (Point.Empty);
}
internal Point GetDataPointEx(ChartSeries series, SeriesPoint sp, int dy)
{
object pointValueX = sp.ValueX;
object pointValueY = 0;
if (dy >= 0)
{
if (sp.ValueY != null && sp.ValueY.Length > dy)
pointValueY = sp.ValueY[dy];
}
if (series.IsRotated == true)
return (GetPointFromValue(series, pointValueY, pointValueX));
return (GetPointFromValue(series, pointValueX, pointValueY));
}
#region GetDataPointX
internal int GetDataPointX(ChartAxis axis, object pointValueX)
{
TickmarkLayout layoutX = axis.TickmarkLayout;
if (layoutX.Ticks != null)
{
Rectangle tmBoundsX = axis.MajorTickmarks.TickmarkBounds;
int minOffset;
int majOffset = GetDataOffsetX(axis, layoutX, pointValueX, out minOffset);
return ((tmBoundsX.X + majOffset - layoutX.MarginOffset) + minOffset);
}
else
{
Rectangle r = ScrollBounds;
return (int)(r.Left);
}
}
#region GetDataOffsetX
private int GetDataOffsetX(ChartAxis axis,
TickmarkLayout layout, object pointValue, out int minOffset)
{
double ptValue;
switch (axis.ScaleType)
{
case ScaleType.Qualitative:
ptValue = axis.QualitativeValues.IndexOf(pointValue) - Convert.ToInt32(layout.BaseValue);
break;
case ScaleType.DateTime:
ptValue = GetDateTimePointValue(axis, layout, (DateTime)pointValue);
break;
default:
try
{
ptValue = Convert.ToDouble(pointValue) - Convert.ToDouble(layout.BaseValue);
}
catch
{
minOffset = 0;
return (0);
}
break;
}
int n = (int)(ptValue / layout.MajorSpacing);
int p1 = (int)(n * layout.MajorInterval);
int p2 = (int)((n + 1) * layout.MajorInterval);
double minorValue = (ptValue - (n * layout.MajorSpacing));
minOffset = (int)(((p2 - p1) * minorValue) / layout.MajorSpacing);
return (p1);
}
#endregion
#endregion
#region GetDataPointY
internal int GetDataPointY(ChartAxis axis, object pointValueY)
{
TickmarkLayout layoutY = axis.TickmarkLayout;
if (layoutY.Ticks != null)
{
Rectangle tmBoundsY = axis.MajorTickmarks.TickmarkBounds;
int minOffset;
int majOffset = GetDataOffsetY(axis, layoutY, pointValueY, out minOffset);
return (((tmBoundsY.Bottom - 1) - majOffset + layoutY.MarginOffset) - minOffset);
}
else
{
Rectangle r = ScrollBounds;
if (HScrollBar.Enabled == true)
r.Height -= HScrollBar.Height;
return (int)(r.Bottom - 1);
}
}
#region GetDataOffsetY
private int GetDataOffsetY(ChartAxis axis,
TickmarkLayout layout, object pointValue, out int minOffset)
{
double ptValue;
switch (axis.ScaleType)
{
case ScaleType.Qualitative:
ptValue = axis.QualitativeValues.IndexOf(pointValue) - Convert.ToInt32(layout.BaseValue);
break;
case ScaleType.DateTime:
ptValue = GetDateTimePointValue(axis, layout, (DateTime)pointValue);
break;
default:
try
{
ptValue = Convert.ToDouble(pointValue) - Convert.ToDouble(layout.BaseValue);
}
catch
{
minOffset = 0;
return (0);
}
break;
}
int n = (int)(ptValue / layout.MajorSpacing);
int p1 = (int)Math.Ceiling(n * layout.MajorInterval);
int p2 = (int)Math.Ceiling((n + 1) * layout.MajorInterval);
double minorValue = (ptValue - (n * layout.MajorSpacing));
minOffset = (int)Math.Ceiling(((p2 - p1) * minorValue) / layout.MajorSpacing);
return (p1);
}
#endregion
#endregion
#region GetDateTimePointValue
internal double GetDateTimePointValue(
ChartAxis axis, TickmarkLayout layout, DateTime dt)
{
return (GetDateTimePointValue(axis, layout, dt, (DateTime)layout.BaseValue));
}
internal double GetDateTimePointValue(
ChartAxis axis, TickmarkLayout layout, DateTime dt, DateTime baseValue)
{
TimeSpan ts = dt - baseValue;
DateTimeUnits adtu = axis.ActualDateTimeUnits;
switch (adtu)
{
case DateTimeUnits.Ticks:
return (ts.Ticks);
case DateTimeUnits.Milliseconds:
return (ts.TotalMilliseconds);
case DateTimeUnits.Seconds:
return (ts.TotalSeconds);
case DateTimeUnits.Minutes:
return (ts.TotalMinutes);
case DateTimeUnits.Hours:
return (ts.TotalHours);
case DateTimeUnits.Days:
return (ts.TotalDays);
case DateTimeUnits.Months:
return (axis.CalcDateTimeMonths(baseValue, dt));
default:
return (axis.CalcDateTimeYears(baseValue, dt));
}
}
#endregion
#endregion
#region GetDataPointValueX
internal object GetDataPointValueX(ChartSeries series, SeriesPoint sp)
{
ChartAxis axisX = series.AxisX ?? AxisX;
switch (axisX.ScaleType)
{
case ScaleType.Qualitative:
return (axisX.QualitativeValues.IndexOf(sp.ValueX));
default:
return (sp.ValueX);
}
}
#endregion
#region GetDataPointValueY
internal double GetDataPointValueY(ChartSeries series, SeriesPoint sp, int dy)
{
if (dy >= 0)
{
if (sp.IsQuantitativeYValue == true)
{
if (sp.ValueY != null && sp.ValueY.Length > dy)
return (Convert.ToDouble(sp.ValueY[dy]));
return (1);
}
ChartAxis axisY = series.AxisY ?? AxisY;
return (axisY.QualitativeValues.IndexOf(sp.ValueY[dy]));
}
return (0);
}
#endregion
#region GetQualitativeColumnWidth
internal int GetQualitativeColumnWidth(ChartAxis axis, int groupId)
{
ChartXyVisualStyle cstyle = EffectiveChartStyle;
List slist = GetQualitativeSeriesList(axis, groupId);
int width = 0;
int swidth = 0;
int count = 0;
foreach (ChartSeries series in slist)
{
Size size;
if (series.PointMarkerImage != null)
size = series.PointMarkerImage.Size;
else
size = series.EffectiveChartSeriesStyle.MarkerVisualStyle.Size;
if (series.StackQualitativePoints == false)
{
count++;
width += size.Width;
}
else
{
swidth = Math.Max(swidth, size.Width);
}
}
width += swidth;
if (count > 1)
width += ((count - 1) * cstyle.IntraSeriesGap);
int offset = -width / 2;
if (swidth > 0)
{
Point pt = new Point(offset + swidth / 2, 0);
foreach (ChartSeries series in slist)
{
if (series.StackQualitativePoints == true)
series.PointOffset = pt;
}
offset += (swidth + cstyle.IntraSeriesGap);
}
foreach (ChartSeries series in slist)
{
if (series.StackQualitativePoints == false)
{
Size size;
if (series.PointMarkerImage != null)
size = series.PointMarkerImage.Size;
else
size = series.EffectiveChartSeriesStyle.MarkerVisualStyle.Size;
series.PointOffset = new Point(offset + size.Width / 2 + 1, 0);
offset += (size.Width + cstyle.IntraSeriesGap);
}
}
width += (cstyle.InterSeriesGap * 2);
return (width);
}
#endregion
#region AdjustQualitativeOffsets
internal void AdjustQualitativeOffsets(ChartAxis axis, int groupId, int colWidth, int interval)
{
ChartXyVisualStyle cstyle = EffectiveChartStyle;
if (cstyle.AutoExpandIntraSeriesGap == Tbool.True)
{
List slist = GetQualitativeSeriesList(axis, groupId);
interval -= cstyle.InterSeriesGap;
int count = 0;
foreach (ChartSeries series in slist)
{
if (series.StackQualitativePoints == false)
count++;
}
if (count > 1)
{
if (interval > colWidth)
{
int offset = (interval - colWidth);
int dv = offset / count;
offset = offset / 2 - dv / 2;
foreach (ChartSeries series in slist)
{
Point pt = series.PointOffset;
if (axis.AxisOrientation == AxisOrientation.X)
pt.X -= offset;
else
pt.Y -= offset;
series.PointOffset = pt;
if (series.StackQualitativePoints == false)
offset -= dv;
}
}
}
}
}
#endregion
#region GetQualitativeSeriesList
private List GetQualitativeSeriesList(ChartAxis axis, int groupId)
{
List slist = new List();
if (axis.ScaleType == ScaleType.Qualitative)
{
foreach (ChartSeries series in ChartSeries)
{
if (series.Visible == true && series.GroupId == groupId)
{
if (Legend.Visible == false ||
(series.ShowCheckBoxInLegend == false || series.CheckedInLegend == true))
{
if (axis.AxisOrientation == AxisOrientation.X)
{
if (series.AxisX == axis || (series.AxisX == null && axis.IsPrimaryAxis))
slist.Add(series);
}
else
{
if (series.AxisY == axis || (series.AxisY == null && axis.IsPrimaryAxis))
slist.Add(series);
}
}
}
}
}
return (slist);
}
#endregion
#region GetChartBubbleData
internal int GetChartBubbleData(out double min, out double max)
{
int count = 0;
min = double.MaxValue;
max = double.MinValue;
foreach (ChartSeries series in ChartSeries)
{
if (series.Visible == true)
{
BubblePlotData bpd = series.PlotData as BubblePlotData;
if (bpd != null)
{
int n = series.SeriesPoints.Count;
count += n;
double size = bpd.MinSize;
if (size < min)
min = size;
size = bpd.MaxSize;
if (size > max)
max = size;
}
}
}
return (count);
}
#endregion
#region GetMaxDotPlotMarkerSize
internal Size GetMaxDotPlotMarkerSize()
{
Size size = Size.Empty;
foreach (ChartSeries series in ChartSeries)
{
if (series.Visible == true)
{
Image marker = series.PointMarkerImage;
if (marker != null)
{
if (marker.Size.Width > size.Width)
size.Width = marker.Size.Width;
if (marker.Size.Height > size.Height)
size.Height = marker.Size.Height;
}
}
}
return (size);
}
#endregion
#region GetDotPlotTypes
internal DotPlotType GetDotPlotTypes()
{
DotPlotType types = DotPlotType.None;
foreach (ChartSeries series in ChartSeries)
{
if (series.Visible == true)
{
if (series.SeriesType == SeriesType.VerticalDot)
types |= DotPlotType.Vertical;
else if (series.SeriesType == SeriesType.HorizontalDot)
types |= DotPlotType.Horizontal;
}
}
return (types);
}
#endregion
#region GetBaseSeries
internal override ChartBaseSeriesCollection GetBaseSeries()
{
ChartBaseSeriesCollection baseSeries = new ChartBaseSeriesCollection();
foreach (BaseSeries series in ChartSeries)
baseSeries.Add(series);
return (baseSeries);
}
#endregion
#region GetSeriesByName
///
/// Gets the chart series with the given Name.
///
///
/// ChartSeries or null.
public ChartSeries GetSeriesByName(string name)
{
if (String.IsNullOrEmpty(name) == true)
return (null);
foreach (ChartSeries series in ChartSeries)
{
if (name.Equals(series.Name) == true)
return (series);
}
return (null);
}
#endregion
#region GetAutoGenSeriesType
internal override SeriesType GetAutoGenSeriesType()
{
return (AutoGenSeriesType);
}
#endregion
#region GetAutoGenSeriesNameCount
internal override int GetAutoGenSeriesNameCount()
{
return (AutoGenSeriesType == SeriesType.Bubble ? 2 : 1);
}
#endregion
#region GetNewSeries
internal override BaseSeries GetNewSeries()
{
return (new ChartSeries(AutoGenSeriesType));
}
#endregion
#region AddChartSeries
internal override void AddChartSeries(BaseSeries series)
{
ChartSeries.Add((ChartSeries)series);
}
#endregion
#region Style handling
#region ApplyStyles
public override void ApplyStyles(BaseVisualStyle style)
{
base.ApplyStyles(style);
ChartXyVisualStyle xyStyle = style as ChartXyVisualStyle;
if (xyStyle != null)
{
ApplyParentStyles(xyStyle, Parent as ChartContainer);
xyStyle.ApplyStyle(ChartVisualStyle);
xyStyle.ApplyDefaults();
}
else if (style is ChartSeriesVisualStyle)
{
ChartSeriesVisualStyle sstyle = (ChartSeriesVisualStyle)style;
ApplyParentStyles(sstyle, Parent as ChartContainer);
sstyle.ApplyStyle(_ChartSeriesVisualStyle);
sstyle.ApplyDefaults();
}
else if (style is DataLabelVisualStyle)
{
DataLabelVisualStyle dstyle = style as DataLabelVisualStyle;
if (dstyle != null)
{
ApplyParentStyles(dstyle, Parent as ChartContainer);
dstyle.ApplyStyle(_DataLabelVisualStyle);
dstyle.ApplyDefaults();
}
}
}
#region ApplyParentStyles
private void ApplyParentStyles(ChartXyVisualStyle pstyle, ChartContainer item)
{
if (item != null)
{
ApplyParentStyles(pstyle, item.Parent as ChartContainer);
if (item is ChartPanel)
pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.ChartXyVisualStyle);
}
else
{
pstyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartXyVisualStyle);
pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartXyVisualStyle);
}
}
#endregion
#region ApplyParentStyles (ChartSeriesVisualStyle)
private void ApplyParentStyles(ChartSeriesVisualStyle pstyle, ChartContainer item)
{
if (item != null)
{
ApplyParentStyles(pstyle, item.Parent as ChartContainer);
if (item is ChartPanel)
pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.ChartSeriesVisualStyle);
}
else
{
pstyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartSeriesVisualStyle);
pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartSeriesVisualStyle);
}
}
#endregion
#region ApplyParentStyles (DataLabelVisualStyle)
private void ApplyParentStyles(DataLabelVisualStyle pstyle, ChartContainer item)
{
if (item != null)
{
ApplyParentStyles(pstyle, item.Parent as ChartContainer);
if (item is ChartPanel)
pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.DataLabelVisualStyle);
}
else
{
pstyle.ApplyStyle(ChartControl.BaseVisualStyles.DataLabelVisualStyle);
pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.DataLabelVisualStyle);
}
}
#endregion
#endregion
#region ClearEffectiveStyles
protected override void ClearEffectiveStyles()
{
_EffectiveChartStyle.InvalidateStyle();
_EffectiveChartSeriesStyle.InvalidateStyle();
if (_EffectiveDataLabelStyle.InvalidateStyle() == true)
InvalidateLayout();
base.ClearEffectiveStyles();
}
#endregion
#endregion
#region InvalidateLayoutBounds
public override void InvalidateLayoutBounds(ScrollBarLite sbar)
{
base.InvalidateLayoutBounds(sbar);
if (sbar != null)
{
Rectangle contentBounds = GetScrollBounds(ContentBounds);
InvalidateRender(contentBounds);
if (sbar.Orientation == Orientation.Horizontal)
InvalidateAxes(AncillaryAxesX, AxisX);
else
InvalidateAxes(AncillaryAxesY, AxisY);
}
}
#region InvalidateAxes
private void InvalidateAxes(ChartAxesCollection axes, ChartAxis axis)
{
foreach (ChartAxis ca in axes)
{
if (ca.Visible == true)
{
Rectangle bounds = ca.GetScrollBounds(ca.AxisBounds);
ca.InvalidateRender(bounds);
}
}
if (axis.Visible == true)
{
Rectangle bounds = axis.GetScrollBounds(axis.AxisBounds);
axis.InvalidateRender(bounds);
}
}
#endregion
#endregion
#region InvalidateSeriesPoints
private void InvalidateSeriesPoints()
{
SeriesPointCount++;
foreach (ChartSeries series in ChartSeries)
series.InvalidatePoints();
InvalidatePointLabelsEx();
}
#endregion
#region InvalidatePointLabels
///
/// Invalidate the cached PointLabels
///
public void InvalidatePointLabels()
{
InvalidatePointLabelsEx();
InvalidateRender();
}
internal void InvalidatePointLabelsEx()
{
_PointLabels = null;
}
#endregion
#region GetLegendData
///
/// Gets the list of chart legend data.
///
///
public override List GetLegendData()
{
base.GetLegendData();
GetAxesLegendData(AncillaryAxesX, AxisX);
GetAxesLegendData(AncillaryAxesY, AxisY);
return (LegendData);
}
#endregion
#region GetAxesLegendData
private void GetAxesLegendData(ChartAxesCollection axes, ChartAxis axis)
{
for (int i = axes.Count - 1; i >= 0; i--)
{
ChartAxis ca = axes[i];
if (ca.Visible == true)
ca.GetLegendData(LegendData);
}
if (axis.Visible == true)
axis.GetLegendData(LegendData);
}
#endregion
#region GetHitArea
///
/// Gets the hit area for the chart.
///
///
/// ItemHitArea
public override ItemHitArea GetHitArea(Point pt)
{
if (AxisX.Bounds.Contains(pt))
return (ItemHitArea.InPrimaryAxisX);
if (AxisY.Bounds.Contains(pt))
return (ItemHitArea.InPrimaryAxisY);
foreach (ChartAxis axis in AncillaryAxesX)
{
if (axis.Bounds.Contains(pt))
return (ItemHitArea.InAncillaryAxisX);
}
foreach (ChartAxis axis in AncillaryAxesY)
{
if (axis.Bounds.Contains(pt))
return (ItemHitArea.InAncillaryAxisY);
}
return (base.GetHitArea(pt));
}
#endregion
#region Copy/CopyTo
public override ChartVisualElement Copy()
{
ChartXy copy = new ChartXy();
CopyTo(copy);
return (copy);
}
public override void CopyTo(ChartVisualElement copy)
{
ChartXy c = copy as ChartXy;
if (c != null)
{
base.CopyTo(c);
foreach (ChartAxisX axis in AncillaryAxesX)
c.AncillaryAxesX.Add((ChartAxisX)axis.Copy());
foreach (ChartAxisY axis in AncillaryAxesY)
c.AncillaryAxesY.Add((ChartAxisY)axis.Copy());
c.AutoGenSeriesType = AutoGenSeriesType;
AxisX.CopyTo(c.AxisX);
AxisY.CopyTo(c.AxisY);
c.BarFillRange = BarFillRange;
c.BarLabelPosition = BarLabelPosition;
c.BarOrigin = BarOrigin;
c.BarOverlayEnabled = BarOverlayEnabled;
c.BarShadingEnabled = BarShadingEnabled;
c.BarSpacing = BarSpacing;
c.BarSpacingRatio = BarSpacingRatio;
c.BarWidthRatio = BarWidthRatio;
c.BubbleIntensityMode = BubbleIntensityMode;
c.BubbleSizeMode = BubbleSizeMode;
c.ChartLineAreaDisplayMode = ChartLineAreaDisplayMode;
c.ChartLineDisplayMode = ChartLineDisplayMode;
foreach (ChartSeries series in ChartSeries)
c.ChartSeries.Add((ChartSeries)series.Copy());
c.ChartSeriesVisualStyle =
(_ChartSeriesVisualStyle != null) ? _ChartSeriesVisualStyle.Copy() : null;
c.ChartVisualStyle = (_ChartVisualStyle != null) ? ChartVisualStyle.Copy() : null;
c.ConvexHullDisplayMode = ConvexHullDisplayMode;
ChartCrosshair.CopyTo(c.ChartCrosshair);
c.DataLabelOverlapMode = DataLabelOverlapMode;
c.DataLabelVisualStyle =
(_DataLabelVisualStyle != null) ? _DataLabelVisualStyle.Copy() : null;
c.PointLabelDisplayMode = PointLabelDisplayMode;
c.SeriesDisplayOrder = SeriesDisplayOrder;
c.StepLines = StepLines;
c.StepLineMode = StepLineMode;
}
}
#endregion
#region GetSerialData
internal override SerialElementCollection GetSerialData(string serialName)
{
SerialElementCollection sec = new SerialElementCollection();
if (serialName != null)
{
if (serialName.Equals("") == true)
serialName = "ChartXy";
sec.AddStartElement(serialName);
}
if (_AncillaryAxesX != null && _AncillaryAxesX.Count > 0)
{
sec.AddStartElement("AncillaryAxesX count=\"" + _AncillaryAxesX.Count + "\"");
foreach (ChartAxisX axis in _AncillaryAxesX)
sec.AddElement(axis.GetSerialData("ChartAxisX"));
sec.AddEndElement("AncillaryAxesX");
}
if (_AncillaryAxesY != null && _AncillaryAxesY.Count > 0)
{
sec.AddStartElement("AncillaryAxesY count=\"" + _AncillaryAxesY.Count + "\"");
foreach (ChartAxisY axis in _AncillaryAxesY)
sec.AddElement(axis.GetSerialData("ChartAxisY"));
sec.AddEndElement("AncillaryAxesY");
}
sec.AddValue("AutoGenSeriesType", AutoGenSeriesType, SeriesType.Point);
if (AxisX != null)
sec.AddElement(AxisX.GetSerialData("AxisX"));
if (AxisY != null)
sec.AddElement(AxisY.GetSerialData("AxisY"));
sec.AddValue("BarFillRange", BarFillRange, BarFillRange.NotSet);
sec.AddValue("BarLabelPosition", BarLabelPosition, BarLabelPosition.NotSet);
sec.AddDataValue("BarOrigin", BarOrigin, null);
sec.AddValue("BarOverlayEnabled", BarOverlayEnabled, false);
sec.AddValue("BarShadingEnabled", BarShadingEnabled, Tbool.NotSet);
sec.AddValue("BarShowAsHistogram", BarShowAsHistogram, Tbool.NotSet);
sec.AddValue("BarSpacing", BarSpacing, 0);
sec.AddValue("BarSpacingRatio", BarSpacingRatio, 0.2d);
sec.AddValue("BarWidthRatio", BarWidthRatio, 0d);
sec.AddValue("BubbleIntensityMode", BubbleIntensityMode, BubbleIntensityMode.NotSet);
sec.AddValue("BubbleSizeMode", BubbleSizeMode, BubbleSizeMode.NotSet);
sec.AddValue("ChartLineAreaDisplayMode", ChartLineAreaDisplayMode, ChartLineAreaDisplayMode.NotSet);
sec.AddValue("ChartLineDisplayMode", ChartLineDisplayMode, ChartLineDisplayMode.NotSet);
if (ChartSeries.Count > 0)
{
sec.AddStartElement("ChartSeries count=\"" + ChartSeries.Count + "\"");
foreach (ChartSeries series in ChartSeries)
sec.AddElement(series.GetSerialData("ChartSeries"));
sec.AddEndElement("ChartSeries");
}
if (_ChartSeriesVisualStyle != null && _ChartSeriesVisualStyle.IsEmpty == false)
sec.AddElement(_ChartSeriesVisualStyle.GetSerialData("ChartSeriesVisualStyle"));
if (_ChartVisualStyle != null && _ChartVisualStyle.IsEmpty == false)
sec.AddElement(_ChartVisualStyle.GetSerialData("ChartVisualStyle"));
sec.AddValue("ConvexHullDisplayMode", ConvexHullDisplayMode, ConvexHullDisplayMode.NotSet);
sec.AddElement(ChartCrosshair.GetSerialData("ChartCrosshair"));
sec.AddValue("DataLabelOverlapMode", DataLabelOverlapMode, DataLabelOverlapMode.NotSet);
if (_DataLabelVisualStyle != null && _DataLabelVisualStyle.IsEmpty == false)
sec.AddElement(_DataLabelVisualStyle.GetSerialData("DataLabelVisualStyle"));
sec.AddValue("PointLabelDisplayMode", PointLabelDisplayMode, PointLabelDisplayMode.NotSet);
sec.AddValue("SeriesDisplayOrder", SeriesDisplayOrder, SeriesDisplayOrder.NotSet);
sec.AddValue("StepLines", StepLines, StepLines.NotSet);
sec.AddValue("StepLineMode", StepLineMode, StepLineMode.NotSet);
sec.AddElement(base.GetSerialData(null));
if (serialName != null)
sec.AddEndElement(serialName);
return (sec);
}
#endregion
#region PutSerialData
#region ProcessValue
internal override void ProcessValue(SerialElement se)
{
switch (se.Name)
{
case "AutoGenSeriesType":
AutoGenSeriesType = (SeriesType)se.GetValueEnum(typeof(SeriesType));
break;
case "BarFillRange":
BarFillRange = (BarFillRange)se.GetValueEnum(typeof(BarFillRange));
break;
case "BarLabelPosition":
BarLabelPosition = (BarLabelPosition)se.GetValueEnum(typeof(BarLabelPosition));
break;
case "BarOrigin":
BarOrigin = se.DataValue;
break;
case "BarOverlayEnabled":
BarOverlayEnabled = bool.Parse(se.StringValue);
break;
case "BarShadingEnabled":
BarShadingEnabled = (Tbool)se.GetValueEnum(typeof(Tbool));
break;
case "BarShowAsHistogram":
BarShowAsHistogram = (Tbool)se.GetValueEnum(typeof(Tbool));
break;
case "BarSpacing":
BarSpacing = int.Parse(se.StringValue);
break;
case "BarSpacingRatio":
BarSpacingRatio = double.Parse(se.StringValue);
break;
case "BarWidthRatio":
BarWidthRatio = double.Parse(se.StringValue);
break;
case "BubbleIntensityMode":
BubbleIntensityMode = (BubbleIntensityMode)se.GetValueEnum(typeof(BubbleIntensityMode));
break;
case "BubbleSizeMode":
BubbleSizeMode = (BubbleSizeMode)se.GetValueEnum(typeof(BubbleSizeMode));
break;
case "ChartLineAreaDisplayMode":
ChartLineAreaDisplayMode = (ChartLineAreaDisplayMode)se.GetValueEnum(typeof(ChartLineAreaDisplayMode));
break;
case "ChartLineDisplayMode":
ChartLineDisplayMode = (ChartLineDisplayMode)se.GetValueEnum(typeof(ChartLineDisplayMode));
break;
case "ConvexHullDisplayMode":
ConvexHullDisplayMode = (ConvexHullDisplayMode)se.GetValueEnum(typeof(ConvexHullDisplayMode));
break;
case "DataLabelOverlapMode":
DataLabelOverlapMode = (DataLabelOverlapMode)se.GetValueEnum(typeof(DataLabelOverlapMode));
break;
case "PointLabelDisplayMode":
PointLabelDisplayMode = (PointLabelDisplayMode)se.GetValueEnum(typeof(PointLabelDisplayMode));
break;
case "SeriesDisplayOrder":
SeriesDisplayOrder = (SeriesDisplayOrder)se.GetValueEnum(typeof(SeriesDisplayOrder));
break;
case "StepLines":
StepLines = (StepLines)se.GetValueEnum(typeof(StepLines));
break;
case "StepLineMode":
StepLineMode = (StepLineMode)se.GetValueEnum(typeof(StepLineMode));
break;
default:
base.ProcessValue(se);
break;
}
}
#endregion
#region ProcessCollection
internal override void ProcessCollection(SerialElement se)
{
SerialElementCollection sec = se.Sec;
switch (se.Name)
{
case "AncillaryAxesX":
case "AncillaryAxesY":
sec.PutSerialData(this);
break;
case "AxisX":
sec.PutSerialData(AxisX);
break;
case "AxisY":
sec.PutSerialData(AxisY);
break;
case "ChartAxisX":
string nameX = sec.GetItemValue("Name");
ChartAxis axisX = AncillaryAxesX[nameX];
if (axisX != null)
AncillaryAxesX.Remove(axisX);
axisX = new ChartAxisX(nameX);
sec.PutSerialData(axisX);
AncillaryAxesX.Add(axisX);
break;
case "ChartAxisY":
string nameY = sec.GetItemValue("Name");
ChartAxis axisY = AncillaryAxesY[nameY];
if (axisY != null)
AncillaryAxesY.Remove(axisY);
axisY = new ChartAxisY(nameY);
sec.PutSerialData(axisY);
AncillaryAxesY.Add(axisY);
break;
case "ChartSeries":
if (se.ArrayCount > 0)
{
sec.PutSerialData(this);
}
else
{
string name = sec.GetItemValue("Name");
ChartSeries series = new ChartSeries(name);
ChartSeries.Add(series);
sec.PutSerialData(series);
}
break;
case "ChartSeriesVisualStyle":
sec.PutSerialData(ChartSeriesVisualStyle);
break;
case "ChartVisualStyle":
sec.PutSerialData(ChartVisualStyle);
break;
case "ChartCrosshair":
sec.PutSerialData(ChartCrosshair);
break;
case "DataLabelVisualStyle":
sec.PutSerialData(DataLabelVisualStyle);
break;
default:
base.ProcessCollection(se);
break;
}
}
#endregion
#endregion
#region States
[Flags]
private enum States : uint
{
BarOverlayEnabled = (1U << 0),
DisplayCrosshair = (1U << 1),
DropShadowDisplayed = (1U << 2),
}
#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()
{
AncillaryAxesX = null;
AncillaryAxesY = null;
AxisX = null;
AxisY = null;
ChartSeriesVisualStyle = null;
ChartVisualStyle = null;
ChartCrosshair = null;
DataLabelVisualStyle = null;
base.Dispose();
}
#endregion
}
#region CrosshairPoint
///
/// Defines a Crosshair Point
///
public class CrosshairPoint
{
#region Public variables
private ChartSeries _ChartSeries;
private SeriesPoint _SeriesPoint;
private int _PointIndex;
private int _ValueIndex;
private SortedSeriesPoints _SortedSeriesPoints;
private Point _Point;
private string _Text;
private Size _TextSize;
private bool _IsDescending;
#endregion
public CrosshairPoint(ChartSeries chartSeries, SortedSeriesPoints ssp,
int pointIndex, SeriesPoint seriesPoint, int valueIndex, Point point, bool isDescending)
{
_ChartSeries = chartSeries;
_IsDescending = isDescending;
_SortedSeriesPoints = ssp;
_PointIndex = pointIndex;
_SeriesPoint = seriesPoint;
_ValueIndex = valueIndex;
_Point = point;
}
#region Public properties
#region ChartSeries
///
/// Gets the associated chart series.
///
public ChartSeries ChartSeries
{
get { return (_ChartSeries); }
internal set { _ChartSeries = value; }
}
#endregion
#region SeriesPoint
///
/// Gets the associated SeriesPoint.
///
public SeriesPoint SeriesPoint
{
get { return (_SeriesPoint); }
internal set { _SeriesPoint = value; }
}
#endregion
#region ValueX
///
/// Gets the X-Value
///
public object ValueX
{
get { return (SeriesPoint.ValueX); }
}
#endregion
#region ValueY
///
/// Gets the associated ValueY.
///
public object ValueY
{
get
{
if (ChartSeries.SeriesType == SeriesType.VerticalDot ||
ChartSeries.SeriesType == SeriesType.HorizontalDot)
{
return (SortedSeriesPoints.CountArray[PointIndex]);
}
if (SeriesPoint.ValueY != null && (uint)_ValueIndex < SeriesPoint.ValueY.Length)
return (SeriesPoint.ValueY[_ValueIndex]);
return (string.Empty);
}
}
#endregion
#endregion
#region Internal properties
#region IsDescending
internal bool IsDescending
{
get { return (_IsDescending); }
set { _IsDescending = value; }
}
#endregion
#region Point
internal Point Point
{
get { return (_Point); }
set { _Point = value; }
}
#endregion
#region PointIndex
internal int PointIndex
{
get { return (_PointIndex); }
set { _PointIndex = value; }
}
#endregion
#region SortedSeriesPoints
internal SortedSeriesPoints SortedSeriesPoints
{
get { return (_SortedSeriesPoints); }
set { _SortedSeriesPoints = value; }
}
#endregion
#region Text
internal string Text
{
get { return (_Text); }
set { _Text = value; }
}
#endregion
#region TextSize
internal Size TextSize
{
get { return (_TextSize); }
set { _TextSize = value; }
}
#endregion
#region ValueIndex
internal int ValueIndex
{
get { return (_ValueIndex); }
set { _ValueIndex = value; }
}
#endregion
#endregion
}
#endregion
#region CrosshairGroup
internal class CrosshairGroup
{
public string Text;
public Size TextSize;
public Size LabelSize;
public int MarkerWidth;
public List Cps;
}
#endregion
#region enums
#region BarFillRange
public enum BarFillRange
{
///
/// Not set (default is ByBar)
///
NotSet = 0,
///
/// Bars are filled according to each individual
/// bar's defined range.
///
ByBar,
///
/// Bars are filled according to the associated series
/// minimum and maximum values.
///
BySeries,
}
#endregion
#region BubbleIntensityMode
public enum BubbleIntensityMode
{
///
/// Not set (default is None)
///
NotSet = 0,
///
/// Bubble intensity not used.
///
None,
///
/// Bubble intensity is expressed as an alpha value (0 - 255).
///
Alpha,
///
/// Bubble intensity is expressed as a data value (as is the size of the bubble).
///
Value,
}
#endregion
#region BubbleSizeMode
public enum BubbleSizeMode
{
///
/// Not set (default is Area)
///
NotSet = 0,
///
/// Bubble size is proportional to the bubble area.
///
Area,
///
/// Bubble size is proportional to the bubble diameter.
///
Diameter,
}
#endregion
#region ChartLineDisplayMode
[Flags]
public enum ChartLineDisplayMode
{
///
/// Not set
///
NotSet = 0,
///
/// Display defined points on line
///
DisplayPoints = (1 << 0),
///
/// Display a straight line through defined series points
///
DisplayLine = (1 << 1),
///
/// Display a spline through defined series points
///
DisplaySpline = (1 << 2),
///
/// Display a Step Line through defined series points
///
DisplayStepLine = (1 << 3),
///
/// Points are displayed unsorted
///
DisplayUnsorted = (1 << 4),
///
/// Start and end Points are connected.
///
DisplayClosed = (1 << 5),
}
#endregion
#region ChartLineAreaDisplayMode
[Flags]
public enum ChartLineAreaDisplayMode
{
///
/// Not set
///
NotSet = 0,
///
/// Not set
///
None = (1 << 0),
///
/// Display background area under series Line.
///
DisplayLine = (1 << 1),
///
/// Display background area under series Spline.
///
DisplaySpline = (1 << 2),
///
/// Display background area under series StepLine.
///
DisplayStepLine = (1 << 3),
///
/// Display background area under series EmptyLines.
///
DisplayEmptyLine = (1 << 4),
}
#endregion
#region DotPlotType
[Flags]
internal enum DotPlotType
{
None = 0,
Horizontal = (1 << 0),
Vertical = (1 << 1),
}
#endregion
#region DataLabelOverlapMode
///
/// Specifies how overlapping Series Data Labels are resolved
///
public enum DataLabelOverlapMode
{
///
/// Not set (default is None).
///
NotSet = -1,
///
/// Overlapping labels will be shown.
///
ShowOverlapping,
///
/// Overlapping labels will be hidden.
///
HideOverlapping,
///
/// Overlapping labels will be rotated around point (when applicable).
///
RotateAroundPoint,
}
#endregion
#region SeriesDisplayOrder
public enum SeriesDisplayOrder
{
///
/// Not set (default is Forward).
///
NotSet,
///
/// Series are displayed in the normal collection order.
///
Forward,
///
/// Series are displayed in the reverse collection order.
///
Reverse,
}
#endregion
#region XyAlignment
public enum XyAlignment
{
NotSet = -1,
Top,
Left,
Bottom,
Right,
}
#endregion
#endregion
}