5492 lines
158 KiB
C#
5492 lines
158 KiB
C#
using System;
|
|
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
|
|
{
|
|
/// <summary>
|
|
/// Represents the collection of Chart AxesX.
|
|
/// </summary>
|
|
[Editor("DevComponents.Charts.Design.ChartAxesCollectionEditor, DevComponents.Charts.Design, " +
|
|
"Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
|
|
public class ChartAxesXCollection : ChartAxesCollection
|
|
{
|
|
public ChartAxesXCollection()
|
|
: base(AxisOrientation.X)
|
|
{
|
|
}
|
|
|
|
#region GetUniqueName
|
|
|
|
public string GetUniqueName()
|
|
{
|
|
return (GetUniqueName("AncAxisX"));
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents the collection of Chart AxesY.
|
|
/// </summary>
|
|
[Editor("DevComponents.Charts.Design.ChartAxesCollectionEditor, DevComponents.Charts.Design, " +
|
|
"Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
|
|
public class ChartAxesYCollection : ChartAxesCollection
|
|
{
|
|
public ChartAxesYCollection()
|
|
: base(AxisOrientation.Y)
|
|
{
|
|
}
|
|
|
|
#region GetUniqueName
|
|
|
|
public string GetUniqueName()
|
|
{
|
|
return (GetUniqueName("AncAxisY"));
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents the collection of Chart Axes.
|
|
/// </summary>
|
|
public class ChartAxesCollection : CustomNamedCollection<ChartAxis>
|
|
{
|
|
#region Private variables
|
|
|
|
private AxisOrientation _AxisOrientation;
|
|
|
|
#endregion
|
|
|
|
public ChartAxesCollection(AxisOrientation axisOrientation)
|
|
{
|
|
_AxisOrientation = axisOrientation;
|
|
}
|
|
|
|
#region Public properties
|
|
|
|
#region AxisOrientation
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public AxisOrientation AxisOrientation
|
|
{
|
|
get { return (_AxisOrientation); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region InsertItem
|
|
|
|
protected override void InsertItem(int index, ChartAxis item)
|
|
{
|
|
if (item.IsPrimaryAxis == true)
|
|
throw new Exception("Primary Axes cannot be added as Ancillary Axes.");
|
|
|
|
base.InsertItem(index, item);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#region ChartAxisX
|
|
|
|
/// <summary>
|
|
/// Represents an X-Axis element.
|
|
/// </summary>
|
|
[TypeConverter(typeof(BlankExpandableObjectConverter))]
|
|
public class ChartAxisX : ChartAxis
|
|
{
|
|
#region Constructors
|
|
|
|
public ChartAxisX()
|
|
: base(AxisOrientation.X)
|
|
{
|
|
}
|
|
|
|
public ChartAxisX(string name)
|
|
: base(AxisOrientation.X)
|
|
{
|
|
Name = name;
|
|
}
|
|
|
|
public ChartAxisX(string name, object minValue, object maxValue)
|
|
: base(AxisOrientation.X)
|
|
{
|
|
Name = name;
|
|
|
|
MinValue = minValue;
|
|
MaxValue = MaxValue;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
#region MajorGridLines
|
|
|
|
///<summary>
|
|
/// Gets the axis MajorGridLines element.
|
|
///</summary>
|
|
[Description("Indicates the MajorGridLines element.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public override ChartMajorGridLines MajorGridLines
|
|
{
|
|
get
|
|
{
|
|
if (_MajorGridLines == null)
|
|
{
|
|
_MajorGridLines = new ChartMajorGridLinesX();
|
|
_MajorGridLines.Parent = this;
|
|
}
|
|
|
|
return (_MajorGridLines);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MajorTickmarks
|
|
|
|
///<summary>
|
|
/// Gets the axis MajorTickmarks element.
|
|
///</summary>
|
|
[Description("Indicates the MajorTickmarks element.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public override MajorTickmarks MajorTickmarks
|
|
{
|
|
get
|
|
{
|
|
if (_MajorTickmarks == null)
|
|
{
|
|
_MajorTickmarks = new MajorTickmarksX();
|
|
_MajorTickmarks.Parent = this;
|
|
}
|
|
|
|
return (_MajorTickmarks);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinorGridLines
|
|
|
|
///<summary>
|
|
/// Gets the axis MinorGridLines element.
|
|
///</summary>
|
|
[Description("Indicates the MinorGridLines element.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public override ChartMinorGridLines MinorGridLines
|
|
{
|
|
get
|
|
{
|
|
if (_MinorGridLines == null)
|
|
{
|
|
_MinorGridLines = new ChartMinorGridLinesX();
|
|
_MinorGridLines.Parent = this;
|
|
}
|
|
|
|
return (_MinorGridLines);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinorTickmarks
|
|
|
|
///<summary>
|
|
/// Gets the axis MinorTickmarks element.
|
|
///</summary>
|
|
[Description("Indicates the MinorTickmarks element.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public override MinorTickmarks MinorTickmarks
|
|
{
|
|
get
|
|
{
|
|
if (_MinorTickmarks == null)
|
|
{
|
|
_MinorTickmarks = new MinorTickmarksX();
|
|
_MinorTickmarks.Parent = this;
|
|
}
|
|
|
|
return (_MinorTickmarks);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
ChartAxisVisualStyle astyle = EffectiveAxisStyle;
|
|
AxisAlignment axisAlignment = GetAxisAlignment();
|
|
|
|
Rectangle bounds = layoutInfo.LayoutBounds;
|
|
|
|
if (Visible == true)
|
|
{
|
|
MeasureTitle(layoutInfo, axisAlignment);
|
|
|
|
int width = Math.Max(layoutInfo.LayoutBounds.Width, Dpi.Width(chartXy.MinContentSize.Width));
|
|
|
|
int tickmarkLen = MeasureTickmarks(layoutInfo, width);
|
|
|
|
bounds.Height = GetMeasuredHeight();
|
|
|
|
layoutInfo.LayoutBounds.Height -= tickmarkLen;
|
|
|
|
if (axisAlignment == AxisAlignment.Far)
|
|
{
|
|
layoutInfo.LayoutBounds.Y += tickmarkLen;
|
|
}
|
|
else
|
|
{
|
|
bounds.Y = layoutInfo.LayoutBounds.Bottom;
|
|
|
|
if (EdgeAxis == true)
|
|
{
|
|
bounds.Y--;
|
|
|
|
if (chartXy.DropShadowDisplayed == true)
|
|
layoutInfo.LayoutBounds.Height += 3;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int width = Math.Max(layoutInfo.LayoutBounds.Width, Dpi.Width(chartXy.MinContentSize.Width));
|
|
|
|
MeasureTickmarks(layoutInfo, width);
|
|
|
|
bounds.Height = 0;
|
|
}
|
|
|
|
CalcAxisBounds(layoutInfo, axisAlignment, bounds);
|
|
|
|
BoundsRelative = bounds;
|
|
|
|
base.MeasureOverride(layoutInfo);
|
|
}
|
|
|
|
#region MeasureTitle
|
|
|
|
protected void MeasureTitle(
|
|
ChartLayoutInfo layoutInfo, AxisAlignment axisAlignment)
|
|
{
|
|
if (Title.Visible == true)
|
|
{
|
|
Title.XyAlignment = (axisAlignment == AxisAlignment.Near)
|
|
? XyAlignment.Bottom : XyAlignment.Top;
|
|
|
|
Title.Measure(layoutInfo);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MeasureTickmarks
|
|
|
|
protected virtual int MeasureTickmarks(ChartLayoutInfo layoutInfo, int width)
|
|
{
|
|
CalcMajorSpacing(layoutInfo, width);
|
|
|
|
MajorTickmarks.TickmarkLayout = TickmarkLayout;
|
|
MinorTickmarks.TickmarkLayout = TickmarkLayout;
|
|
|
|
MajorTickmarks.Measure(layoutInfo);
|
|
MinorTickmarks.Measure(layoutInfo);
|
|
|
|
return (Math.Max(MajorTickmarks.Size.Height,
|
|
MinorTickmarks.Size.Height));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetMeasuredHeight
|
|
|
|
private int GetMeasuredHeight()
|
|
{
|
|
int height = Math.Max(MajorTickmarks.Size.Height,
|
|
MinorTickmarks.Size.Height);
|
|
|
|
if (Title.Visible == true)
|
|
height += Title.Size.Height;
|
|
|
|
return (height);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalcAxisBounds
|
|
|
|
private void CalcAxisBounds(ChartLayoutInfo layoutInfo,
|
|
AxisAlignment axisAlignment, Rectangle bounds)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
int labelHeight = 0;
|
|
int tmInnerLength = 0;
|
|
int tmOuterLength = 0;
|
|
|
|
if (TickmarkLayout.MajorCount > 0)
|
|
{
|
|
labelHeight = MajorTickmarks.GetTotalLabelHeight();
|
|
|
|
tmOuterLength = Dpi.Width(GetMaxTickMarkLength(false));
|
|
tmInnerLength = Dpi.Width(GetMaxTickMarkLength(true));
|
|
|
|
if (axisAlignment == AxisAlignment.Near)
|
|
{
|
|
if (EdgeAxis == true)
|
|
{
|
|
if (chartXy.HScrollBar.Visible == true)
|
|
tmInnerLength += (chartXy.HScrollBar.Height + 1);
|
|
|
|
bounds.Y -= tmInnerLength;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Title.Visible == true)
|
|
bounds.Y += Title.Size.Height;
|
|
}
|
|
|
|
bounds.Height = (labelHeight + tmOuterLength + tmInnerLength + 1);
|
|
|
|
AxisBounds = bounds;
|
|
|
|
Rectangle r = bounds;
|
|
r.Height = 1;
|
|
|
|
if (axisAlignment == AxisAlignment.Near)
|
|
{
|
|
r.Y += tmInnerLength;
|
|
|
|
if (EdgeAxis == false)
|
|
r.Y += 1;
|
|
}
|
|
else
|
|
{
|
|
r.Y = bounds.Bottom - tmInnerLength - 1;
|
|
}
|
|
|
|
AxisLineBounds = r;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ArrangeOverride
|
|
|
|
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
// Let the axis bounds extend into the chart's frame
|
|
// area as much as possible for better label display.
|
|
|
|
Rectangle r = AxisBounds;
|
|
r.Width = chartXy.ContentBounds.Width;
|
|
|
|
int n1 = r.X - chartXy.FrameBounds.X;
|
|
int n2 = chartXy.FrameBounds.Right - r.Right;
|
|
|
|
r.X = chartXy.FrameBounds.X;
|
|
r.Width += (n1 + n2);
|
|
|
|
AxisBounds = r;
|
|
|
|
r = AxisLineBounds;
|
|
r.Width = chartXy.ContentBounds.Width;
|
|
AxisLineBounds = r;
|
|
|
|
base.ArrangeOverride(layoutInfo);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
if (Visible == true)
|
|
{
|
|
base.RenderOverride(renderInfo);
|
|
|
|
Graphics g = renderInfo.Graphics;
|
|
ChartAxisVisualStyle astyle = EffectiveAxisStyle;
|
|
|
|
if (TickmarkLayout.MajorCount > 0)
|
|
{
|
|
Rectangle axisBounds = GetScrollBounds(AxisBounds);
|
|
|
|
Region clip = g.Clip;
|
|
g.SetClip(axisBounds, CombineMode.Intersect);
|
|
|
|
MajorTickmarks.Render(renderInfo);
|
|
MinorTickmarks.Render(renderInfo);
|
|
|
|
RenderAxisLine(g, astyle);
|
|
|
|
g.Clip = clip;
|
|
}
|
|
}
|
|
}
|
|
|
|
#region RenderAxisLine
|
|
|
|
private void RenderAxisLine(Graphics g, ChartAxisVisualStyle astyle)
|
|
{
|
|
if (astyle.AxisColor.IsEmpty == false &&
|
|
astyle.AxisColor.Equals(Color.Transparent) == false)
|
|
{
|
|
Rectangle alBounds = GetScrollBounds(AxisLineBounds);
|
|
|
|
using (Pen pen = new Pen(astyle.AxisColor, Dpi.Height1))
|
|
g.DrawLine(pen, alBounds.X, alBounds.Y, alBounds.Right - 1, alBounds.Y);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderCrosshairLabel (Point)
|
|
|
|
internal override void RenderCrosshairLabel(Graphics g, Point pt)
|
|
{
|
|
TickmarkLayout layout = TickmarkLayout;
|
|
|
|
if (layout != null && layout.Ticks != null && layout.Ticks.Length > 0)
|
|
{
|
|
TickmarkTick tick = layout.Ticks[0];
|
|
CrosshairValueVisualStyle lstyle = EffectiveCrosshairLabelStyle;
|
|
|
|
string text = GetCrosshairLabel(pt, layout, tick, lstyle);
|
|
|
|
if (string.IsNullOrEmpty(text) == false)
|
|
{
|
|
Rectangle r = GetCrosshairBounds(g, text, pt, lstyle);
|
|
|
|
lstyle.RenderBackground(g, r);
|
|
lstyle.RenderBorder(g, r);
|
|
|
|
if (lstyle.DropShadow.Enabled == Tbool.True)
|
|
lstyle.DropShadow.RenderDropShadow(g, r, true, true);
|
|
|
|
using (StringFormat sf = new StringFormat())
|
|
{
|
|
sf.Alignment = StringAlignment.Center;
|
|
sf.LineAlignment = StringAlignment.Center;
|
|
|
|
using (Brush br = new SolidBrush(lstyle.TextColor))
|
|
g.DrawString(text, lstyle.Font, br, r, sf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region GetCrosshairLabel
|
|
|
|
private string GetCrosshairLabel(Point pt,
|
|
TickmarkLayout layout, TickmarkTick tick, CrosshairValueVisualStyle lstyle)
|
|
{
|
|
object value = null;
|
|
|
|
switch (ScaleType)
|
|
{
|
|
case ScaleType.DateTime:
|
|
value = GetValueFromPoint(layout, pt);
|
|
break;
|
|
|
|
case ScaleType.Qualitative:
|
|
pt = GetChartPoint(pt);
|
|
|
|
int n = (int)Math.Floor((pt.X - (layout.NearMargin + layout.MarginOffset -
|
|
layout.MajorInterval / 2 + tick.TickPoint.X)) / (layout.MajorInterval * layout.MajorSpacing));
|
|
|
|
n += tick.Index;
|
|
|
|
if ((uint)n < QualitativeValues.Count)
|
|
value = QualitativeValues[n];
|
|
break;
|
|
|
|
case ScaleType.Quantitative:
|
|
double dvalue = Convert.ToDouble(GetValueFromPoint(layout, pt));
|
|
|
|
if (DotPlotAxis == true && Math.Floor(layout.MajorSpacing) == layout.MajorSpacing)
|
|
dvalue = Math.Floor(dvalue + .5);
|
|
|
|
value = dvalue;
|
|
break;
|
|
}
|
|
|
|
return (GetCrosshairLabel(value, lstyle));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetCrosshairBounds
|
|
|
|
private Rectangle GetCrosshairBounds(Graphics g,
|
|
string text, Point pt, CrosshairValueVisualStyle lstyle)
|
|
{
|
|
Rectangle bounds = GetScrollBounds(MajorTickmarks.LabelBounds);
|
|
Rectangle r = bounds;
|
|
|
|
SizeF sizef = g.MeasureString(text, lstyle.Font);
|
|
|
|
r.Width = (int)(sizef.Width + 2);
|
|
r.Height = (int)(sizef.Height + 2);
|
|
|
|
r.X = pt.X - (int)(sizef.Width / 2);
|
|
r.Y--;
|
|
|
|
AxisAlignment axisalignment = GetAxisAlignment();
|
|
|
|
if (lstyle.Margin.IsEmpty == false)
|
|
{
|
|
if (axisalignment == AxisAlignment.Near)
|
|
r.Y += lstyle.Margin.Top;
|
|
else
|
|
r.Y -= lstyle.Margin.Bottom;
|
|
}
|
|
|
|
if (axisalignment == AxisAlignment.Near)
|
|
r.Y += (lstyle.BorderThickness.Vertical);
|
|
else
|
|
r.Y -= (lstyle.BorderThickness.Vertical);
|
|
|
|
r.Height += lstyle.BorderThickness.Vertical;
|
|
|
|
if (lstyle.Padding.IsEmpty == false)
|
|
{
|
|
if (axisalignment == AxisAlignment.Far)
|
|
r.Y -= lstyle.Padding.Vertical;
|
|
|
|
r.Height += lstyle.Padding.Vertical;
|
|
|
|
r.X -= lstyle.Padding.Left;
|
|
r.Width += lstyle.Padding.Horizontal;
|
|
}
|
|
|
|
if (r.Bottom > bounds.Bottom)
|
|
r.Y -= (r.Bottom - bounds.Bottom);
|
|
|
|
if (r.Right > bounds.Right)
|
|
r.X -= (r.Right - bounds.Right);
|
|
|
|
return (r);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderCrosshairLabel (CrosshairPoint)
|
|
|
|
internal override void RenderCrosshairLabel(Graphics g, CrosshairPoint cp)
|
|
{
|
|
CrosshairValueVisualStyle lstyle = EffectiveCrosshairLabelStyle;
|
|
|
|
string text = (cp.ChartSeries.IsRotated == false)
|
|
? GetCrosshairLabel(cp.SeriesPoint.ValueX, lstyle)
|
|
: GetCrosshairLabel(cp.SeriesPoint.ValueY[cp.ValueIndex], lstyle);
|
|
|
|
if (string.IsNullOrEmpty(text) == false)
|
|
{
|
|
Rectangle r = GetCrosshairBounds(g, text, cp.Point, lstyle);
|
|
|
|
lstyle.RenderBackground(g, r);
|
|
lstyle.RenderBorder(g, r);
|
|
|
|
if (lstyle.DropShadow.Enabled == Tbool.True)
|
|
lstyle.DropShadow.RenderDropShadow(g, r, true, true);
|
|
|
|
using (StringFormat sf = new StringFormat())
|
|
{
|
|
sf.Alignment = StringAlignment.Center;
|
|
sf.LineAlignment = StringAlignment.Center;
|
|
|
|
using (Brush br = new SolidBrush(lstyle.TextColor))
|
|
g.DrawString(text, lstyle.Font, br, r, sf);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderBackground
|
|
|
|
internal override void RenderBackground(ChartRenderInfo renderInfo, Rectangle scContentBounds)
|
|
{
|
|
if (UseAlternateBackground == true)
|
|
{
|
|
if (TickmarkLayout.Ticks != null)
|
|
{
|
|
Graphics g = renderInfo.Graphics;
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
Point pt = chartXy.GetLocalAdjustedPoint(Point.Empty);
|
|
|
|
if (ScaleType == ScaleType.Qualitative)
|
|
pt.X -= (int)(TickmarkLayout.MajorInterval / 2);
|
|
|
|
ChartAxisVisualStyle astyle = EffectiveAxisStyle;
|
|
|
|
if (astyle.AlternateBackground.IsSolidBrush == true)
|
|
{
|
|
using (Brush br = astyle.AlternateBackground.GetBrush(Rectangle.Empty))
|
|
{
|
|
RenderAltBackground(g,
|
|
scContentBounds, pt, TickmarkLayout, astyle, br);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RenderAltBackground(g,
|
|
scContentBounds, pt, TickmarkLayout, astyle, null);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region RenderAltBackground
|
|
|
|
private void RenderAltBackground(Graphics g, Rectangle scContentBounds,
|
|
Point pt, TickmarkLayout TickmarkLayout, ChartAxisVisualStyle astyle, Brush br)
|
|
{
|
|
foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
|
|
{
|
|
double value = GetTickmarkAltValue(tmi);
|
|
int n = (int)(Math.Ceiling(value / TickmarkLayout.MajorSpacing));
|
|
|
|
if (n % 2 == 0)
|
|
{
|
|
Rectangle r = scContentBounds;
|
|
r.X = tmi.TickPoint.X + pt.X;
|
|
r.Width = (int)TickmarkLayout.MajorInterval + 1;
|
|
|
|
if (br == null)
|
|
{
|
|
using (Brush br2 = astyle.AlternateBackground.GetBrush(r))
|
|
g.FillRectangle(br2, r);
|
|
}
|
|
else
|
|
{
|
|
g.FillRectangle(br, r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderStripes
|
|
|
|
internal override void RenderStripes(ChartRenderInfo renderInfo, Rectangle scContentBounds)
|
|
{
|
|
if (AxisStripes.Count > 0)
|
|
{
|
|
Graphics g = renderInfo.Graphics;
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
Point pt = chartXy.GetLocalAdjustedPoint(Point.Empty);
|
|
|
|
foreach (AxisStripe stripe in AxisStripes)
|
|
{
|
|
if (stripe.IsDisplayed == true)
|
|
{
|
|
if (stripe.MinValue != stripe.MaxValue)
|
|
{
|
|
int x1 = chartXy.GetDataPointX(this, stripe.MinValue);
|
|
int x2 = chartXy.GetDataPointX(this, stripe.MaxValue);
|
|
|
|
Rectangle r = scContentBounds;
|
|
r.X = (x1 + pt.X);
|
|
r.Width = (x2 - x1);
|
|
|
|
RenderStripe(g, r, stripe);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateRangeValues
|
|
|
|
internal override void UpdateRangeValues(ChartXy chartXy)
|
|
{
|
|
bool seriesSeen = false;
|
|
|
|
foreach (ChartSeries series in chartXy.ChartSeries)
|
|
{
|
|
if (series.AxisX == this)
|
|
{
|
|
if (series.SeriesPoints.Count > 0)
|
|
UpdateRangeValuesEx(chartXy, series, ref seriesSeen);
|
|
}
|
|
}
|
|
|
|
if (seriesSeen == false)
|
|
{
|
|
foreach (ChartSeries series in chartXy.ChartSeries)
|
|
{
|
|
if (series.AxisX == null)
|
|
{
|
|
if (series.SeriesPoints.Count > 0)
|
|
UpdateRangeValuesEx(chartXy, series, ref seriesSeen);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region UpdateRangeValuesEx
|
|
|
|
private void UpdateRangeValuesEx(ChartXy chartXy, ChartSeries series, ref bool seriesSeen)
|
|
{
|
|
if (ActualMinValue == null)
|
|
{
|
|
ActualMinValue = series.MinValueX;
|
|
ActualMaxValue = series.MaxValueX;
|
|
}
|
|
else
|
|
{
|
|
if (chartXy.DataCompare(series.MinValueX, ActualMinValue) < 0)
|
|
ActualMinValue = series.MinValueX;
|
|
|
|
if (chartXy.DataCompare(series.MaxValueX, ActualMaxValue) > 0)
|
|
ActualMaxValue = series.MaxValueX;
|
|
}
|
|
|
|
if (seriesSeen == false)
|
|
{
|
|
seriesSeen = true;
|
|
|
|
ScaleType = series.ActualScaleTypeX;
|
|
}
|
|
else
|
|
{
|
|
if (series.ActualScaleTypeX != ScaleType)
|
|
{
|
|
string s = "XAxis cannot contain series with differing ScaleTypes";
|
|
|
|
if (String.IsNullOrEmpty(Name) == false)
|
|
s += " (" + Name + ")";
|
|
|
|
throw new Exception(s);
|
|
}
|
|
}
|
|
|
|
if (ScaleType == ScaleType.Qualitative)
|
|
{
|
|
if (series.IsRotated == true)
|
|
{
|
|
foreach (object o in series.QualitativeYValues)
|
|
{
|
|
if (QualitativeValues.Contains(o) == false)
|
|
QualitativeValues.Add(o);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (object o in series.QualitativeXValues)
|
|
{
|
|
if (QualitativeValues.Contains(o) == false)
|
|
QualitativeValues.Add(o);
|
|
}
|
|
}
|
|
|
|
if (QualitativeValues.Count - 1 > (int)ActualMaxValue)
|
|
ActualMaxValue = QualitativeValues.Count - 1;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetValueFromPoint
|
|
|
|
internal override object GetValueFromPoint(TickmarkLayout layout, Point pt)
|
|
{
|
|
if (layout.Ticks != null)
|
|
{
|
|
pt = GetChartPoint(pt);
|
|
|
|
TickmarkTick lastTick = null;
|
|
|
|
foreach (TickmarkTick tick in layout.Ticks)
|
|
{
|
|
if (tick.TickPoint.X == pt.X)
|
|
return (tick.Value);
|
|
|
|
if (tick.TickPoint.X > pt.X)
|
|
{
|
|
if (lastTick != null)
|
|
{
|
|
double d = ((double)tick.TickPoint.X - lastTick.TickPoint.X) / (layout.MinorCount + 1);
|
|
|
|
for (int i = 1; i <= layout.MinorCount; i++)
|
|
{
|
|
int x = (int)(lastTick.TickPoint.X + (d * i));
|
|
|
|
if (x >= pt.X)
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
lastTick = tick;
|
|
}
|
|
|
|
int dx = pt.X - Bounds.X;
|
|
|
|
switch (ScaleType)
|
|
{
|
|
case ScaleType.Qualitative:
|
|
return (layout.MajorSpacing * ((dx + layout.MarginOffset) /
|
|
layout.MajorInterval) + (int)layout.BaseValue);
|
|
|
|
case ScaleType.DateTime:
|
|
return (GetDateTimePointValue(layout, dx));
|
|
|
|
default:
|
|
return (layout.MajorSpacing * ((dx + layout.MarginOffset) /
|
|
layout.MajorInterval) + Convert.ToDouble(layout.BaseValue));
|
|
}
|
|
}
|
|
|
|
return (null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetPointFromValue
|
|
|
|
/// <summary>
|
|
/// Gets the chart Point from the given axis data value.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
public override Point GetPointFromValue(object value)
|
|
{
|
|
return (new Point(GetDisplayValue(value), 0));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDisplayValue
|
|
|
|
internal override int GetDisplayValue(object axisValue)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
return (chartXy.GetDataPointX(this, axisValue));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EnsureVisible
|
|
|
|
/// <summary>
|
|
/// Ensures the given data value is visible and
|
|
/// optionally centered on screen.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
public override void EnsureVisible(object value, bool center)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
if (chartXy != null)
|
|
{
|
|
if (chartXy.ChartControl != null)
|
|
{
|
|
if (chartXy.ChartControl.LayoutValid == false)
|
|
chartXy.ChartControl.UpdateLayout();
|
|
|
|
Rectangle cbounds = chartXy.ContentBounds;
|
|
|
|
int x = GetDisplayValue(value);
|
|
|
|
if (center == true)
|
|
{
|
|
int n = (x - cbounds.Width / 2) - cbounds.X;
|
|
|
|
chartXy.HScrollOffset = n;
|
|
}
|
|
else
|
|
{
|
|
int n = cbounds.X + chartXy.HScrollOffset + 20;
|
|
|
|
if (x < n)
|
|
{
|
|
chartXy.HScrollOffset += (x - n);
|
|
}
|
|
else
|
|
{
|
|
n = cbounds.Right + chartXy.HScrollOffset - 20;
|
|
|
|
if (x > n)
|
|
chartXy.HScrollOffset += (x - n);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Copy/CopyTo
|
|
|
|
/// <summary>
|
|
/// Creates a copy of the axis.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override ChartVisualElement Copy()
|
|
{
|
|
ChartAxisX copy = new ChartAxisX();
|
|
|
|
CopyTo(copy);
|
|
|
|
return (copy);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies the current axis properties to the
|
|
/// given "copy" axis.
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
ChartAxisX c = copy as ChartAxisX;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyTo(c);
|
|
|
|
MajorGridLines.CopyTo(c.MajorGridLines);
|
|
MinorGridLines.CopyTo(c.MinorGridLines);
|
|
|
|
MajorTickmarks.CopyTo(c.MajorTickmarks);
|
|
MinorTickmarks.CopyTo(c.MinorTickmarks);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSerialData
|
|
|
|
internal override SerialElementCollection GetSerialData(string serialName)
|
|
{
|
|
SerialElementCollection sec = new SerialElementCollection();
|
|
|
|
if (serialName != null)
|
|
{
|
|
if (serialName.Equals("") == true)
|
|
serialName = "ChartAxisX";
|
|
|
|
sec.AddStartElement(serialName);
|
|
}
|
|
|
|
sec.AddElement(MajorGridLines.GetSerialData("MajorGridLines"));
|
|
sec.AddElement(MinorGridLines.GetSerialData("MinorGridLines"));
|
|
sec.AddElement(MajorTickmarks.GetSerialData("MajorTickmarks"));
|
|
sec.AddElement(MinorTickmarks.GetSerialData("MinorTickmarks"));
|
|
|
|
sec.AddElement(base.GetSerialData(null));
|
|
|
|
if (serialName != null)
|
|
sec.AddEndElement(serialName);
|
|
|
|
return (sec);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PutSerialData
|
|
|
|
#region ProcessCollection
|
|
|
|
internal override void ProcessCollection(SerialElement se)
|
|
{
|
|
SerialElementCollection sec = se.Sec;
|
|
|
|
switch (se.Name)
|
|
{
|
|
case "MajorGridLines":
|
|
sec.PutSerialData(MajorGridLines);
|
|
break;
|
|
|
|
case "MinorGridLines":
|
|
sec.PutSerialData(MinorGridLines);
|
|
break;
|
|
|
|
case "MajorTickmarks":
|
|
sec.PutSerialData(MajorTickmarks);
|
|
break;
|
|
|
|
case "MinorTickmarks":
|
|
sec.PutSerialData(MinorTickmarks);
|
|
break;
|
|
|
|
default:
|
|
base.ProcessCollection(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ChartAxisY
|
|
|
|
/// <summary>
|
|
/// Represents a Y-Axis element.
|
|
/// </summary>
|
|
[TypeConverter(typeof(BlankExpandableObjectConverter))]
|
|
public class ChartAxisY : ChartAxis
|
|
{
|
|
#region Constructors
|
|
|
|
public ChartAxisY()
|
|
: base(AxisOrientation.Y)
|
|
{
|
|
}
|
|
|
|
public ChartAxisY(string name)
|
|
: base(AxisOrientation.Y)
|
|
{
|
|
Name = name;
|
|
}
|
|
|
|
public ChartAxisY(string name, object minValue, object maxValue)
|
|
: base(AxisOrientation.Y)
|
|
{
|
|
Name = name;
|
|
|
|
MinValue = minValue;
|
|
MaxValue = MaxValue;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
#region MajorGridLines
|
|
|
|
///<summary>
|
|
/// Gets the axis MajorGridLines element.
|
|
///</summary>
|
|
[Description("Indicates the MajorGridLines element.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public override ChartMajorGridLines MajorGridLines
|
|
{
|
|
get
|
|
{
|
|
if (_MajorGridLines == null)
|
|
{
|
|
_MajorGridLines = new ChartMajorGridLinesY();
|
|
_MajorGridLines.Parent = this;
|
|
}
|
|
|
|
return (_MajorGridLines);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MajorTickmarks
|
|
|
|
///<summary>
|
|
/// Gets the axis MajorTickmarks element.
|
|
///</summary>
|
|
[Description("Indicates the MajorTickmarks element.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public override MajorTickmarks MajorTickmarks
|
|
{
|
|
get
|
|
{
|
|
if (_MajorTickmarks == null)
|
|
{
|
|
_MajorTickmarks = new MajorTickmarksY();
|
|
_MajorTickmarks.Parent = this;
|
|
}
|
|
|
|
return (_MajorTickmarks);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinorGridLines
|
|
|
|
///<summary>
|
|
/// Gets the axis MinorGridLines element.
|
|
///</summary>
|
|
[Description("Indicates the MinorGridLines element.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public override ChartMinorGridLines MinorGridLines
|
|
{
|
|
get
|
|
{
|
|
if (_MinorGridLines == null)
|
|
{
|
|
_MinorGridLines = new ChartMinorGridLinesY();
|
|
_MinorGridLines.Parent = this;
|
|
}
|
|
|
|
return (_MinorGridLines);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinorTickmarks
|
|
|
|
///<summary>
|
|
/// Gets the axis MinorTickmarks element.
|
|
///</summary>
|
|
[Description("Indicates the MinorTickmarks element.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public override MinorTickmarks MinorTickmarks
|
|
{
|
|
get
|
|
{
|
|
if (_MinorTickmarks == null)
|
|
{
|
|
_MinorTickmarks = new MinorTickmarksY();
|
|
_MinorTickmarks.Parent = this;
|
|
}
|
|
|
|
return (_MinorTickmarks);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
ChartAxisVisualStyle astyle = EffectiveAxisStyle;
|
|
AxisAlignment axisAlignment = GetAxisAlignment();
|
|
|
|
Rectangle bounds = layoutInfo.LayoutBounds;
|
|
|
|
if (Visible == true)
|
|
{
|
|
MeasureTitle(layoutInfo, axisAlignment);
|
|
|
|
int height = Math.Max(layoutInfo.LayoutBounds.Height, Dpi.Height((chartXy.MinContentSize.Height)));
|
|
int tickmarkLen = MeasureTickmarks(layoutInfo, height);
|
|
|
|
bounds.Width = GetMeasuredWidth();
|
|
|
|
layoutInfo.LayoutBounds.Width -= tickmarkLen;
|
|
|
|
if (axisAlignment == AxisAlignment.Far)
|
|
{
|
|
layoutInfo.LayoutBounds.X += tickmarkLen;
|
|
}
|
|
else
|
|
{
|
|
bounds.X = layoutInfo.LayoutBounds.Right;
|
|
|
|
if (EdgeAxis == true)
|
|
{
|
|
bounds.X -= 1;
|
|
|
|
if (chartXy.DropShadowDisplayed == true)
|
|
layoutInfo.LayoutBounds.Width += 3;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int height = Math.Max(layoutInfo.LayoutBounds.Height, Dpi.Height(chartXy.MinContentSize.Height));
|
|
int tickmarkLen = MeasureTickmarks(layoutInfo, height);
|
|
|
|
bounds.Width = 0;
|
|
}
|
|
|
|
CalcAxisBounds(layoutInfo, axisAlignment, bounds);
|
|
|
|
BoundsRelative = bounds;
|
|
|
|
base.MeasureOverride(layoutInfo);
|
|
}
|
|
|
|
#region MeasureTitle
|
|
|
|
protected void MeasureTitle(
|
|
ChartLayoutInfo layoutInfo, AxisAlignment axisAlignment)
|
|
{
|
|
if (Title.Visible == true)
|
|
{
|
|
Title.XyAlignment = (axisAlignment == AxisAlignment.Near)
|
|
? XyAlignment.Right : XyAlignment.Left;
|
|
|
|
Title.Measure(layoutInfo);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MeasureTickmarks
|
|
|
|
protected virtual int MeasureTickmarks(ChartLayoutInfo layoutInfo, int height)
|
|
{
|
|
CalcMajorSpacing(layoutInfo, height);
|
|
|
|
MajorTickmarks.TickmarkLayout = TickmarkLayout;
|
|
MinorTickmarks.TickmarkLayout = TickmarkLayout;
|
|
|
|
MajorTickmarks.Measure(layoutInfo);
|
|
MinorTickmarks.Measure(layoutInfo);
|
|
|
|
return (Math.Max(MajorTickmarks.Size.Width,
|
|
MinorTickmarks.Size.Width));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetMeasuredWidth
|
|
|
|
private int GetMeasuredWidth()
|
|
{
|
|
int width = Math.Max(MajorTickmarks.Size.Width,
|
|
MinorTickmarks.Size.Width);
|
|
|
|
if (Title.Visible == true)
|
|
width += Title.Size.Width;
|
|
|
|
return (width);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalcAxisBounds
|
|
|
|
private void CalcAxisBounds(ChartLayoutInfo layoutInfo,
|
|
AxisAlignment axisAlignment, Rectangle bounds)
|
|
{
|
|
int labelWidth = 0;
|
|
int tmInnerLength = 0;
|
|
int tmOuterLength = 0;
|
|
|
|
if (TickmarkLayout.MajorCount > 0)
|
|
{
|
|
labelWidth = MajorTickmarks.GetTotalLabelWidth();
|
|
|
|
tmOuterLength = Dpi.Width(GetMaxTickMarkLength(false));
|
|
tmInnerLength = Dpi.Width(GetMaxTickMarkLength(true));
|
|
|
|
if (axisAlignment == AxisAlignment.Near)
|
|
{
|
|
if (EdgeAxis == true)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
if (chartXy.VScrollBar.Visible == true)
|
|
tmInnerLength += (chartXy.VScrollBar.Width + 1);
|
|
|
|
bounds.X -= tmInnerLength;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Title.Visible == true)
|
|
bounds.X += Title.Size.Width;
|
|
}
|
|
|
|
bounds.Width = (labelWidth + tmOuterLength + tmInnerLength + 1);
|
|
|
|
AxisBounds = bounds;
|
|
|
|
Rectangle r = bounds;
|
|
r.Width = 1;
|
|
|
|
if (axisAlignment == AxisAlignment.Near)
|
|
{
|
|
r.X += tmInnerLength;
|
|
|
|
if (EdgeAxis == false)
|
|
r.X += 1;
|
|
}
|
|
else
|
|
{
|
|
r.X = bounds.Right - tmInnerLength - 1;
|
|
}
|
|
|
|
AxisLineBounds = r;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ArrangeOverride
|
|
|
|
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
// Let the axis bounds extend into the chart's frame
|
|
// area as much as possible for better label display.
|
|
|
|
Rectangle r = AxisBounds;
|
|
r.Height = chartXy.ContentBounds.Height;
|
|
|
|
int n1 = r.Y - chartXy.FrameBounds.Y;
|
|
int n2 = chartXy.FrameBounds.Bottom - r.Bottom;
|
|
|
|
r.Y = chartXy.FrameBounds.Y;
|
|
r.Height += (n1 + n2);
|
|
|
|
AxisBounds = r;
|
|
|
|
r = AxisLineBounds;
|
|
r.Height = chartXy.ContentBounds.Height;
|
|
AxisLineBounds = r;
|
|
|
|
base.ArrangeOverride(layoutInfo);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
base.RenderOverride(renderInfo);
|
|
|
|
Graphics g = renderInfo.Graphics;
|
|
ChartAxisVisualStyle astyle = EffectiveAxisStyle;
|
|
|
|
if (TickmarkLayout.MajorCount > 0)
|
|
{
|
|
Rectangle axisBounds = GetScrollBounds(AxisBounds);
|
|
|
|
Region clip = g.Clip;
|
|
g.SetClip(axisBounds, CombineMode.Intersect);
|
|
|
|
MajorTickmarks.Render(renderInfo);
|
|
MinorTickmarks.Render(renderInfo);
|
|
|
|
RenderAxisLine(g, astyle);
|
|
|
|
g.Clip = clip;
|
|
}
|
|
}
|
|
|
|
#region RenderAxisLine
|
|
|
|
private void RenderAxisLine(Graphics g, ChartAxisVisualStyle astyle)
|
|
{
|
|
if (astyle.AxisColor.IsEmpty == false &&
|
|
astyle.AxisColor.Equals(Color.Transparent) == false)
|
|
{
|
|
Rectangle alBounds = GetScrollBounds(AxisLineBounds);
|
|
|
|
using (Pen pen = new Pen(astyle.AxisColor, Dpi.Width1))
|
|
g.DrawLine(pen, alBounds.X, alBounds.Y, alBounds.X, alBounds.Bottom - 1);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderCrosshairLabel (Point)
|
|
|
|
internal override void RenderCrosshairLabel(Graphics g, Point pt)
|
|
{
|
|
TickmarkLayout layout = TickmarkLayout;
|
|
|
|
if (layout != null && layout.Ticks != null && layout.Ticks.Length > 0)
|
|
{
|
|
TickmarkTick tick = layout.Ticks[0];
|
|
CrosshairValueVisualStyle lstyle = EffectiveCrosshairLabelStyle;
|
|
|
|
string text = GetCrosshairLabel(pt, layout, tick, lstyle);
|
|
|
|
if (string.IsNullOrEmpty(text) == false)
|
|
{
|
|
Rectangle r = GetCrosshairBounds(g, text, pt, lstyle);
|
|
|
|
lstyle.RenderBackground(g, r);
|
|
lstyle.RenderBorder(g, r);
|
|
|
|
if (lstyle.DropShadow.Enabled == Tbool.True)
|
|
lstyle.DropShadow.RenderDropShadow(g, r, true, true);
|
|
|
|
using (StringFormat sf = new StringFormat())
|
|
{
|
|
sf.Alignment = StringAlignment.Center;
|
|
sf.LineAlignment = StringAlignment.Center;
|
|
|
|
using (Brush br = new SolidBrush(lstyle.TextColor))
|
|
g.DrawString(text, lstyle.Font, br, r, sf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region GetCrosshairLabel
|
|
|
|
private string GetCrosshairLabel(Point pt,
|
|
TickmarkLayout layout, TickmarkTick tick, CrosshairValueVisualStyle lstyle)
|
|
{
|
|
object value = null;
|
|
|
|
switch (ScaleType)
|
|
{
|
|
case ScaleType.DateTime:
|
|
value = GetValueFromPoint(layout, pt);
|
|
break;
|
|
|
|
case ScaleType.Qualitative:
|
|
pt = GetChartPoint(pt);
|
|
|
|
int n = (int)Math.Floor(((tick.TickPoint.Y - layout.NearMargin - layout.MarginOffset +
|
|
layout.MajorInterval / 2) - pt.Y) / (layout.MajorInterval * layout.MajorSpacing));
|
|
|
|
n += tick.Index;
|
|
|
|
if ((uint)n < QualitativeValues.Count)
|
|
value = QualitativeValues[n];
|
|
break;
|
|
|
|
case ScaleType.Quantitative:
|
|
double dvalue = (Double)GetValueFromPoint(layout, pt);
|
|
|
|
if (DotPlotAxis == true && Math.Floor(layout.MajorSpacing) == layout.MajorSpacing)
|
|
dvalue = Math.Floor(dvalue + .5);
|
|
|
|
value = dvalue;
|
|
break;
|
|
}
|
|
|
|
return (GetCrosshairLabel(value, lstyle));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetCrosshairBounds
|
|
|
|
private Rectangle GetCrosshairBounds(Graphics g,
|
|
string text, Point pt, CrosshairValueVisualStyle lstyle)
|
|
{
|
|
ChartXy chartXy = (ChartXy)Parent;
|
|
|
|
AxisAlignment axisalignment = GetAxisAlignment();
|
|
Rectangle r = GetScrollBounds(MajorTickmarks.LabelBounds);
|
|
ChartXyVisualStyle cstyle = chartXy.EffectiveChartStyle;
|
|
|
|
if (axisalignment == AxisAlignment.Far)
|
|
{
|
|
r.X -= cstyle.Padding.Left;
|
|
r.Width += cstyle.Padding.Left;
|
|
}
|
|
else
|
|
{
|
|
r.Width += cstyle.Padding.Right;
|
|
}
|
|
|
|
SizeF sizef = g.MeasureString(text, lstyle.Font);
|
|
|
|
int width = (int) sizef.Width + 2;
|
|
|
|
if (Visible == true)
|
|
width = Math.Min(r.Width, width);
|
|
|
|
if (axisalignment == AxisAlignment.Far)
|
|
r.X = Math.Max(r.X, r.Right - width);
|
|
|
|
r.Width = width;
|
|
|
|
r.Y = pt.Y - (int)(sizef.Height / 2) - 2 - lstyle.BorderThickness.Top;
|
|
r.Height = (int)sizef.Height;
|
|
|
|
if (lstyle.Margin.IsEmpty == false)
|
|
{
|
|
if (axisalignment == AxisAlignment.Near)
|
|
r.Y += lstyle.Margin.Top;
|
|
else
|
|
r.Y -= lstyle.Margin.Bottom;
|
|
}
|
|
|
|
if (axisalignment == AxisAlignment.Near)
|
|
r.X += (lstyle.BorderThickness.Horizontal);
|
|
else
|
|
r.X -= (lstyle.BorderThickness.Horizontal);
|
|
|
|
r.Width += lstyle.BorderThickness.Horizontal;
|
|
r.Height += lstyle.BorderThickness.Vertical;
|
|
|
|
if (lstyle.Padding.IsEmpty == false)
|
|
{
|
|
if (axisalignment == AxisAlignment.Far)
|
|
r.Y -= lstyle.Padding.Vertical;
|
|
|
|
r.Height += lstyle.Padding.Vertical;
|
|
|
|
r.X -= lstyle.Padding.Left;
|
|
r.Width += lstyle.Padding.Horizontal;
|
|
}
|
|
|
|
return (r);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderCrosshairLabel (CrosshairPoint)
|
|
|
|
internal override void RenderCrosshairLabel(Graphics g, CrosshairPoint cp)
|
|
{
|
|
if ((DotPlotAxis == true) ||
|
|
(cp.SeriesPoint.ValueY == null || cp.SeriesPoint.ValueY.Length == 0))
|
|
{
|
|
RenderCrosshairLabel(g, cp.Point);
|
|
}
|
|
else
|
|
{
|
|
CrosshairValueVisualStyle lstyle = EffectiveCrosshairLabelStyle;
|
|
|
|
string text = (cp.ChartSeries.IsRotated == true)
|
|
? GetCrosshairLabel(cp.SeriesPoint.ValueX, lstyle)
|
|
: GetCrosshairLabel(cp.SeriesPoint.ValueY[cp.ValueIndex], lstyle);
|
|
|
|
if (string.IsNullOrEmpty(text) == false)
|
|
{
|
|
Rectangle r = GetCrosshairBounds(g, text, cp.Point, lstyle);
|
|
|
|
lstyle.RenderBackground(g, r);
|
|
lstyle.RenderBorder(g, r);
|
|
|
|
if (lstyle.DropShadow.Enabled == Tbool.True)
|
|
lstyle.DropShadow.RenderDropShadow(g, r, true, true);
|
|
|
|
using (StringFormat sf = new StringFormat())
|
|
{
|
|
sf.Alignment = StringAlignment.Center;
|
|
sf.LineAlignment = StringAlignment.Center;
|
|
|
|
using (Brush br = new SolidBrush(lstyle.TextColor))
|
|
g.DrawString(text, lstyle.Font, br, r, sf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderBackground
|
|
|
|
internal override void RenderBackground(ChartRenderInfo renderInfo, Rectangle scContentBounds)
|
|
{
|
|
if (UseAlternateBackground == true)
|
|
{
|
|
if (TickmarkLayout.Ticks != null)
|
|
{
|
|
Graphics g = renderInfo.Graphics;
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
Point pt = chartXy.GetLocalAdjustedPoint(Point.Empty);
|
|
|
|
if (ScaleType == ScaleType.Qualitative)
|
|
pt.Y -= (int)(TickmarkLayout.MajorInterval / 2);
|
|
|
|
ChartAxisVisualStyle astyle = EffectiveAxisStyle;
|
|
|
|
if (astyle.AlternateBackground.IsSolidBrush == true)
|
|
{
|
|
using (Brush br = astyle.AlternateBackground.GetBrush(Rectangle.Empty))
|
|
{
|
|
RenderAltBackground(g,
|
|
scContentBounds, pt, TickmarkLayout, astyle, br);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RenderAltBackground(g,
|
|
scContentBounds, pt, TickmarkLayout, astyle, null);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region RenderAltBackground
|
|
|
|
private void RenderAltBackground(Graphics g, Rectangle scContentBounds,
|
|
Point pt, TickmarkLayout TickmarkLayout, ChartAxisVisualStyle astyle, Brush br)
|
|
{
|
|
foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
|
|
{
|
|
double value = GetTickmarkAltValue(tmi);
|
|
int n = (int)(Math.Ceiling(value / TickmarkLayout.MajorSpacing));
|
|
|
|
if (n % 2 == 0)
|
|
{
|
|
Rectangle r = scContentBounds;
|
|
r.Y = tmi.TickPoint.Y + pt.Y;
|
|
r.Height = (int)TickmarkLayout.MajorInterval + 1;
|
|
|
|
if (br == null)
|
|
{
|
|
using (Brush br2 = astyle.AlternateBackground.GetBrush(r))
|
|
g.FillRectangle(br2, r);
|
|
}
|
|
else
|
|
{
|
|
g.FillRectangle(br, r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderStripes
|
|
|
|
internal override void RenderStripes(ChartRenderInfo renderInfo, Rectangle scContentBounds)
|
|
{
|
|
if (AxisStripes.Count > 0)
|
|
{
|
|
Graphics g = renderInfo.Graphics;
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
Point pt = chartXy.GetLocalAdjustedPoint(Point.Empty);
|
|
|
|
foreach (AxisStripe stripe in AxisStripes)
|
|
{
|
|
if (stripe.IsDisplayed == true)
|
|
{
|
|
int y2 = chartXy.GetDataPointY(this, stripe.MinValue);
|
|
int y1 = chartXy.GetDataPointY(this, stripe.MaxValue);
|
|
|
|
Rectangle r = scContentBounds;
|
|
r.Y = (y1 + pt.Y);
|
|
r.Height = (y2 - y1) + 1;
|
|
|
|
RenderStripe(g, r, stripe);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateRangeValues
|
|
|
|
internal override void UpdateRangeValues(ChartXy chartXy)
|
|
{
|
|
bool seriesSeen = false;
|
|
|
|
foreach (ChartSeries series in chartXy.ChartSeries)
|
|
{
|
|
if (series.AxisY == this)
|
|
{
|
|
if (series.SeriesPoints.Count > 0)
|
|
UpdateRangeValuesEx(chartXy, series, ref seriesSeen);
|
|
}
|
|
}
|
|
|
|
if (seriesSeen == false)
|
|
{
|
|
foreach (ChartSeries series in chartXy.ChartSeries)
|
|
{
|
|
if (series.AxisY == null)
|
|
{
|
|
if (series.SeriesPoints.Count > 0)
|
|
UpdateRangeValuesEx(chartXy, series, ref seriesSeen);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region UpdateRangeValuesEx
|
|
|
|
private void UpdateRangeValuesEx(ChartXy chartXy, ChartSeries series, ref bool seriesSeen)
|
|
{
|
|
if (ActualMinValue == null)
|
|
{
|
|
ActualMinValue = series.MinValueY;
|
|
ActualMaxValue = series.MaxValueY;
|
|
}
|
|
else
|
|
{
|
|
if (chartXy.DataCompare(series.MinValueY, ActualMinValue) < 0)
|
|
ActualMinValue = series.MinValueY;
|
|
|
|
if (chartXy.DataCompare(series.MaxValueY, ActualMaxValue) > 0)
|
|
ActualMaxValue = series.MaxValueY;
|
|
}
|
|
|
|
if (seriesSeen == false)
|
|
{
|
|
seriesSeen = true;
|
|
|
|
ScaleType = series.ActualScaleTypeY;
|
|
}
|
|
else
|
|
{
|
|
if (series.ActualScaleTypeY != ScaleType)
|
|
{
|
|
string s = "YAxis cannot contain series with differing ScaleTypes";
|
|
|
|
if (String.IsNullOrEmpty(Name) == false)
|
|
s += " (" + Name + ")";
|
|
|
|
throw new Exception(s);
|
|
}
|
|
}
|
|
|
|
if (ScaleType == ScaleType.Qualitative)
|
|
{
|
|
if (series.IsRotated == true)
|
|
{
|
|
foreach (object o in series.QualitativeXValues)
|
|
{
|
|
if (QualitativeValues.Contains(o) == false)
|
|
QualitativeValues.Add(o);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (object o in series.QualitativeYValues)
|
|
{
|
|
if (QualitativeValues.Contains(o) == false)
|
|
QualitativeValues.Add(o);
|
|
}
|
|
}
|
|
|
|
if (QualitativeValues.Count - 1 > (int)ActualMaxValue)
|
|
ActualMaxValue = QualitativeValues.Count - 1;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetValueFromPoint
|
|
|
|
internal override object GetValueFromPoint(TickmarkLayout layout, Point pt)
|
|
{
|
|
pt = GetChartPoint(pt);
|
|
|
|
TickmarkTick lastTick = null;
|
|
|
|
foreach (TickmarkTick tick in layout.Ticks)
|
|
{
|
|
if (tick.TickPoint.Y == pt.Y)
|
|
return (Convert.ToDouble(tick.Value));
|
|
|
|
if (tick.TickPoint.Y < pt.Y)
|
|
{
|
|
if (lastTick != null)
|
|
{
|
|
double d = ((double)lastTick.TickPoint.Y - tick.TickPoint.Y) / (layout.MinorCount + 1);
|
|
|
|
for (int i = 1; i <= layout.MinorCount; i++)
|
|
{
|
|
int y = (int)(lastTick.TickPoint.Y - (d * i));
|
|
|
|
if (y == pt.Y)
|
|
return (Convert.ToDouble(lastTick.Value) + (layout.MajorSpacing / (layout.MinorCount + 1) * i));
|
|
|
|
if (y < pt.Y)
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
lastTick = tick;
|
|
}
|
|
|
|
int dy = Bounds.Bottom - pt.Y;
|
|
|
|
switch (ScaleType)
|
|
{
|
|
case ScaleType.Qualitative:
|
|
return (layout.MajorSpacing * ((dy + layout.MarginOffset) /
|
|
layout.MajorInterval) + (int)layout.BaseValue);
|
|
|
|
case ScaleType.DateTime:
|
|
return (GetDateTimePointValue(layout, dy));
|
|
|
|
default:
|
|
return (layout.MajorSpacing * ((dy + layout.MarginOffset) /
|
|
layout.MajorInterval) + Convert.ToDouble(layout.BaseValue));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetPointFromValue
|
|
|
|
/// <summary>
|
|
/// Gets the chart Point from the given axis data value.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
public override Point GetPointFromValue(object value)
|
|
{
|
|
return (new Point(0, GetDisplayValue(value)));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDisplayValue
|
|
|
|
internal override int GetDisplayValue(object axisValue)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
return (chartXy.GetDataPointY(this, axisValue));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EnsureVisible
|
|
|
|
/// <summary>
|
|
/// Ensures the given data value is visible and
|
|
/// optionally centered on screen.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
public override void EnsureVisible(object value, bool center)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
if (chartXy != null)
|
|
{
|
|
if (chartXy.ChartControl != null)
|
|
{
|
|
if (chartXy.ChartControl.LayoutValid == false)
|
|
chartXy.ChartControl.UpdateLayout();
|
|
|
|
Rectangle cbounds = chartXy.ContentBounds;
|
|
|
|
int y = GetDisplayValue(value);
|
|
|
|
if (center == true)
|
|
{
|
|
int n = cbounds.Y - (y - cbounds.Height / 2);
|
|
|
|
chartXy.VScrollOffset = n;
|
|
}
|
|
else
|
|
{
|
|
int n = cbounds.Y - chartXy.VScrollOffset + 20;
|
|
|
|
if (y < n)
|
|
{
|
|
chartXy.VScrollOffset += (n - y);
|
|
}
|
|
else
|
|
{
|
|
n = cbounds.Bottom - chartXy.VScrollOffset - 20;
|
|
|
|
if (y > n)
|
|
chartXy.VScrollOffset -= (y - n);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Copy/CopyTo
|
|
|
|
/// <summary>
|
|
/// Creates a copy of the axis.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override ChartVisualElement Copy()
|
|
{
|
|
ChartAxisY copy = new ChartAxisY();
|
|
|
|
CopyTo(copy);
|
|
|
|
return (copy);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies each axis property to the given "copy".
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
ChartAxisY c = copy as ChartAxisY;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyTo(c);
|
|
|
|
MajorGridLines.CopyTo(c.MajorGridLines);
|
|
MinorGridLines.CopyTo(c.MinorGridLines);
|
|
|
|
MajorTickmarks.CopyTo(c.MajorTickmarks);
|
|
MinorTickmarks.CopyTo(c.MinorTickmarks);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSerialData
|
|
|
|
internal override SerialElementCollection GetSerialData(string serialName)
|
|
{
|
|
SerialElementCollection sec = new SerialElementCollection();
|
|
|
|
if (serialName != null)
|
|
{
|
|
if (serialName.Equals("") == true)
|
|
serialName = "ChartAxisY";
|
|
|
|
sec.AddStartElement(serialName);
|
|
}
|
|
|
|
sec.AddElement(MajorGridLines.GetSerialData("MajorGridLines"));
|
|
sec.AddElement(MinorGridLines.GetSerialData("MinorGridLines"));
|
|
sec.AddElement(MajorTickmarks.GetSerialData("MajorTickmarks"));
|
|
sec.AddElement(MinorTickmarks.GetSerialData("MinorTickmarks"));
|
|
|
|
sec.AddElement(base.GetSerialData(null));
|
|
|
|
if (serialName != null)
|
|
sec.AddEndElement(serialName);
|
|
|
|
return (sec);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PutSerialData
|
|
|
|
#region ProcessCollection
|
|
|
|
internal override void ProcessCollection(SerialElement se)
|
|
{
|
|
SerialElementCollection sec = se.Sec;
|
|
|
|
switch (se.Name)
|
|
{
|
|
case "MajorGridLines":
|
|
sec.PutSerialData(MajorGridLines);
|
|
break;
|
|
|
|
case "MinorGridLines":
|
|
sec.PutSerialData(MinorGridLines);
|
|
break;
|
|
|
|
case "MajorTickmarks":
|
|
sec.PutSerialData(MajorTickmarks);
|
|
break;
|
|
|
|
case "MinorTickmarks":
|
|
sec.PutSerialData(MinorTickmarks);
|
|
break;
|
|
|
|
default:
|
|
base.ProcessCollection(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ChartAxis
|
|
|
|
[TypeConverter(typeof(BlankExpandableObjectConverter))]
|
|
abstract public class ChartAxis : ChartVisualElement
|
|
{
|
|
#region Private variables
|
|
|
|
private States _States;
|
|
|
|
private AxisOrientation _AxisOrientation = AxisOrientation.X;
|
|
private AxisAlignment _AxisAlignment = AxisAlignment.NotSet;
|
|
private SortDirection _QualitativeSortDirection = SortDirection.None;
|
|
|
|
private int _AxisMargins = -1;
|
|
private int _AxisNearMargin = -1;
|
|
private int _AxisFarMargin = -1;
|
|
|
|
private AxisStripeCollection _AxisStripes;
|
|
|
|
private object _MinValue = null;
|
|
private object _MaxValue = null;
|
|
|
|
private object _ActualMinValue;
|
|
private object _ActualMaxValue;
|
|
|
|
private double _GridSpacing;
|
|
private double _GridInterval;
|
|
private int _MinGridInterval = 10;
|
|
|
|
private AxisTitle _Title;
|
|
private ReferenceLineCollection _ReferenceLines;
|
|
|
|
private TickmarkLayout _TickmarkLayout;
|
|
private TickmarkLayout _LastTickmarkLayout;
|
|
|
|
private Rectangle _AxisBounds;
|
|
private Rectangle _AxisLineBounds;
|
|
|
|
private ChartAxisVisualStyle _ChartAxisVisualStyle;
|
|
private EffectiveStyle<ChartAxisVisualStyle> _EffectiveAxisStyle;
|
|
|
|
private CrosshairValueVisualStyle _CrosshairLabelVisualStyle;
|
|
private EffectiveStyle<CrosshairValueVisualStyle> _EffectiveCrosshairLabelStyle;
|
|
|
|
private List<object> _QualitativeValues;
|
|
private DateTimeUnits _DateTimeUnits = DateTimeUnits.Days;
|
|
private DateTimeUnits _DateTimeUnitsLimit = DateTimeUnits.Years;
|
|
private DateTimeUnits _ActualDateTimeUnits = DateTimeUnits.Days;
|
|
|
|
private ScaleType _ScaleType;
|
|
|
|
private AxisBar[] _AxisBars;
|
|
|
|
#endregion
|
|
|
|
#region Protected variables
|
|
|
|
protected MajorTickmarks _MajorTickmarks;
|
|
protected MinorTickmarks _MinorTickmarks;
|
|
|
|
protected ChartMajorGridLines _MajorGridLines;
|
|
protected ChartMinorGridLines _MinorGridLines;
|
|
|
|
#endregion
|
|
|
|
public ChartAxis(AxisOrientation orientation)
|
|
{
|
|
InitDefaultStates();
|
|
|
|
_AxisOrientation = orientation;
|
|
|
|
_EffectiveAxisStyle = new EffectiveStyle<ChartAxisVisualStyle>(this);
|
|
_EffectiveCrosshairLabelStyle = new EffectiveStyle<CrosshairValueVisualStyle>(this);
|
|
|
|
_AxisBars = new AxisBar[(int)AxisBarType.MaxBarCount];
|
|
|
|
for (int i = 0; i < _AxisBars.Length; i++)
|
|
_AxisBars[i] = new AxisBar();
|
|
}
|
|
|
|
#region InitDefaultStates
|
|
|
|
private void InitDefaultStates()
|
|
{
|
|
SetState(States.AutoCalcBarMargins, true);
|
|
SetState(States.SeriesRangeChanged, true);
|
|
SetState(States.UseAutoMinGridInterval, true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
#region ActualDateTimeUnits
|
|
|
|
/// <summary>
|
|
/// Gets the actual axis display units for DateTime data (as determined by
|
|
/// either the DateTimeUnits property or actual inspection of the associated data).
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public DateTimeUnits ActualDateTimeUnits
|
|
{
|
|
get { return (_ActualDateTimeUnits); }
|
|
internal set { _ActualDateTimeUnits = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ActualMaxValue
|
|
|
|
/// <summary>
|
|
/// Gets the actual, axis max data value (as determined by
|
|
/// either the MaxValue property or actual inspection of the associated data).
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public object ActualMaxValue
|
|
{
|
|
get { return (_ActualMaxValue); }
|
|
internal set { _ActualMaxValue = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ActualMinValue
|
|
|
|
/// <summary>
|
|
/// Gets the actual, axis min data value (as determined by
|
|
/// either the MinValue property or actual inspection of the associated data).
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public object ActualMinValue
|
|
{
|
|
get { return (_ActualMinValue); }
|
|
internal set { _ActualMinValue = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AutoCalcBarMargins
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether axis Bar Margins are calculated and used.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Appearance")]
|
|
[Description("Indicates whether axis Bar Margins are calculated and used.")]
|
|
public bool AutoCalcBarMargins
|
|
{
|
|
get { return (TestState(States.AutoCalcBarMargins)); }
|
|
|
|
set
|
|
{
|
|
if (value != AutoCalcBarMargins)
|
|
{
|
|
SetState(States.AutoCalcBarMargins, value);
|
|
|
|
OnPropertyChangedEx("AutoCalcBarMargins", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisAlignment
|
|
|
|
/// <summary>
|
|
/// Gets or sets the axis alignment.
|
|
/// </summary>
|
|
[DefaultValue(AxisAlignment.NotSet), Category("Layout")]
|
|
[Description("Indicates the axis alignment.")]
|
|
public AxisAlignment AxisAlignment
|
|
{
|
|
get { return (_AxisAlignment); }
|
|
|
|
set
|
|
{
|
|
if (value != _AxisAlignment)
|
|
{
|
|
_AxisAlignment = value;
|
|
|
|
OnPropertyChangedEx("AxisAlignment", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisFarMargin
|
|
|
|
///<summary>
|
|
/// Gets or sets the far/ending margin for the axis. When set ( >= 0 ), the
|
|
/// value overrides the general AxisMargins setting.
|
|
///</summary>
|
|
[DefaultValue(-1), Category("Layout")]
|
|
[Description("Indicates the far/ending margin for the axis. When set ( >= 0 ), the value overrides the general AxisMargins setting.")]
|
|
public int AxisFarMargin
|
|
{
|
|
get { return (_AxisFarMargin); }
|
|
|
|
set
|
|
{
|
|
if (value != _AxisFarMargin)
|
|
{
|
|
_AxisFarMargin = value;
|
|
|
|
OnPropertyChangedEx("AxisFarMargin", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisMargins
|
|
|
|
///<summary>
|
|
/// Gets or sets the near/beginning and far/ending pixel margins for the axis
|
|
/// (ignored when set to < 0).
|
|
///</summary>
|
|
[DefaultValue(-1), Category("Layout")]
|
|
[Description("Indicates the near/beginning and far/ending margins for the axis (ignored when set to < 0).")]
|
|
public int AxisMargins
|
|
{
|
|
get { return (_AxisMargins); }
|
|
|
|
set
|
|
{
|
|
if (value != _AxisMargins)
|
|
{
|
|
_AxisMargins = value;
|
|
|
|
OnPropertyChangedEx("AxisMargins", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisNearMargin
|
|
|
|
///<summary>
|
|
/// Gets or sets the near/beginning margin for the axis. When set ( >= 0 ), the
|
|
/// value overrides the general AxisMargins setting.
|
|
///</summary>
|
|
[DefaultValue(-1), Category("Layout")]
|
|
[Description("Indicates the near/beginning margin for the axis. When set ( >= 0 ), the value overrides the general AxisMargins setting.")]
|
|
public int AxisNearMargin
|
|
{
|
|
get { return (_AxisNearMargin); }
|
|
|
|
set
|
|
{
|
|
if (value != _AxisNearMargin)
|
|
{
|
|
_AxisNearMargin = value;
|
|
|
|
OnPropertyChangedEx("AxisNearMargin", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisOrientation
|
|
|
|
///<summary>
|
|
/// Gets the axis orientation (X/Y).
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public AxisOrientation AxisOrientation
|
|
{
|
|
get { return (_AxisOrientation); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisStripes
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the collection of AxisStripes associated with the axis.
|
|
/// </summary>
|
|
[Category("Appearance")]
|
|
[Description("Indicates the collection of AxisStripes associated with the axis.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public AxisStripeCollection AxisStripes
|
|
{
|
|
get
|
|
{
|
|
if (_AxisStripes == null)
|
|
{
|
|
_AxisStripes = new AxisStripeCollection();
|
|
|
|
_AxisStripes.CollectionChanged += AxisStripeCollectionChanged;
|
|
}
|
|
|
|
return (_AxisStripes);
|
|
}
|
|
|
|
internal set
|
|
{
|
|
if (_AxisStripes != null)
|
|
_AxisStripes.CollectionChanged -= AxisStripeCollectionChanged;
|
|
|
|
_AxisStripes = value;
|
|
|
|
if (_AxisStripes != null)
|
|
_AxisStripes.CollectionChanged += AxisStripeCollectionChanged;
|
|
}
|
|
}
|
|
|
|
#region AxisStripeCollectionChanged
|
|
|
|
void AxisStripeCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
switch (e.Action)
|
|
{
|
|
case NotifyCollectionChangedAction.Add:
|
|
foreach (ChartElement item in e.NewItems)
|
|
item.Parent = this;
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Replace:
|
|
foreach (ChartElement item in e.OldItems)
|
|
item.Parent = null;
|
|
|
|
foreach (ChartElement item in e.NewItems)
|
|
item.Parent = this;
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Remove:
|
|
foreach (ChartElement item in e.OldItems)
|
|
item.Parent = null;
|
|
break;
|
|
}
|
|
|
|
InvalidateLayout();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ChartAxisVisualStyle
|
|
|
|
/// <summary>
|
|
/// Gets or sets the visual style for the Axis.
|
|
/// </summary>
|
|
[Category("Style")]
|
|
[Description("Indicates the visual style for the Axis.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public ChartAxisVisualStyle ChartAxisVisualStyle
|
|
{
|
|
get
|
|
{
|
|
if (_ChartAxisVisualStyle == null)
|
|
{
|
|
_ChartAxisVisualStyle = new ChartAxisVisualStyle();
|
|
|
|
StyleVisualChangeHandler(null, _ChartAxisVisualStyle);
|
|
}
|
|
|
|
return (_ChartAxisVisualStyle);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_ChartAxisVisualStyle != value)
|
|
{
|
|
ChartAxisVisualStyle oldValue = _ChartAxisVisualStyle;
|
|
|
|
_ChartAxisVisualStyle = value;
|
|
|
|
OnStyleChanged("ChartAxisVisualStyle", oldValue, value);
|
|
|
|
if (oldValue != null)
|
|
oldValue.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CrosshairLabelVisualStyle
|
|
|
|
/// <summary>
|
|
/// Gets or sets the visual style to be used for Crosshair elements associated with the axis.
|
|
/// </summary>
|
|
[Category("Style")]
|
|
[Description("Indicates the visual style to be used for Crosshair elements associated with the axis.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public CrosshairValueVisualStyle CrosshairLabelVisualStyle
|
|
{
|
|
get
|
|
{
|
|
if (_CrosshairLabelVisualStyle == null)
|
|
{
|
|
_CrosshairLabelVisualStyle = new CrosshairValueVisualStyle();
|
|
|
|
StyleVisualChangeHandler(null, _CrosshairLabelVisualStyle);
|
|
}
|
|
|
|
return (_CrosshairLabelVisualStyle);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_CrosshairLabelVisualStyle != value)
|
|
{
|
|
CrosshairValueVisualStyle oldValue = _CrosshairLabelVisualStyle;
|
|
_CrosshairLabelVisualStyle = value;
|
|
|
|
OnStyleChanged("CrosshairLabelVisualStyle", oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DateTimeUnits
|
|
|
|
/// <summary>
|
|
/// Gets or sets the axis display units for DateTime data.
|
|
/// </summary>
|
|
[DefaultValue(DateTimeUnits.Days), Category("Data")]
|
|
[Description("Indicates the axis display units for DateTime data.")]
|
|
public DateTimeUnits DateTimeUnits
|
|
{
|
|
get { return (_DateTimeUnits); }
|
|
|
|
set
|
|
{
|
|
if (value != _DateTimeUnits)
|
|
{
|
|
_DateTimeUnits = value;
|
|
|
|
OnPropertyChangedEx("DateTimeUnits", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DateTimeUnitsLimit
|
|
|
|
/// <summary>
|
|
/// Gets or sets the limiting axis display units for DateTime data (the
|
|
/// max DateTime units the chart will, if needed, promote the display to).
|
|
/// </summary>
|
|
[DefaultValue(DateTimeUnits.Years), Category("Data")]
|
|
[Description("Indicates the limiting axis display units for DateTime data (the max DateTime units the chart will, if needed, promote the display to).")]
|
|
public DateTimeUnits DateTimeUnitsLimit
|
|
{
|
|
get { return (_DateTimeUnitsLimit); }
|
|
|
|
set
|
|
{
|
|
if (value != _DateTimeUnitsLimit)
|
|
{
|
|
_DateTimeUnitsLimit = value;
|
|
|
|
OnPropertyChangedEx("DateTimeUnitsLimit", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EffectiveAxisStyle
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the Axis' Effective (cached, composite) style.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public ChartAxisVisualStyle EffectiveAxisStyle
|
|
{
|
|
get { return (_EffectiveAxisStyle.Style); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EffectiveCrosshairLabelStyle
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the CrosshairLabel's Effective (cached, composite) style.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public CrosshairValueVisualStyle EffectiveCrosshairLabelStyle
|
|
{
|
|
get { return (_EffectiveCrosshairLabelStyle.Style); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GridInterval
|
|
|
|
///<summary>
|
|
/// Gets or sets the grid interval (the distance between MajorTickmarks, in pixels)
|
|
///</summary>
|
|
[Description("Indicates the grid interval (the distance between MajorTickmarks, in pixels).")]
|
|
[DefaultValue(0.0d), Category("Layout")]
|
|
public double GridInterval
|
|
{
|
|
get { return (_GridInterval); }
|
|
|
|
set
|
|
{
|
|
if (value != _GridInterval)
|
|
{
|
|
_GridInterval = value;
|
|
|
|
OnPropertyChangedEx("GridInterval", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GridSpacing
|
|
|
|
///<summary>
|
|
/// Gets or sets the numerical spacing between MajorTickmarks (such as 1, 10, 100, ...).
|
|
///</summary>
|
|
[Description("Indicates the numerical spacing between MajorTickmarks (such as 1, 10, 100, ...).")]
|
|
[DefaultValue(0.0d), Category("Layout")]
|
|
public double GridSpacing
|
|
{
|
|
get { return (_GridSpacing); }
|
|
|
|
set
|
|
{
|
|
if (value != _GridSpacing)
|
|
{
|
|
_GridSpacing = value;
|
|
|
|
OnPropertyChangedEx("GridSpacing", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsPrimaryAxis
|
|
|
|
/// <summary>
|
|
/// Gets whether the axis is the Primary axis.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public bool IsPrimaryAxis
|
|
{
|
|
get { return (TestState(States.PrimaryAxis)); }
|
|
internal set { SetState(States.PrimaryAxis, value); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MajorGridLines
|
|
|
|
///<summary>
|
|
/// Gets the axis MajorGridLines element.
|
|
///</summary>
|
|
[Description("Indicates the MajorGridLines element."), Category("Appearance")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public virtual ChartMajorGridLines MajorGridLines
|
|
{
|
|
get { return (_MajorGridLines); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MajorTickmarks
|
|
|
|
///<summary>
|
|
/// Gets the axis MajorTickmarks element.
|
|
///</summary>
|
|
[Description("Indicates the MajorTickmarks element."), Category("Appearance")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public virtual MajorTickmarks MajorTickmarks
|
|
{
|
|
get { return (_MajorTickmarks); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MaxValue
|
|
|
|
///<summary>
|
|
/// Gets or sets the maximum axis data value.
|
|
///</summary>
|
|
[DefaultValue(null), Category("Data")]
|
|
[Description("Indicates the maximum axis data value.")]
|
|
[TypeConverter("DevComponents.Charts.Design.PointValueConverter," +
|
|
"DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf")]
|
|
public object MaxValue
|
|
{
|
|
get { return (_MaxValue); }
|
|
|
|
set
|
|
{
|
|
if (value != _MaxValue)
|
|
{
|
|
_MaxValue = value;
|
|
|
|
OnPropertyChangedEx("MaxValue", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinorGridLines
|
|
|
|
///<summary>
|
|
/// Gets the axis MinorGridLines element.
|
|
///</summary>
|
|
[Description("Indicates the MinorGridLines element."), Category("Appearance")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public virtual ChartMinorGridLines MinorGridLines
|
|
{
|
|
get { return (_MinorGridLines); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinGridInterval
|
|
|
|
///<summary>
|
|
/// Gets or sets the minimum grid interval size. This is the distance (in pixels)
|
|
/// between tickmark layout items.
|
|
///</summary>
|
|
[DefaultValue(10), Category("Layout")]
|
|
[Description("Indicates the minimum grid interval size. This is the distance (in pixels) between tickmark layout items.")]
|
|
public int MinGridInterval
|
|
{
|
|
get { return (_MinGridInterval); }
|
|
|
|
set
|
|
{
|
|
if (value != _MinGridInterval)
|
|
{
|
|
_MinGridInterval = value;
|
|
|
|
OnPropertyChangedEx("MinGridInterval", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinorTickmarks
|
|
|
|
///<summary>
|
|
/// Gets the axis MinorTickmarks element.
|
|
///</summary>
|
|
[Description("Indicates the MinorTickmarks element."), Category("Appearance")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public virtual MinorTickmarks MinorTickmarks
|
|
{
|
|
get { return (_MinorTickmarks); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinValue
|
|
|
|
///<summary>
|
|
/// Gets or sets the minimum axis data value.
|
|
///</summary>
|
|
[DefaultValue(null), Category("Data")]
|
|
[Description("Indicates the minimum axis data value.")]
|
|
[TypeConverter("DevComponents.Charts.Design.PointValueConverter," +
|
|
"DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf")]
|
|
public object MinValue
|
|
{
|
|
get { return (_MinValue); }
|
|
|
|
set
|
|
{
|
|
if (value != _MinValue)
|
|
{
|
|
_MinValue = value;
|
|
|
|
OnPropertyChangedEx("MinValue", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region QualitativeSortDirection
|
|
|
|
///<summary>
|
|
/// Gets or sets the sort direction for Qualitative axis values.
|
|
///</summary>
|
|
[DefaultValue(SortDirection.None), Category("Data")]
|
|
[Description("Indicates the sort direction for Qualitative axis values.")]
|
|
public SortDirection QualitativeSortDirection
|
|
{
|
|
get { return (_QualitativeSortDirection); }
|
|
|
|
set
|
|
{
|
|
if (value != _QualitativeSortDirection)
|
|
{
|
|
_QualitativeSortDirection = value;
|
|
|
|
RefreshRangeValues();
|
|
|
|
OnPropertyChangedEx("QualitativeSortDirection", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ReferenceLines
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the collection of axis Reference Lines
|
|
/// </summary>
|
|
[Category("Appearance")]
|
|
[Description("Indicates the collection of axis Reference Lines.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public ReferenceLineCollection ReferenceLines
|
|
{
|
|
get
|
|
{
|
|
if (_ReferenceLines == null)
|
|
{
|
|
_ReferenceLines = new ReferenceLineCollection();
|
|
|
|
_ReferenceLines.CollectionChanged += ReferenceLineCollectionChanged;
|
|
}
|
|
|
|
return (_ReferenceLines);
|
|
}
|
|
|
|
internal set
|
|
{
|
|
if (_ReferenceLines != null)
|
|
_ReferenceLines.CollectionChanged -= ReferenceLineCollectionChanged;
|
|
|
|
_ReferenceLines = value;
|
|
|
|
if (_ReferenceLines != null)
|
|
_ReferenceLines.CollectionChanged += ReferenceLineCollectionChanged;
|
|
}
|
|
}
|
|
|
|
#region ReferenceLineCollectionChanged
|
|
|
|
void ReferenceLineCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
switch (e.Action)
|
|
{
|
|
case NotifyCollectionChangedAction.Add:
|
|
foreach (ChartElement item in e.NewItems)
|
|
item.Parent = this;
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Replace:
|
|
foreach (ChartElement item in e.OldItems)
|
|
item.Parent = null;
|
|
|
|
foreach (ChartElement item in e.NewItems)
|
|
item.Parent = this;
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Remove:
|
|
foreach (ChartElement item in e.OldItems)
|
|
item.Parent = null;
|
|
break;
|
|
}
|
|
|
|
InvalidateRender();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Title
|
|
|
|
///<summary>
|
|
/// Gets or sets the Axis Title.
|
|
///</summary>
|
|
[Category("Layout")]
|
|
[Description("Indicates the Axis Title.")]
|
|
[TypeConverter(typeof(BlankExpandableObjectConverter))]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public AxisTitle Title
|
|
{
|
|
get
|
|
{
|
|
if (_Title == null)
|
|
{
|
|
_Title = new AxisTitle();
|
|
_Title.Parent = this;
|
|
}
|
|
|
|
return (_Title);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != _Title)
|
|
{
|
|
_Title = value;
|
|
_Title.Parent = (value != null) ? this : null;
|
|
|
|
OnPropertyChangedEx("Title", Style.VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UseAlternateBackground
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether the axis utilizes the alternate background color.
|
|
/// </summary>
|
|
[DefaultValue(false), Category("Appearance")]
|
|
[Description("Indicates whether the axis utilizes the alternate background color.")]
|
|
public bool UseAlternateBackground
|
|
{
|
|
get { return (TestState(States.UseAlternateBackground)); }
|
|
|
|
set
|
|
{
|
|
if (value != UseAlternateBackground)
|
|
{
|
|
SetState(States.UseAlternateBackground, value);
|
|
|
|
OnPropertyChangedEx("UseAlternateBackground", VisualChangeType.Render);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UseAutoMinGridInterval
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether the auto-calculated minimum grid interval
|
|
/// will be used in determining the axis major tickmark interval.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Appearance")]
|
|
[Description("Indicates whether the auto-calculated minimum grid interval will be used in determining the axis major tickmark interval.")]
|
|
public bool UseAutoMinGridInterval
|
|
{
|
|
get { return (TestState(States.UseAutoMinGridInterval)); }
|
|
|
|
set
|
|
{
|
|
if (value != UseAutoMinGridInterval)
|
|
{
|
|
SetState(States.UseAutoMinGridInterval, value);
|
|
|
|
OnPropertyChangedEx("UseAutoMinGridInterval", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Internal properties
|
|
|
|
#region AxisBars
|
|
|
|
internal AxisBar[] AxisBars
|
|
{
|
|
get { return (_AxisBars); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisBounds
|
|
|
|
internal Rectangle AxisBounds
|
|
{
|
|
get { return (_AxisBounds); }
|
|
set { _AxisBounds = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisLineBounds
|
|
|
|
internal Rectangle AxisLineBounds
|
|
{
|
|
get { return (_AxisLineBounds); }
|
|
set { _AxisLineBounds = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DotPlotAxis
|
|
|
|
internal bool DotPlotAxis
|
|
{
|
|
get { return (TestState(States.DotPlotAxis)); }
|
|
set { SetState(States.DotPlotAxis, value); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EdgeAxis
|
|
|
|
internal bool EdgeAxis
|
|
{
|
|
get { return (TestState(States.EdgeAxis)); }
|
|
set { SetState(States.EdgeAxis, value); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LastTickmarkLayout
|
|
|
|
internal TickmarkLayout LastTickmarkLayout
|
|
{
|
|
get { return (_LastTickmarkLayout); }
|
|
set { _LastTickmarkLayout = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region QualitativeValues
|
|
|
|
internal List<object> QualitativeValues
|
|
{
|
|
get
|
|
{
|
|
if (_QualitativeValues == null)
|
|
_QualitativeValues = new List<object>();
|
|
|
|
return (_QualitativeValues);
|
|
}
|
|
|
|
set { _QualitativeValues = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ScaleType
|
|
|
|
internal ScaleType ScaleType
|
|
{
|
|
get { return (_ScaleType); }
|
|
set { _ScaleType = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SeriesRangeChanged
|
|
|
|
internal bool SeriesRangeChanged
|
|
{
|
|
get { return (TestState(States.SeriesRangeChanged)); }
|
|
set { SetState(States.SeriesRangeChanged, value); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TickmarkLayout
|
|
|
|
internal TickmarkLayout TickmarkLayout
|
|
{
|
|
get { return(_TickmarkLayout); }
|
|
set { _TickmarkLayout = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
MeasureReferenceLines(layoutInfo);
|
|
}
|
|
|
|
protected void MeasureReferenceLines(ChartLayoutInfo layoutInfo)
|
|
{
|
|
Rectangle layoutBounds = layoutInfo.LayoutBounds;
|
|
|
|
foreach (ReferenceLine line in ReferenceLines)
|
|
{
|
|
layoutInfo.LayoutBounds = BoundsRelative;
|
|
|
|
line.Measure(layoutInfo);
|
|
}
|
|
|
|
layoutInfo.LayoutBounds = layoutBounds;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ArrangeOverride
|
|
|
|
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
if (Title.Visible == true)
|
|
Title.Arrange(layoutInfo);
|
|
|
|
MajorTickmarks.Arrange(layoutInfo);
|
|
MinorTickmarks.Arrange(layoutInfo);
|
|
|
|
MajorGridLines.TickmarkLayout = TickmarkLayout;
|
|
MinorGridLines.TickmarkLayout = TickmarkLayout;
|
|
|
|
MajorGridLines.Arrange(layoutInfo);
|
|
MinorGridLines.Arrange(layoutInfo);
|
|
|
|
ArrangeReferenceLines(layoutInfo);
|
|
}
|
|
|
|
#region ArrangeReferenceLines
|
|
|
|
private void ArrangeReferenceLines(ChartLayoutInfo layoutInfo)
|
|
{
|
|
Rectangle layoutBounds = layoutInfo.LayoutBounds;
|
|
|
|
foreach (ReferenceLine line in ReferenceLines)
|
|
{
|
|
layoutInfo.LayoutBounds = BoundsRelative;
|
|
|
|
line.Arrange(layoutInfo);
|
|
}
|
|
|
|
layoutInfo.LayoutBounds = layoutBounds;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
ChartAxisVisualStyle astyle = EffectiveAxisStyle;
|
|
|
|
if (Title.Visible == true)
|
|
Title.Render(renderInfo);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Render
|
|
|
|
internal override void Render(ChartRenderInfo renderInfo)
|
|
{
|
|
if (Displayed == true)
|
|
{
|
|
Rectangle bounds = GetScrollBounds(AxisBounds);
|
|
|
|
if (renderInfo.ClipRectangle.IntersectsWith(bounds))
|
|
RenderOverride(renderInfo);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderCrosshairLabel
|
|
|
|
internal virtual void RenderCrosshairLabel(Graphics g, Point pt)
|
|
{
|
|
}
|
|
|
|
internal virtual void RenderCrosshairLabel(Graphics g, CrosshairPoint cp)
|
|
{
|
|
}
|
|
|
|
#region GetCrosshairLabel
|
|
|
|
internal string GetCrosshairLabel(object value, CrosshairValueVisualStyle lstyle)
|
|
{
|
|
string label = "";
|
|
|
|
if (value != null)
|
|
{
|
|
TickmarkLabelVisualStyle tstyle = MajorTickmarks.EffectiveLabelStyle;
|
|
|
|
try
|
|
{
|
|
switch (ScaleType)
|
|
{
|
|
case ScaleType.DateTime:
|
|
DateTime dtvalue = (DateTime)value;
|
|
|
|
if (string.IsNullOrEmpty(lstyle.TextFormat) == false)
|
|
label = dtvalue.ToString(lstyle.TextFormat);
|
|
|
|
else if (string.IsNullOrEmpty(tstyle.TextFormat) == false)
|
|
label = dtvalue.ToString(tstyle.TextFormat);
|
|
else
|
|
label = GetDateTimeLabel(dtvalue);
|
|
break;
|
|
|
|
case ScaleType.Qualitative:
|
|
if (string.IsNullOrEmpty(lstyle.TextFormat) == false)
|
|
label = string.Format(lstyle.TextFormat, value);
|
|
|
|
else if (string.IsNullOrEmpty(tstyle.TextFormat) == false)
|
|
label = string.Format(tstyle.TextFormat, value);
|
|
else
|
|
label = value.ToString();
|
|
break;
|
|
|
|
default:
|
|
double d = Convert.ToDouble(value);
|
|
|
|
if (string.IsNullOrEmpty(lstyle.TextFormat) == false)
|
|
label = d.ToString(lstyle.TextFormat);
|
|
|
|
else if (string.IsNullOrEmpty(tstyle.TextFormat) == false)
|
|
label = d.ToString(tstyle.TextFormat);
|
|
|
|
else if (value is int)
|
|
label = ((int)value).ToString();
|
|
|
|
else
|
|
label = d.ToString("F6");
|
|
|
|
break;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
ChartControl chartControl = ChartControl;
|
|
|
|
if (chartControl != null)
|
|
chartControl.DoGetCrosshairAxisLabelEvent(this, value, ref label);
|
|
|
|
return (label);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderBackground
|
|
|
|
internal virtual void RenderBackground(
|
|
ChartRenderInfo renderInfo, Rectangle scContentBounds)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderStripes
|
|
|
|
internal virtual void RenderStripes(
|
|
ChartRenderInfo renderInfo, Rectangle scContentBounds)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderStripe
|
|
|
|
protected void RenderStripe(
|
|
Graphics g, Rectangle bounds, AxisStripe stripe)
|
|
{
|
|
if (bounds.Width > 0 && bounds.Height > 0)
|
|
{
|
|
AxisStripeVisualStyle astyle = stripe.AxisStripeVisualStyle;
|
|
|
|
if (astyle.Background.IsEmpty == true)
|
|
{
|
|
g.FillRectangle(Brushes.LightPink, bounds);
|
|
}
|
|
else
|
|
{
|
|
using (Brush br = astyle.Background.GetBrush(bounds))
|
|
g.FillRectangle(br, bounds);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalcMajorSpacing
|
|
|
|
protected void CalcMajorSpacing(ChartLayoutInfo layoutInfo, int width)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
if (chartXy.DropShadowDisplayed == true)
|
|
width -= 3;
|
|
|
|
if (AxisOrientation == AxisOrientation.X)
|
|
{
|
|
if (chartXy.VScrollBar.Visible == true)
|
|
width -= chartXy.VScrollBar.Width;
|
|
}
|
|
else
|
|
{
|
|
if (chartXy.HScrollBar.Visible == true)
|
|
width -= chartXy.HScrollBar.Height;
|
|
}
|
|
|
|
TickmarkLayout layout = new TickmarkLayout();
|
|
|
|
layout.MinValue = GetMinValue();
|
|
layout.MaxValue = GetMaxValue();
|
|
|
|
if (layout.MinValue != null && layout.MaxValue != null)
|
|
{
|
|
ScaleType scaleType = ScaleType;
|
|
|
|
if (ScaleType == ScaleType.NotSet)
|
|
ScaleType = SeriesPoint.GetScaleType(layout.MinValue.GetType());
|
|
|
|
layout.MinorCount = MinorTickmarks.TickmarkCount;
|
|
|
|
if (ScaleType != ScaleType.NotSet)
|
|
{
|
|
switch (ScaleType)
|
|
{
|
|
case ScaleType.DateTime:
|
|
CalcMajorDateTimeSpacing(chartXy, layout, width);
|
|
break;
|
|
|
|
case ScaleType.Qualitative:
|
|
CalcMajorQualitativeSpacing(layout, width);
|
|
break;
|
|
|
|
default:
|
|
CalcMajorQuantitativeSpacing(chartXy, layout, width);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (AxisOrientation == AxisOrientation.Y)
|
|
{
|
|
if (chartXy.HScrollBar.Visible == true)
|
|
layout.MarginOffset -= chartXy.HScrollBarHeight;
|
|
}
|
|
}
|
|
|
|
TickmarkLayout = layout;
|
|
}
|
|
|
|
#region CalcMajorDateTimeSpacing
|
|
|
|
private void CalcMajorDateTimeSpacing(
|
|
ChartXy chartXy, TickmarkLayout layout, int width)
|
|
{
|
|
DateTime dtMinValue = (DateTime)layout.MinValue;
|
|
DateTime dtMaxValue = (DateTime)layout.MaxValue;
|
|
|
|
DateTime odtMinValue = dtMinValue;
|
|
|
|
if (width > 0 && dtMinValue < dtMaxValue)
|
|
{
|
|
DateTime ominValue = dtMinValue;
|
|
|
|
width = SetLayoutMargin(layout, width) - 2;
|
|
|
|
CalcDateTimeSpacing(chartXy, layout, dtMinValue, dtMaxValue, width);
|
|
|
|
if (AutoCalcBarMargins == true)
|
|
{
|
|
ChartSeries barSeries = GetBarSeries(chartXy);
|
|
|
|
if (barSeries != null)
|
|
{
|
|
if ((barSeries.IsRotated == false && AxisOrientation == AxisOrientation.X) ||
|
|
(barSeries.IsRotated == true && AxisOrientation == AxisOrientation.Y))
|
|
{
|
|
int n = (int)(width / layout.MajorCount / 2 / layout.MajorSpacing);
|
|
|
|
layout.NearMargin += n;
|
|
layout.FarMargin += n;
|
|
|
|
width -= (n * 2);
|
|
|
|
layout.MajorInterval = (double)width / layout.MajorCount;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
layout.MajorInterval = (double)width / layout.MajorCount;
|
|
}
|
|
|
|
if (UseAutoMinGridInterval == true)
|
|
{
|
|
if (layout.MajorInterval <= 3)
|
|
layout.MajorInterval = 3;
|
|
}
|
|
|
|
dtMinValue = AdjustDateTimeBase(layout, dtMinValue);
|
|
|
|
UpdateDateTimeMargins(layout, ref dtMinValue, ref dtMaxValue);
|
|
|
|
double offset = GetDateTimeRange(ActualDateTimeUnits, dtMinValue, ominValue);
|
|
|
|
int moff = (int)((layout.MajorInterval * offset) / layout.MajorSpacing - layout.NearMargin - 1);
|
|
|
|
layout.MarginOffset = moff;
|
|
|
|
layout.MinValue = dtMinValue;
|
|
layout.MaxValue = dtMaxValue;
|
|
}
|
|
}
|
|
|
|
#region AdjustDateTimeBase
|
|
|
|
private DateTime AdjustDateTimeBase(TickmarkLayout layout, DateTime dtValue)
|
|
{
|
|
switch (ActualDateTimeUnits)
|
|
{
|
|
case DateTimeUnits.Milliseconds:
|
|
dtValue = dtValue.AddMilliseconds(-dtValue.Millisecond % layout.GridSpacing);
|
|
break;
|
|
|
|
case DateTimeUnits.Seconds:
|
|
dtValue = new DateTime(dtValue.Year, dtValue.Month, dtValue.Day, dtValue.Hour, dtValue.Minute, dtValue.Second);
|
|
dtValue = dtValue.AddSeconds(-dtValue.Second % layout.GridSpacing);
|
|
break;
|
|
|
|
case DateTimeUnits.Minutes:
|
|
dtValue = new DateTime(dtValue.Year, dtValue.Month, dtValue.Day, dtValue.Hour, dtValue.Minute, 0);
|
|
dtValue = dtValue.AddMinutes(-dtValue.Minute % layout.GridSpacing);
|
|
break;
|
|
|
|
case DateTimeUnits.Hours:
|
|
dtValue = new DateTime(dtValue.Year, dtValue.Month, dtValue.Day, dtValue.Hour, 0, 0);
|
|
dtValue = dtValue.AddHours(-dtValue.Hour % layout.GridSpacing);
|
|
break;
|
|
|
|
case DateTimeUnits.Days:
|
|
dtValue = new DateTime(dtValue.Year, dtValue.Month, dtValue.Day);
|
|
dtValue = dtValue.AddDays(-dtValue.Day % layout.GridSpacing);
|
|
break;
|
|
|
|
case DateTimeUnits.Months:
|
|
dtValue = new DateTime(dtValue.Year, dtValue.Month, 1);
|
|
dtValue = dtValue.AddMonths(-(int)(dtValue.Month % layout.GridSpacing));
|
|
break;
|
|
|
|
case DateTimeUnits.Years:
|
|
dtValue = new DateTime(dtValue.Year, 1, 1);
|
|
dtValue = dtValue.AddYears(-(int)(dtValue.Year % layout.GridSpacing));
|
|
break;
|
|
|
|
default:
|
|
dtValue = dtValue.AddTicks(-(long)(dtValue.Millisecond % layout.GridSpacing));
|
|
break;
|
|
}
|
|
|
|
return (dtValue);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalcDateTimeSpacing
|
|
|
|
private void CalcDateTimeSpacing(ChartXy chartXy,
|
|
TickmarkLayout layout, DateTime dtMinValue, DateTime dtMaxValue, int width)
|
|
{
|
|
DateTimeUnits adtu = DateTimeUnits;
|
|
|
|
double range = GetDateTimeRange(adtu, dtMinValue, dtMaxValue);
|
|
|
|
if (GridSpacing <= 0)
|
|
{
|
|
layout.GridSpacing = 1;
|
|
layout.MajorSpacing = layout.GridSpacing;
|
|
}
|
|
else
|
|
{
|
|
layout.GridSpacing = GridSpacing;
|
|
layout.MajorSpacing = layout.GridSpacing;
|
|
}
|
|
|
|
CalcDateTimeInterval(layout, range, width);
|
|
|
|
double minorInterval = layout.MajorInterval / (MinorTickmarks.TickmarkCount + 1);
|
|
|
|
if (minorInterval > 0)
|
|
{
|
|
ChartSeries barSeries = GetBarSeries(chartXy);
|
|
|
|
while (minorInterval < MinGridInterval)
|
|
{
|
|
if ((barSeries == null) && (int)adtu < (int)DateTimeUnitsLimit)
|
|
{
|
|
adtu = GetNextDateTimeUnit(adtu, dtMinValue, dtMaxValue);
|
|
range = GetDateTimeRange(adtu, dtMinValue, dtMaxValue);
|
|
|
|
CalcDateTimeInterval(layout, range, width);
|
|
|
|
minorInterval = layout.MajorInterval / (MinorTickmarks.TickmarkCount + 1);
|
|
}
|
|
else
|
|
{
|
|
if (GridSpacing > 0)
|
|
break;
|
|
|
|
minorInterval *= 2;
|
|
layout.MajorSpacing *= 2;
|
|
}
|
|
}
|
|
|
|
ActualDateTimeUnits = adtu;
|
|
|
|
CalcDateTimeInterval(layout, range, width);
|
|
}
|
|
}
|
|
|
|
#region CalcDateTimeInterval
|
|
|
|
private void CalcDateTimeInterval(TickmarkLayout layout, double range, int width)
|
|
{
|
|
double d = range / layout.MajorSpacing;
|
|
|
|
layout.MajorCount = (int)Math.Ceiling(d);
|
|
layout.MajorInterval = (double)width / d;
|
|
|
|
if (layout.MajorCount <= 0)
|
|
layout.MajorCount = 1;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetNextDateTimeUnit
|
|
|
|
private DateTimeUnits GetNextDateTimeUnit(
|
|
DateTimeUnits adtu, DateTime dtMinValue, DateTime dtMaxValue)
|
|
{
|
|
switch (adtu)
|
|
{
|
|
case DateTimeUnits.Ticks:
|
|
return (DateTimeUnits.Milliseconds);
|
|
|
|
case DateTimeUnits.Milliseconds:
|
|
return (DateTimeUnits.Seconds);
|
|
|
|
case DateTimeUnits.Seconds:
|
|
return (DateTimeUnits.Minutes);
|
|
|
|
case DateTimeUnits.Minutes:
|
|
return (DateTimeUnits.Hours);
|
|
|
|
case DateTimeUnits.Hours:
|
|
return (DateTimeUnits.Days);
|
|
|
|
case DateTimeUnits.Days:
|
|
return (DateTimeUnits.Months);
|
|
|
|
default:
|
|
return (DateTimeUnits.Years);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region AddDateTimeOffset
|
|
|
|
private DateTime AddDateTimeOffset(DateTime dtValue, int offset)
|
|
{
|
|
switch (ActualDateTimeUnits)
|
|
{
|
|
case DateTimeUnits.Milliseconds:
|
|
dtValue = dtValue.AddMilliseconds(offset);
|
|
break;
|
|
|
|
case DateTimeUnits.Seconds:
|
|
dtValue = dtValue.AddSeconds(offset);
|
|
break;
|
|
|
|
case DateTimeUnits.Minutes:
|
|
dtValue = dtValue.AddMinutes(offset);
|
|
break;
|
|
|
|
case DateTimeUnits.Hours:
|
|
dtValue = dtValue.AddHours(offset);
|
|
break;
|
|
|
|
case DateTimeUnits.Days:
|
|
dtValue = dtValue.AddDays(offset);
|
|
break;
|
|
|
|
case DateTimeUnits.Months:
|
|
dtValue = dtValue.AddMonths(offset);
|
|
break;
|
|
|
|
case DateTimeUnits.Years:
|
|
dtValue = dtValue.AddYears(offset);
|
|
break;
|
|
|
|
default:
|
|
dtValue = dtValue.AddTicks(offset);
|
|
break;
|
|
}
|
|
|
|
return (dtValue);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateDateTimeMargins
|
|
|
|
private void UpdateDateTimeMargins(
|
|
TickmarkLayout layout, ref DateTime dtMinValue, ref DateTime dtMaxValue)
|
|
{
|
|
if (layout.NearMargin > 0)
|
|
{
|
|
int marginCount = (int)Math.Ceiling(layout.NearMargin / layout.MajorInterval);
|
|
|
|
layout.MajorCount += marginCount;
|
|
|
|
dtMinValue = AddDateTimeOffset(dtMinValue, -(int)(marginCount * 1)); //layout.MajorSpacing));
|
|
}
|
|
|
|
if (layout.FarMargin > 0)
|
|
{
|
|
int marginCount = (int)Math.Ceiling(layout.FarMargin / layout.MajorInterval);
|
|
|
|
layout.MajorCount += marginCount;
|
|
|
|
dtMaxValue = AddDateTimeOffset(dtMaxValue, (int)(marginCount * 1)); //layout.MajorSpacing));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDateTimeRange
|
|
|
|
private double GetDateTimeRange(
|
|
DateTimeUnits dtu, DateTime dtMinValue, DateTime dtMaxValue)
|
|
{
|
|
TimeSpan ts = dtMaxValue - dtMinValue;
|
|
|
|
switch (dtu)
|
|
{
|
|
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 (CalcDateTimeMonths(dtMinValue, dtMaxValue));
|
|
|
|
case DateTimeUnits.Years:
|
|
return (CalcDateTimeYears(dtMinValue, dtMaxValue));
|
|
|
|
default:
|
|
return (dtMaxValue.Ticks - dtMinValue.Ticks);
|
|
}
|
|
}
|
|
|
|
#region CalcDateTimeYears
|
|
|
|
internal double CalcDateTimeYears(DateTime dtMinValue, DateTime dtMaxValue)
|
|
{
|
|
int years = dtMaxValue.Year - dtMinValue.Year;
|
|
|
|
DateTime last = dtMinValue.AddYears(years);
|
|
|
|
if (last > dtMaxValue)
|
|
{
|
|
last = last.AddYears(-1);
|
|
years--;
|
|
}
|
|
|
|
DateTime next = last.AddYears(1);
|
|
|
|
double yearDays = (next - last).Days;
|
|
double days = (dtMaxValue - last).Days;
|
|
|
|
return ((double)years + (days / yearDays));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalcDateTimeMonths
|
|
|
|
internal double CalcDateTimeMonths(DateTime dtMinValue, DateTime dtMaxValue)
|
|
{
|
|
// Rough estimation...
|
|
|
|
TimeSpan ts = dtMaxValue - dtMinValue;
|
|
|
|
return ((double)ts.Days / 30);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region CalcMajorQuantitativeSpacing
|
|
|
|
private void CalcMajorQuantitativeSpacing(
|
|
ChartXy chartXy, TickmarkLayout layout, int width)
|
|
{
|
|
Type otype = layout.MinValue.GetType();
|
|
|
|
double dminValue = Convert.ToDouble(layout.MinValue);
|
|
double dmaxValue = Convert.ToDouble(layout.MaxValue);
|
|
|
|
if (AutoCalcBarMargins == true)
|
|
{
|
|
ChartSeries barSeries = GetFullBarSeries(chartXy);
|
|
|
|
if (barSeries != null)
|
|
{
|
|
if (barSeries.IsRotated == true && AxisOrientation == AxisOrientation.X ||
|
|
barSeries.IsRotated == false && AxisOrientation == AxisOrientation.Y)
|
|
{
|
|
double origin = Convert.ToDouble((chartXy.BarOrigin ?? 0));
|
|
|
|
dminValue = Math.Min(origin, dminValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
double ominValue = dminValue;
|
|
|
|
if (dminValue == dmaxValue)
|
|
dmaxValue++;
|
|
|
|
if (width > 0 && dminValue <= dmaxValue)
|
|
{
|
|
width = SetLayoutMargin(layout, width);
|
|
|
|
double range = Math.Abs(dmaxValue - dminValue);
|
|
|
|
CalcQuantitativeSpacing(chartXy, layout, range, width);
|
|
|
|
if (UseAutoMinGridInterval == true)
|
|
{
|
|
if (layout.MajorInterval < 3)
|
|
layout.MajorInterval = 3;
|
|
}
|
|
|
|
UpdateQuantitativeMargins(layout, otype, ref dminValue, ref dmaxValue);
|
|
|
|
// Make sure zero is included on the axis
|
|
|
|
int n = dminValue < 0 ? -1 : 1;
|
|
|
|
if (dminValue < 0)
|
|
dminValue -= ((dminValue % layout.MajorSpacing) + layout.MajorSpacing);
|
|
|
|
else if (dminValue > 0)
|
|
dminValue -= (dminValue % layout.MajorSpacing);
|
|
|
|
int moff = 0;
|
|
|
|
double delta = Math.Floor(Math.Abs(dminValue) / layout.MajorSpacing);
|
|
double value = (int)delta * layout.MajorSpacing * n;
|
|
double offset = Math.Abs(value - ominValue);
|
|
|
|
moff = (int)((layout.MajorInterval * offset) / layout.MajorSpacing - layout.NearMargin);
|
|
|
|
layout.MarginOffset = moff;
|
|
|
|
layout.MinValue = Convert.ChangeType(dminValue, otype);
|
|
layout.MaxValue = Convert.ChangeType(dmaxValue, otype);
|
|
}
|
|
}
|
|
|
|
#region CalcQuantitativeSpacing
|
|
|
|
void CalcQuantitativeSpacing(
|
|
ChartXy chartXy, TickmarkLayout layout, double range, int width)
|
|
{
|
|
if (GridSpacing <= 0)
|
|
{
|
|
// User has not specified a spacing, so calculate it for them based
|
|
// upon powers of 10 (10, 100, 1000, etc)
|
|
//
|
|
// MajorSpacing is set to a multiple of the GridSpacing (based upon
|
|
// the calculated minor tickmark interval)
|
|
|
|
layout.GridSpacing = Math.Pow(10, Math.Floor(Math.Log10(range / 10)));
|
|
|
|
if (layout.GridSpacing < 1)
|
|
layout.GridSpacing = 1;
|
|
|
|
if (layout.MinValue is int)
|
|
layout.GridSpacing = Math.Ceiling(layout.GridSpacing);
|
|
|
|
layout.MajorSpacing = layout.GridSpacing;
|
|
|
|
layout.MajorCount = (int)Math.Ceiling(range / layout.MajorSpacing);
|
|
layout.MajorInterval = (double)width / layout.MajorCount;
|
|
}
|
|
else
|
|
{
|
|
layout.GridSpacing = GridSpacing;
|
|
layout.MajorSpacing = layout.GridSpacing;
|
|
|
|
layout.MajorCount = (int)Math.Ceiling(range / layout.MajorSpacing);
|
|
layout.MajorInterval = (double)width / layout.MajorCount;
|
|
}
|
|
|
|
double gridInterval = GridInterval;
|
|
double pxp = (range < 1) ? width : ((double)width / range);
|
|
|
|
ChartSeries dpSeries = GetChartDotPlotSeries(chartXy);
|
|
|
|
if (dpSeries != null)
|
|
{
|
|
// Calculate the default dot plot spacing
|
|
|
|
gridInterval = CalcDotPlotSpacing(
|
|
chartXy, layout, range, ref width, dpSeries);
|
|
|
|
double count = range / layout.MajorSpacing;
|
|
|
|
layout.MajorCount = (int)Math.Ceiling(count);
|
|
|
|
pxp = (double)width / range;
|
|
|
|
DotPlotAxis = true;
|
|
}
|
|
else
|
|
{
|
|
ChartSeries barSeries = GetBarSeries(chartXy);
|
|
|
|
if (barSeries != null)
|
|
{
|
|
if ((barSeries.IsRotated == false && AxisOrientation == AxisOrientation.X) ||
|
|
(barSeries.IsRotated == true && AxisOrientation == AxisOrientation.Y))
|
|
{
|
|
int n = (int)(pxp / 2) + 1;
|
|
|
|
layout.NearMargin += n;
|
|
layout.FarMargin += n;
|
|
|
|
width -= (n * 2);
|
|
|
|
layout.MajorInterval = (double)width / layout.MajorCount;
|
|
|
|
pxp = (double)width / (range);
|
|
}
|
|
}
|
|
|
|
double minorInterval = layout.MajorInterval / (MinorTickmarks.TickmarkCount + 1);
|
|
|
|
if (minorInterval > 0)
|
|
{
|
|
while (minorInterval < MinGridInterval)
|
|
{
|
|
minorInterval *= 2;
|
|
layout.MajorSpacing *= 2;
|
|
}
|
|
}
|
|
|
|
gridInterval = layout.MajorInterval;
|
|
|
|
double dminValue = Convert.ToDouble(layout.MinValue);
|
|
double dmaxValue = Convert.ToDouble(layout.MaxValue);
|
|
|
|
double maxp = (int)(dmaxValue / layout.MajorSpacing) * layout.MajorSpacing;
|
|
|
|
if (maxp < dmaxValue)
|
|
maxp += layout.MajorSpacing;
|
|
|
|
double minp = (int)(dminValue / layout.MajorSpacing) * layout.MajorSpacing;
|
|
|
|
if (minp > dminValue)
|
|
minp -= layout.MajorSpacing;
|
|
|
|
layout.MajorCount = (int)Math.Ceiling((maxp - minp) / layout.MajorSpacing);
|
|
|
|
layout.MinValue = minp;
|
|
layout.MaxValue = maxp;
|
|
|
|
DotPlotAxis = false;
|
|
}
|
|
|
|
if (GridInterval > 0)
|
|
{
|
|
layout.MajorInterval = GridInterval;
|
|
}
|
|
else
|
|
{
|
|
if (AxisCanExpand(dpSeries) == true)
|
|
gridInterval = Math.Max(gridInterval, pxp * layout.MajorSpacing);
|
|
|
|
layout.MajorInterval = Math.Max(gridInterval, 1);
|
|
}
|
|
}
|
|
|
|
#region GetChartDotPlotSeries
|
|
|
|
private ChartSeries GetChartDotPlotSeries(ChartXy chartXy)
|
|
{
|
|
foreach (ChartSeries series in chartXy.ChartSeries)
|
|
{
|
|
if ((series.SeriesType == SeriesType.VerticalDot) ||
|
|
(series.SeriesType == SeriesType.HorizontalDot))
|
|
{
|
|
return (series);
|
|
}
|
|
}
|
|
|
|
return (null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalcDotPlotSpacing
|
|
|
|
private double CalcDotPlotSpacing(ChartXy chartXy,
|
|
TickmarkLayout layout, double range, ref int width, ChartSeries dpSeries)
|
|
{
|
|
// If we previously added a default margin, back it back out
|
|
// since we are going to adjust the margin based upon the orientation
|
|
// and size of the marker
|
|
|
|
if (AxisMargins < 0)
|
|
{
|
|
width += ((layout.NearMargin * 2) - Dpi.Width10);
|
|
layout.NearMargin = Dpi.Width5;
|
|
}
|
|
|
|
Size dotSize = chartXy.GetMaxDotPlotMarkerSize();
|
|
DotPlotType dotTypes = chartXy.GetDotPlotTypes();
|
|
|
|
return (AxisOrientation == AxisOrientation.X)
|
|
? CalcXDotPlotSpacing(chartXy, layout, range, ref width, dpSeries, dotTypes, dotSize)
|
|
: CalcYDotPlotSpacing(chartXy, layout, range, ref width, dpSeries, dotTypes, dotSize);
|
|
}
|
|
|
|
#region CalcXDotPlotSpacing
|
|
|
|
private double CalcXDotPlotSpacing(ChartXy chartXy, TickmarkLayout layout,
|
|
double range, ref int width, ChartSeries dpSeries, DotPlotType dotTypes, Size dotSize)
|
|
{
|
|
if ((dotTypes & DotPlotType.Vertical) == DotPlotType.Vertical)
|
|
{
|
|
int n = dotSize.Width / 2;
|
|
|
|
layout.NearMargin += n;
|
|
width -= (n * 2);
|
|
}
|
|
|
|
layout.MajorSpacing = (GridSpacing <= 0) ? 1 : GridSpacing;
|
|
|
|
double gridInterval = Math.Max(layout.MajorSpacing, 1) * dotSize.Width;
|
|
|
|
if (MinGridInterval > 0)
|
|
{
|
|
while (gridInterval < Dpi.Width(MinGridInterval))
|
|
{
|
|
gridInterval *= 2;
|
|
layout.MajorSpacing *= 2;
|
|
}
|
|
}
|
|
|
|
Size size = chartXy.MinQualitativeSize;
|
|
|
|
double count = range;
|
|
|
|
if ((dotTypes & DotPlotType.Vertical) == DotPlotType.Vertical)
|
|
count = range / dpSeries.DotPlotIndexValue;
|
|
|
|
size.Width = (int)(dotSize.Width * count + layout.NearMargin * 2);
|
|
|
|
if (chartXy.VScrollBar.Enabled == true)
|
|
size.Width += chartXy.VScrollBar.Width;
|
|
|
|
chartXy.MinQualitativeSize = size;
|
|
|
|
return (gridInterval);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalcYDotPlotSpacing
|
|
|
|
private double CalcYDotPlotSpacing(ChartXy chartXy, TickmarkLayout layout,
|
|
double range, ref int width, ChartSeries dpSeries, DotPlotType dotTypes, Size dotSize)
|
|
{
|
|
if ((dotTypes & DotPlotType.Horizontal) == DotPlotType.Horizontal)
|
|
{
|
|
int n = dotSize.Height / 2;
|
|
|
|
layout.NearMargin += n;
|
|
width -= (n * 2);
|
|
}
|
|
|
|
layout.MajorSpacing = (GridSpacing <= 0) ? 1 : GridSpacing;
|
|
|
|
double gridInterval = layout.MajorSpacing * dotSize.Height;
|
|
|
|
if (MinGridInterval > 0)
|
|
{
|
|
while (gridInterval < MinGridInterval)
|
|
{
|
|
gridInterval *= 2;
|
|
layout.MajorSpacing *= 2;
|
|
}
|
|
}
|
|
|
|
Size size = chartXy.MinQualitativeSize;
|
|
|
|
double count = range;
|
|
|
|
if ((dotTypes & DotPlotType.Horizontal) == DotPlotType.Horizontal)
|
|
count = range / dpSeries.DotPlotIndexValue;
|
|
|
|
size.Height = (int)(dotSize.Height * count + layout.NearMargin * 2);
|
|
|
|
if (chartXy.HScrollBar.Enabled == true)
|
|
size.Height += chartXy.HScrollBar.Height;
|
|
|
|
chartXy.MinQualitativeSize = size;
|
|
|
|
return (gridInterval);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region AxisCanExpand
|
|
|
|
private bool AxisCanExpand(ChartSeries dpSeries)
|
|
{
|
|
return ((dpSeries == null) ||
|
|
(AxisOrientation == AxisOrientation.X && dpSeries.SeriesType == SeriesType.VerticalDot) ||
|
|
(AxisOrientation == AxisOrientation.Y && dpSeries.SeriesType == SeriesType.HorizontalDot));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region UpdateQuantitativeMargins
|
|
|
|
private void UpdateQuantitativeMargins(
|
|
TickmarkLayout layout, Type otype, ref double dminValue, ref double dmaxValue)
|
|
{
|
|
if (layout.NearMargin > 0)
|
|
{
|
|
int marginCount = (int)Math.Ceiling(layout.NearMargin / layout.MajorInterval);
|
|
|
|
layout.MajorCount += marginCount;
|
|
|
|
if (otype == typeof(Int32))
|
|
{
|
|
if (dminValue - (marginCount * layout.MajorSpacing) > Int32.MinValue)
|
|
dminValue -= (marginCount * layout.MajorSpacing);
|
|
}
|
|
else
|
|
{
|
|
dminValue -= (marginCount * layout.MajorSpacing);
|
|
}
|
|
}
|
|
|
|
if (layout.FarMargin > 0)
|
|
{
|
|
int marginCount = (int)Math.Ceiling(layout.FarMargin / layout.MajorInterval);
|
|
|
|
layout.MajorCount += marginCount;
|
|
|
|
if (otype == typeof(Int32))
|
|
{
|
|
if (dmaxValue + (marginCount * layout.MajorSpacing) < Int32.MaxValue)
|
|
dmaxValue += (marginCount * layout.MajorSpacing);
|
|
}
|
|
else
|
|
{
|
|
dmaxValue += (marginCount * layout.MajorSpacing);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region CalcMajorQualitativeSpacing
|
|
|
|
private void CalcMajorQualitativeSpacing(TickmarkLayout layout, int width)
|
|
{
|
|
int iminValue = (int)layout.MinValue;
|
|
int imaxValue = (int)layout.MaxValue;
|
|
|
|
int ominValue = iminValue;
|
|
|
|
if (width > 0 && iminValue <= imaxValue)
|
|
{
|
|
width = SetLayoutMargin(layout, width);
|
|
|
|
double range = Math.Abs(imaxValue - iminValue) + 1;
|
|
|
|
CalcQualitativeSpacing(layout, range, width);
|
|
|
|
if (UseAutoMinGridInterval == true)
|
|
{
|
|
if (layout.MajorInterval <= 3)
|
|
layout.MajorInterval = 3;
|
|
}
|
|
|
|
UpdateQualitativeMargins(layout, ref iminValue, ref imaxValue);
|
|
|
|
// Make sure zero is included on the axis
|
|
|
|
iminValue -= (int)(iminValue % layout.MajorSpacing);
|
|
|
|
int moff = 0;
|
|
|
|
int n = iminValue < 0 ? -1 : 1;
|
|
|
|
double delta = Math.Floor(Math.Abs(iminValue) / layout.GridSpacing);
|
|
double value = (int)delta * layout.GridSpacing * n;
|
|
double offset = Math.Abs(value - ominValue);
|
|
|
|
moff = (int)((layout.MajorInterval * offset) / layout.MajorSpacing - layout.NearMargin);
|
|
|
|
layout.MarginOffset = moff;
|
|
|
|
layout.MinValue = iminValue;
|
|
layout.MaxValue = imaxValue;
|
|
}
|
|
}
|
|
|
|
#region CalcQualitativeSpacing
|
|
|
|
private void CalcQualitativeSpacing(
|
|
TickmarkLayout layout, double range, int width)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
layout.GridSpacing = 1;
|
|
layout.MajorSpacing = layout.GridSpacing;
|
|
|
|
layout.MajorCount = (int)range;
|
|
layout.MajorInterval = (double)width / layout.MajorCount;
|
|
|
|
if (layout.MinorCount > 0)
|
|
{
|
|
double minorInterval = layout.MajorInterval / (layout.MinorCount + 1);
|
|
|
|
if (minorInterval > 0)
|
|
{
|
|
while (minorInterval < MinGridInterval)
|
|
{
|
|
minorInterval *= 2;
|
|
layout.MinorCount /= 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
List<int> groupIds = GetSeriesGroupIds(chartXy);
|
|
|
|
int colWidth = int.MinValue;
|
|
|
|
foreach (int groupId in groupIds)
|
|
{
|
|
int n = chartXy.GetQualitativeColumnWidth(this, groupId);
|
|
|
|
if (n > colWidth)
|
|
colWidth = n;
|
|
}
|
|
|
|
if (UseAutoMinGridInterval == false)
|
|
{
|
|
if (colWidth > layout.MajorInterval)
|
|
colWidth = (int)layout.MajorInterval;
|
|
}
|
|
|
|
if (colWidth < MinGridInterval)
|
|
colWidth = MinGridInterval;
|
|
|
|
int minWidth = colWidth * (layout.MajorCount);
|
|
|
|
if (AxisOrientation == AxisOrientation.X)
|
|
{
|
|
if (chartXy.MinQualitativeSize.Width != minWidth)
|
|
{
|
|
Size size = chartXy.MinQualitativeSize;
|
|
size.Width = minWidth + layout.NearMargin;
|
|
chartXy.MinQualitativeSize = size;
|
|
|
|
// Force a layout change when the next
|
|
// layout invalidation arrives
|
|
|
|
LastTickmarkLayout = null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (chartXy.MinQualitativeSize.Height != minWidth)
|
|
{
|
|
Size size = chartXy.MinQualitativeSize;
|
|
size.Height = minWidth + layout.NearMargin;
|
|
chartXy.MinQualitativeSize = size;
|
|
|
|
LastTickmarkLayout = null;
|
|
}
|
|
}
|
|
|
|
width += layout.NearMargin;
|
|
minWidth = Math.Max(width, minWidth) - layout.NearMargin;
|
|
|
|
layout.MajorInterval = (double)minWidth / layout.MajorCount;
|
|
|
|
if (layout.MajorInterval < MinGridInterval)
|
|
{
|
|
layout.MajorInterval = MinGridInterval;
|
|
|
|
minWidth = (int)(layout.MajorInterval * (layout.MajorCount - 0));
|
|
}
|
|
|
|
layout.MajorInterval = (double)minWidth / (layout.MajorCount - 0);
|
|
|
|
foreach (int groupId in groupIds)
|
|
{
|
|
chartXy.AdjustQualitativeOffsets(this,
|
|
groupId, colWidth, (int)(layout.MajorInterval));
|
|
}
|
|
|
|
layout.NearMargin += (int)(layout.MajorInterval / 2);
|
|
}
|
|
|
|
#region GetSeriesGroupIds
|
|
|
|
private List<int> GetSeriesGroupIds(ChartXy chartXy)
|
|
{
|
|
List<int> groupIds = new List<int>();
|
|
|
|
foreach (ChartSeries series in chartXy.ChartSeries)
|
|
{
|
|
if (groupIds.Contains(series.GroupId) == false)
|
|
groupIds.Add(series.GroupId);
|
|
}
|
|
|
|
return (groupIds);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region UpdateQualitativeMargins
|
|
|
|
private void UpdateQualitativeMargins(
|
|
TickmarkLayout layout, ref int iminValue, ref int imaxValue)
|
|
{
|
|
if (layout.NearMargin > 0)
|
|
{
|
|
int marginCount = (int)Math.Ceiling(layout.NearMargin / layout.MajorInterval);
|
|
|
|
layout.MajorCount += marginCount;
|
|
|
|
iminValue -= (int)(marginCount * layout.MajorSpacing);
|
|
}
|
|
|
|
if (layout.FarMargin > 0)
|
|
{
|
|
int marginCount = (int)Math.Ceiling(layout.FarMargin / layout.MajorInterval);
|
|
|
|
layout.MajorCount += marginCount;
|
|
|
|
imaxValue += (int)(marginCount * layout.MajorSpacing);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region SetLayoutMargin
|
|
|
|
private int SetLayoutMargin(TickmarkLayout layout, int width)
|
|
{
|
|
layout.NearMargin = (AxisNearMargin >= 0) ? AxisNearMargin : AxisMargins >= 0 ? AxisMargins : 20;
|
|
layout.FarMargin = (AxisFarMargin >= 0) ? AxisFarMargin : AxisMargins >= 0 ? AxisMargins : 20;
|
|
|
|
layout.NearMargin = Dpi.Width(layout.NearMargin);
|
|
layout.FarMargin = Dpi.Width(layout.FarMargin);
|
|
|
|
layout.NearMargin = Math.Min(layout.NearMargin, width / 3);
|
|
layout.FarMargin = Math.Min(layout.FarMargin, width / 3);
|
|
|
|
if (layout.NearMargin > 0)
|
|
width -= (layout.NearMargin + 1);
|
|
|
|
if (layout.FarMargin > 0)
|
|
width -= (layout.FarMargin + 1);
|
|
|
|
return (width);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetBarSeries
|
|
|
|
private ChartSeries GetBarSeries(ChartXy chartXy)
|
|
{
|
|
foreach (ChartSeries series in chartXy.ChartSeries)
|
|
{
|
|
if (series.Visible == true)
|
|
{
|
|
if (series.IsBarSeries == true)
|
|
return (series);
|
|
}
|
|
}
|
|
|
|
return (null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetFullBarSeries
|
|
|
|
private ChartSeries GetFullBarSeries(ChartXy chartXy)
|
|
{
|
|
foreach (ChartSeries series in chartXy.ChartSeries)
|
|
{
|
|
if (series.Visible == true)
|
|
{
|
|
if (series.SeriesType == SeriesType.HorizontalBar ||
|
|
series.SeriesType == SeriesType.VerticalBar)
|
|
{
|
|
if (AxisOrientation == AxisOrientation.X)
|
|
{
|
|
if (series.AxisX == this || (series.AxisX == null && chartXy.AxisX == this))
|
|
return (series);
|
|
}
|
|
else
|
|
{
|
|
if (series.AxisY == this || (series.AxisY == null && chartXy.AxisY == this))
|
|
return (series);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetMaxTickMarkLength
|
|
|
|
protected int GetMaxTickMarkLength(bool inner)
|
|
{
|
|
int majorLength = MajorTickmarks.GetMaxTickmarkLength(this, inner);
|
|
int minorLength = MinorTickmarks.GetMaxTickmarkLength(this, inner);
|
|
|
|
int maxlen = Math.Max(majorLength, minorLength);
|
|
|
|
return (maxlen);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetAxisAlignment
|
|
|
|
internal AxisAlignment GetAxisAlignment()
|
|
{
|
|
if (AxisAlignment == AxisAlignment.NotSet)
|
|
return (IsPrimaryAxis ? AxisAlignment.Near : AxisAlignment.Far);
|
|
|
|
return (AxisAlignment);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetMinValue
|
|
|
|
internal object GetMinValue()
|
|
{
|
|
UpdateRangeValues();
|
|
|
|
if (MinValue != null)
|
|
{
|
|
if (ScaleType != ScaleType.NotSet)
|
|
{
|
|
if (SeriesPoint.GetScaleType(MinValue.GetType()) != ScaleType)
|
|
{
|
|
if (IsDesignerHosted == false)
|
|
throw new Exception("MinValue ScaleType must match Axis ScaleType");
|
|
|
|
return (ActualMinValue);
|
|
}
|
|
}
|
|
|
|
return (MinValue);
|
|
}
|
|
|
|
return (ActualMinValue);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetMaxValue
|
|
|
|
internal object GetMaxValue()
|
|
{
|
|
UpdateRangeValues();
|
|
|
|
if (MaxValue != null)
|
|
{
|
|
if (ScaleType != ScaleType.NotSet)
|
|
{
|
|
if (SeriesPoint.GetScaleType(MaxValue.GetType()) != ScaleType)
|
|
{
|
|
if (IsDesignerHosted == false)
|
|
throw new Exception("MaxValue ScaleType must match Axis ScaleType");
|
|
|
|
return (ActualMaxValue);
|
|
}
|
|
}
|
|
|
|
return (MaxValue);
|
|
}
|
|
|
|
return (ActualMaxValue);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateRangeValues
|
|
|
|
internal void UpdateRangeValues()
|
|
{
|
|
if (SeriesRangeChanged == true)
|
|
{
|
|
SeriesRangeChanged = false;
|
|
|
|
ActualMinValue = null;
|
|
ActualMaxValue = null;
|
|
|
|
QualitativeValues.Clear();
|
|
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
if (chartXy != null)
|
|
{
|
|
if (chartXy.ChartSeries.Count > 0)
|
|
{
|
|
UpdateRangeValues(chartXy);
|
|
|
|
if (QualitativeValues.Count > 1)
|
|
{
|
|
if (QualitativeSortDirection != SortDirection.None)
|
|
{
|
|
QualitativeValues.Sort(new
|
|
ObjComparer(this, QualitativeSortDirection == SortDirection.Ascending));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal virtual void UpdateRangeValues(ChartXy chartXy)
|
|
{
|
|
}
|
|
|
|
#region ObjComparer
|
|
|
|
private class ObjComparer : IComparer<object>
|
|
{
|
|
private ChartVisualElement _ChartElement;
|
|
private ChartControl _ChartControl;
|
|
|
|
private bool _Ascending;
|
|
|
|
public ObjComparer(ChartVisualElement chartElement, bool ascending)
|
|
{
|
|
_ChartElement = chartElement;
|
|
_ChartControl = chartElement.ChartControl;
|
|
|
|
_Ascending = ascending;
|
|
}
|
|
|
|
public int Compare(object v1, object v2)
|
|
{
|
|
int sval = 0;
|
|
|
|
if (_ChartControl.DoCompareElementsEvent(_ChartElement, v1, v2, ref sval) == true)
|
|
return (sval);
|
|
|
|
if (v1 is IComparable)
|
|
{
|
|
sval = ((IComparable)v1).CompareTo(v2);
|
|
|
|
if (sval != 0)
|
|
return (_Ascending == true) ? sval : -sval;
|
|
}
|
|
|
|
return (sval);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ValidateAxis
|
|
|
|
internal bool ValidateAxis()
|
|
{
|
|
bool altered = false;
|
|
|
|
if (LastTickmarkLayout == null || TickmarkLayout == null)
|
|
altered = true;
|
|
|
|
else if ((TickmarkLayout.MinValue != LastTickmarkLayout.MinValue) ||
|
|
(TickmarkLayout.MaxValue != LastTickmarkLayout.MaxValue) ||
|
|
(TickmarkLayout.MajorInterval != LastTickmarkLayout.MajorInterval) ||
|
|
(TickmarkLayout.MajorSpacing != LastTickmarkLayout.MajorSpacing) ||
|
|
(TickmarkLayout.MarginOffset != LastTickmarkLayout.MarginOffset))
|
|
{
|
|
altered = true;
|
|
}
|
|
|
|
LastTickmarkLayout = TickmarkLayout;
|
|
|
|
return (altered);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetChartPoint
|
|
|
|
protected Point GetChartPoint(Point pt)
|
|
{
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
pt.X += ScrollOffset.X;
|
|
pt.X -= (chartXy.HScrollBar.Inverted == true ? chartXy.HScrollOffset : -chartXy.HScrollOffset);
|
|
|
|
pt.Y += ScrollOffset.Y;
|
|
pt.Y -= (chartXy.VScrollBar.Inverted == true ? chartXy.VScrollOffset : -chartXy.VScrollOffset);
|
|
|
|
return (pt);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDisplayValue
|
|
|
|
virtual internal int GetDisplayValue(object axisValue)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDateTime
|
|
|
|
internal DateTime GetDateTime(DateTime dt, double delta)
|
|
{
|
|
switch (ActualDateTimeUnits)
|
|
{
|
|
case DateTimeUnits.Milliseconds:
|
|
return (dt.AddMilliseconds(delta));
|
|
|
|
case DateTimeUnits.Seconds:
|
|
return (dt.AddSeconds(delta));
|
|
|
|
case DateTimeUnits.Minutes:
|
|
return (dt.AddMinutes(delta));
|
|
|
|
case DateTimeUnits.Hours:
|
|
return (dt.AddHours(delta));
|
|
|
|
case DateTimeUnits.Days:
|
|
return (dt.AddDays(delta));
|
|
|
|
case DateTimeUnits.Months:
|
|
dt = dt.AddMonths((int)delta);
|
|
dt = dt.AddDays((delta - (int)delta) * 31);
|
|
|
|
return (dt);
|
|
|
|
case DateTimeUnits.Years:
|
|
return (dt.AddYears((int)delta));
|
|
|
|
default:
|
|
return (dt.AddTicks((long)delta));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDateTimeValue
|
|
|
|
internal long GetDateTimeValue(DateTime dtValue)
|
|
{
|
|
switch (ActualDateTimeUnits)
|
|
{
|
|
case DateTimeUnits.Milliseconds:
|
|
return (dtValue.Millisecond);
|
|
|
|
case DateTimeUnits.Seconds:
|
|
return (dtValue.Second);
|
|
|
|
case DateTimeUnits.Minutes:
|
|
return (dtValue.Minute);
|
|
|
|
case DateTimeUnits.Hours:
|
|
return (dtValue.Hour);
|
|
|
|
case DateTimeUnits.Days:
|
|
return (dtValue.Day);
|
|
|
|
case DateTimeUnits.Months:
|
|
return (dtValue.Month);
|
|
|
|
case DateTimeUnits.Years:
|
|
return (dtValue.Year);
|
|
|
|
default:
|
|
return (dtValue.Ticks);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDateTimePointValue
|
|
|
|
internal DateTime GetDateTimePointValue(TickmarkLayout layout, int dz)
|
|
{
|
|
double delta = (double)(layout.MajorSpacing * ((dz + layout.MarginOffset) / layout.MajorInterval));
|
|
|
|
return (GetDateTime((DateTime)layout.BaseValue, delta));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDateTimeLabel
|
|
|
|
internal string GetDateTimeLabel(DateTime dt)
|
|
{
|
|
switch (ActualDateTimeUnits)
|
|
{
|
|
case DateTimeUnits.Ticks:
|
|
return (dt.Ticks.ToString());
|
|
|
|
case DateTimeUnits.Milliseconds:
|
|
return (dt.Millisecond.ToString());
|
|
|
|
case DateTimeUnits.Seconds:
|
|
return (dt.Second.ToString());
|
|
|
|
case DateTimeUnits.Minutes:
|
|
return (dt.Minute.ToString());
|
|
|
|
case DateTimeUnits.Hours:
|
|
return (dt.ToShortTimeString());
|
|
|
|
case DateTimeUnits.Days:
|
|
return (dt.ToShortDateString());
|
|
|
|
case DateTimeUnits.Months:
|
|
return (dt.Month + "/" + dt.Year);
|
|
|
|
default:
|
|
return (dt.Year.ToString());
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetTickmarkAltValue
|
|
|
|
internal double GetTickmarkAltValue(TickmarkTick tick)
|
|
{
|
|
switch (ScaleType)
|
|
{
|
|
case ScaleType.DateTime:
|
|
DateTime dt = AddDateTimeOffset((DateTime)tick.Value, (int)(TickmarkLayout.MajorSpacing / 2));
|
|
|
|
return (GetDateTimeValue(dt));
|
|
|
|
case ScaleType.Qualitative:
|
|
return ((int)tick.Value + TickmarkLayout.MajorSpacing / 2);
|
|
|
|
default:
|
|
return (Convert.ToDouble(tick.Value) + TickmarkLayout.MajorSpacing / 2);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetLegendData
|
|
|
|
internal void GetLegendData(List<ChartLegendItem> legendData)
|
|
{
|
|
foreach (ReferenceLine line in ReferenceLines)
|
|
{
|
|
if (line.Visible == true)
|
|
{
|
|
List<ChartLegendItem> items = line.GetLegendItems();
|
|
|
|
if (items != null && items.Count > 0)
|
|
legendData.AddRange(items);
|
|
}
|
|
}
|
|
|
|
foreach (AxisStripe stripe in AxisStripes)
|
|
{
|
|
if (stripe.Visible == true)
|
|
{
|
|
List<ChartLegendItem> items = stripe.GetLegendItems();
|
|
|
|
if (items != null && items.Count > 0)
|
|
legendData.AddRange(items);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetPointFromValue
|
|
|
|
/// <summary>
|
|
/// Gets the chart Point from the given data value.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
public virtual Point GetPointFromValue(object value)
|
|
{
|
|
return (Point.Empty);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetValueFromPoint
|
|
|
|
/// <summary>
|
|
/// Gets the "Data" value from the given Chart Point.
|
|
/// </summary>
|
|
/// <param name="pt"></param>
|
|
/// <returns></returns>
|
|
public object GetValueFromPoint(Point pt)
|
|
{
|
|
TickmarkLayout layout = TickmarkLayout;
|
|
|
|
return (GetValueFromPoint(layout, pt));
|
|
}
|
|
|
|
internal virtual object GetValueFromPoint(TickmarkLayout layout, Point pt)
|
|
{
|
|
return (null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetReferenceLineByName
|
|
|
|
/// <summary>
|
|
/// Gets the ReferenceLine from the given name.
|
|
/// </summary>
|
|
/// <param name="name"></param>
|
|
/// <returns></returns>
|
|
public ReferenceLine GetReferenceLineByName(string name)
|
|
{
|
|
if (String.IsNullOrEmpty(name) == true)
|
|
return (null);
|
|
|
|
if (_ReferenceLines != null)
|
|
{
|
|
foreach (ReferenceLine line in _ReferenceLines)
|
|
{
|
|
if (name.Equals(line.Name) == true)
|
|
return (line);
|
|
}
|
|
}
|
|
|
|
return (null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetStripeByName
|
|
|
|
/// <summary>
|
|
/// Gets the AxisStripe from the given name.
|
|
/// </summary>
|
|
/// <param name="name"></param>
|
|
/// <returns></returns>
|
|
public AxisStripe GetStripeByName(string name)
|
|
{
|
|
if (String.IsNullOrEmpty(name) == true)
|
|
return (null);
|
|
|
|
if (_AxisStripes != null)
|
|
{
|
|
foreach (AxisStripe stripe in _AxisStripes)
|
|
{
|
|
if (name.Equals(stripe.Name) == true)
|
|
return (stripe);
|
|
}
|
|
}
|
|
|
|
return (null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EnsureVisible
|
|
|
|
/// <summary>
|
|
/// Ensures the given data value is visible on screen.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
public void EnsureVisible(object value)
|
|
{
|
|
EnsureVisible(value, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ensures the given data value is visible and
|
|
/// optionally centered on screen.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
public virtual void EnsureVisible(object value, bool center)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Style Support
|
|
|
|
#region ApplyStyles
|
|
|
|
public override void ApplyStyles(BaseVisualStyle style)
|
|
{
|
|
ChartAxisVisualStyle astyle = style as ChartAxisVisualStyle;
|
|
|
|
if (astyle != null)
|
|
{
|
|
ApplyParentStyles(astyle, Parent as ChartContainer);
|
|
|
|
astyle.ApplyStyle(ChartAxisVisualStyle);
|
|
astyle.ApplyDefaults();
|
|
}
|
|
else if (style is CrosshairValueVisualStyle)
|
|
{
|
|
CrosshairValueVisualStyle cstyle = (CrosshairValueVisualStyle)style;
|
|
|
|
ApplyParentStyles(cstyle, Parent as ChartContainer);
|
|
|
|
cstyle.ApplyStyle(CrosshairLabelVisualStyle);
|
|
cstyle.ApplyDefaults();
|
|
}
|
|
}
|
|
|
|
#region ApplyParentStyles (ChartAxisVisualStyle)
|
|
|
|
private void ApplyParentStyles(
|
|
ChartAxisVisualStyle astyle, ChartContainer item)
|
|
{
|
|
if (item != null)
|
|
{
|
|
ApplyParentStyles(astyle, item.Parent as ChartContainer);
|
|
|
|
ChartPanel cp = item as ChartPanel;
|
|
|
|
if (cp != null)
|
|
{
|
|
if (_AxisOrientation == AxisOrientation.X)
|
|
astyle.ApplyStyle(cp.DefaultVisualStyles.ChartXAxisVisualStyle);
|
|
else
|
|
astyle.ApplyStyle(cp.DefaultVisualStyles.ChartYAxisVisualStyle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_AxisOrientation == AxisOrientation.X)
|
|
{
|
|
astyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartXAxisVisualStyle);
|
|
astyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartXAxisVisualStyle);
|
|
}
|
|
else
|
|
{
|
|
astyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartYAxisVisualStyle);
|
|
astyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartYAxisVisualStyle);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ApplyParentStyles (CrosshairLabelVisualStyle)
|
|
|
|
private void ApplyParentStyles(
|
|
CrosshairValueVisualStyle pstyle, ChartContainer item)
|
|
{
|
|
if (item != null)
|
|
{
|
|
ApplyParentStyles(pstyle, item.Parent as ChartContainer);
|
|
|
|
if (item is ChartPanel)
|
|
pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.CrosshairLabelVisualStyle);
|
|
|
|
else if (item is ChartXy)
|
|
pstyle.ApplyStyle(((ChartXy)item).ChartCrosshair.CrosshairLabelVisualStyle);
|
|
}
|
|
else
|
|
{
|
|
pstyle.ApplyStyle(ChartControl.BaseVisualStyles.CrosshairLabelVisualStyle);
|
|
pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.CrosshairLabelVisualStyle);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region InvalidateStyle
|
|
|
|
///<summary>
|
|
///Invalidate the cached Styles
|
|
///</summary>
|
|
public void InvalidateStyle()
|
|
{
|
|
ClearEffectiveStyles();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ClearEffectiveStyles
|
|
|
|
protected override void ClearEffectiveStyles()
|
|
{
|
|
base.ClearEffectiveStyles();
|
|
|
|
_EffectiveAxisStyle.InvalidateStyle();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region InvalidateRender
|
|
|
|
/// <summary>
|
|
/// Invalidate the axis for rendering purposes.
|
|
/// </summary>
|
|
public override void InvalidateRender()
|
|
{
|
|
base.InvalidateRender();
|
|
|
|
ChartXy chartXy = Parent as ChartXy;
|
|
|
|
if (chartXy != null)
|
|
chartXy.InvalidateRender();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RefreshRangeValues
|
|
|
|
/// <summary>
|
|
/// Causes an invalidation and refresh of the range values for the axis.
|
|
/// </summary>
|
|
public void RefreshRangeValues()
|
|
{
|
|
SeriesRangeChanged = true;
|
|
|
|
InvalidateLayout();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Copy/CopyTo
|
|
|
|
/// <summary>
|
|
/// Copies the axis elements to the given "copy"
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
ChartAxis c = copy as ChartAxis;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyTo(c);
|
|
|
|
c.AxisAlignment = AxisAlignment;
|
|
|
|
c.AxisFarMargin = AxisFarMargin;
|
|
c.AxisMargins = AxisMargins;
|
|
c.AxisNearMargin = AxisNearMargin;
|
|
|
|
foreach (AxisStripe stripe in AxisStripes)
|
|
c.AxisStripes.Add((AxisStripe)stripe.Copy());
|
|
|
|
c.ChartAxisVisualStyle = (_ChartAxisVisualStyle != null) ? ChartAxisVisualStyle.Copy() : null;
|
|
c.CrosshairLabelVisualStyle = (_CrosshairLabelVisualStyle != null) ? CrosshairLabelVisualStyle.Copy() : null;
|
|
|
|
c.DateTimeUnits = DateTimeUnits;
|
|
c.GridInterval = GridInterval;
|
|
c.GridSpacing = GridSpacing;
|
|
|
|
c.MinGridInterval = MinGridInterval;
|
|
|
|
c.MaxValue = MaxValue;
|
|
c.MinValue = MinValue;
|
|
|
|
foreach (ReferenceLine line in ReferenceLines)
|
|
c.ReferenceLines.Add((ReferenceLine)line.Copy());
|
|
|
|
Title.CopyTo(c.Title);
|
|
|
|
c.UseAlternateBackground = UseAlternateBackground;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSerialData
|
|
|
|
internal override SerialElementCollection GetSerialData(string serialName)
|
|
{
|
|
SerialElementCollection sec = new SerialElementCollection();
|
|
|
|
if (serialName != null)
|
|
{
|
|
if (serialName.Equals("") == true)
|
|
serialName = "ChartAxis";
|
|
|
|
sec.AddStartElement(serialName);
|
|
}
|
|
|
|
sec.AddValue("AxisAlignment", AxisAlignment, AxisAlignment.NotSet);
|
|
|
|
sec.AddValue("AxisFarMargin", AxisFarMargin, -1);
|
|
sec.AddValue("AxisMargins", AxisMargins, -1);
|
|
sec.AddValue("AxisNearMargin", AxisNearMargin, -1);
|
|
|
|
if (_AxisStripes != null && _AxisStripes.Count > 0)
|
|
{
|
|
sec.AddStartElement("AxisStripes count=\"" + _AxisStripes.Count + "\"");
|
|
|
|
foreach (AxisStripe stripe in _AxisStripes)
|
|
sec.AddElement(stripe.GetSerialData(""));
|
|
|
|
sec.AddEndElement("AxisStripes");
|
|
}
|
|
|
|
if (_ChartAxisVisualStyle != null && _ChartAxisVisualStyle.IsEmpty == false)
|
|
sec.AddElement(_ChartAxisVisualStyle.GetSerialData("ChartAxisVisualStyle"));
|
|
|
|
if (_CrosshairLabelVisualStyle != null && _CrosshairLabelVisualStyle.IsEmpty == false)
|
|
sec.AddElement(_CrosshairLabelVisualStyle.GetSerialData("CrosshairLabelVisualStyle"));
|
|
|
|
sec.AddValue("DateTimeUnits", DateTimeUnits, DateTimeUnits.Days);
|
|
|
|
sec.AddValue("GridInterval", GridInterval, 0.0d);
|
|
sec.AddValue("GridSpacing", GridSpacing, 0.0d);
|
|
sec.AddValue("MinGridInterval", MinGridInterval, 10);
|
|
|
|
sec.AddDataValue("MaxValue", MaxValue, null);
|
|
sec.AddDataValue("MinValue", MinValue, null);
|
|
|
|
sec.AddValue("QualitativeSortDirection", QualitativeSortDirection, SortDirection.None);
|
|
|
|
if (_ReferenceLines != null && _ReferenceLines.Count > 0)
|
|
{
|
|
sec.AddStartElement("ReferenceLines count=\"" + _ReferenceLines.Count + "\"");
|
|
|
|
foreach (ReferenceLine rline in _ReferenceLines)
|
|
sec.AddElement(rline.GetSerialData(""));
|
|
|
|
sec.AddEndElement("ReferenceLines");
|
|
}
|
|
|
|
if (_Title != null)
|
|
sec.AddElement(_Title.GetSerialData("Title"));
|
|
|
|
sec.AddValue("UseAlternateBackground", UseAlternateBackground, false);
|
|
|
|
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 "AxisAlignment":
|
|
AxisAlignment = (AxisAlignment)se.GetValueEnum(typeof(AxisAlignment));
|
|
break;
|
|
|
|
case "AxisFarMargin":
|
|
AxisFarMargin = int.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "AxisMargins":
|
|
AxisMargins = int.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "AxisNearMargin":
|
|
AxisNearMargin = int.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "DateTimeUnits":
|
|
DateTimeUnits = (DateTimeUnits)se.GetValueEnum(typeof(DateTimeUnits));
|
|
break;
|
|
|
|
case "GridInterval":
|
|
GridInterval = double.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "GridSpacing":
|
|
GridSpacing = double.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "MinGridInterval":
|
|
MinGridInterval = int.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "MaxValue":
|
|
MaxValue = se.DataValue;
|
|
break;
|
|
|
|
case "MinValue":
|
|
MinValue = se.DataValue;
|
|
break;
|
|
|
|
case "QualitativeSortDirection":
|
|
QualitativeSortDirection = (SortDirection)se.GetValueEnum(typeof(SortDirection));
|
|
break;
|
|
|
|
case "UseAlternateBackground":
|
|
UseAlternateBackground = bool.Parse(se.StringValue);
|
|
break;
|
|
|
|
default:
|
|
base.ProcessValue(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ProcessCollection
|
|
|
|
internal override void ProcessCollection(SerialElement se)
|
|
{
|
|
SerialElementCollection sec = se.Sec;
|
|
|
|
switch (se.Name)
|
|
{
|
|
case "AxisStripes":
|
|
case "ReferenceLines":
|
|
sec.PutSerialData(this);
|
|
break;
|
|
|
|
case "AxisStripe":
|
|
AxisStripe stripe = GetStripeByName(se.Name);
|
|
|
|
if (stripe != null)
|
|
sec.PutSerialData(stripe);
|
|
break;
|
|
|
|
case "ChartAxisVisualStyle":
|
|
sec.PutSerialData(ChartAxisVisualStyle);
|
|
break;
|
|
|
|
case "CrosshairLabelVisualStyle":
|
|
sec.PutSerialData(CrosshairLabelVisualStyle);
|
|
break;
|
|
|
|
case "ReferenceLine":
|
|
ReferenceLine line = GetReferenceLineByName(se.Name);
|
|
|
|
if (line != null)
|
|
sec.PutSerialData(line);
|
|
break;
|
|
|
|
case "Title":
|
|
sec.PutSerialData(Title);
|
|
break;
|
|
|
|
default:
|
|
base.ProcessCollection(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region States
|
|
|
|
[Flags]
|
|
private enum States : uint
|
|
{
|
|
AutoCalcBarMargins = (1U << 0),
|
|
|
|
DotPlotAxis = (1U << 1),
|
|
EdgeAxis = (1U << 2),
|
|
PrimaryAxis = (1U << 3),
|
|
|
|
SeriesRangeChanged = (1U << 4),
|
|
|
|
UseAlternateBackground = (1U << 5),
|
|
UseAutoMinGridInterval = (1U << 6),
|
|
}
|
|
|
|
#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 ToString
|
|
|
|
public override string ToString()
|
|
{
|
|
if (String.IsNullOrEmpty(Name) == false)
|
|
return (Name);
|
|
|
|
return (base.ToString());
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IDisposable
|
|
|
|
public override void Dispose()
|
|
{
|
|
AxisStripes = null;
|
|
ChartAxisVisualStyle = null;
|
|
CrosshairLabelVisualStyle = null;
|
|
ReferenceLines = null;
|
|
Title = null;
|
|
|
|
base.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TickmarkLayout
|
|
|
|
internal class TickmarkLayout
|
|
{
|
|
public object MinValue;
|
|
public object MaxValue;
|
|
|
|
public object BaseValue;
|
|
|
|
public int NearMargin;
|
|
public int FarMargin;
|
|
public int MarginOffset;
|
|
|
|
public int MajorCount;
|
|
public int MinorCount;
|
|
|
|
public double GridSpacing;
|
|
public double MajorSpacing;
|
|
public double MajorInterval;
|
|
|
|
public int TickmarkStart;
|
|
public int TickmarkEnd;
|
|
|
|
public TickmarkTick[] Ticks;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TickmarkTick
|
|
|
|
internal class TickmarkTick
|
|
{
|
|
public int Index;
|
|
public object Value;
|
|
public Point TickPoint;
|
|
|
|
public string Label;
|
|
public Size LabelSize;
|
|
public Point LabelPoint;
|
|
public int LabelIndex;
|
|
public Color LabelColor;
|
|
|
|
public SizeF TextSize;
|
|
|
|
public bool LabelVisible;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisBar
|
|
|
|
internal class AxisBar
|
|
{
|
|
public int BarCount;
|
|
public int BarOffset;
|
|
public int BarTotalWidth;
|
|
|
|
public double BarTotal;
|
|
|
|
public void Reset()
|
|
{
|
|
BarCount = 0;
|
|
BarTotal = 0;
|
|
BarTotalWidth = 0;
|
|
|
|
BarOffset = int.MinValue;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public class AxisTitle : ChartTitle
|
|
{
|
|
#region XyAlignment
|
|
|
|
[Browsable(false)]
|
|
[Bindable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new XyAlignment XyAlignment
|
|
{
|
|
get { return (base.XyAlignment); }
|
|
set { base.XyAlignment = value; }
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
[Obsolete]
|
|
public class AsixTitle : AxisTitle
|
|
{
|
|
}
|
|
|
|
#region Enums
|
|
|
|
#region AxisAlignment
|
|
|
|
public enum AxisAlignment
|
|
{
|
|
/// <summary>
|
|
/// Default is determined by the Axis (X/Y).
|
|
/// </summary>
|
|
NotSet = -1,
|
|
|
|
/// <summary>
|
|
/// Axis is displayed at the right or bottom side of the chart.
|
|
/// </summary>
|
|
Near,
|
|
|
|
/// <summary>
|
|
/// Axis is displayed at the left or top side of the chart.
|
|
/// </summary>
|
|
Far,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisBarType
|
|
|
|
internal enum AxisBarType
|
|
{
|
|
Bar,
|
|
HiLoBar,
|
|
|
|
MaxBarCount
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AxisOrientation
|
|
|
|
/// <summary>
|
|
/// AxisOrientation.
|
|
/// </summary>
|
|
public enum AxisOrientation
|
|
{
|
|
/// <summary>
|
|
/// X Axis
|
|
/// </summary>
|
|
X,
|
|
|
|
/// <summary>
|
|
/// Y Axis
|
|
/// </summary>
|
|
Y,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DateTimeUnits
|
|
|
|
/// <summary>
|
|
/// DateTimeUnits
|
|
/// </summary>
|
|
public enum DateTimeUnits
|
|
{
|
|
Ticks,
|
|
Milliseconds,
|
|
Seconds,
|
|
Minutes,
|
|
Hours,
|
|
Days,
|
|
Months,
|
|
Years,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MarginLayout
|
|
|
|
public enum MarginLayout
|
|
{
|
|
/// <summary>
|
|
/// No Margins will be displayed.
|
|
/// </summary>
|
|
None,
|
|
|
|
/// <summary>
|
|
/// Margin is displayed at the right or bottom side of the axis.
|
|
/// </summary>
|
|
Near,
|
|
|
|
/// <summary>
|
|
/// Margin is displayed at the left or top side of the axis.
|
|
/// </summary>
|
|
Far,
|
|
|
|
/// <summary>
|
|
/// Both Near and Far margins are displayed.
|
|
/// </summary>
|
|
Both,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region OriginOffsetMode
|
|
|
|
/// <summary>
|
|
/// Mode for setting the axis origin, or offset from its
|
|
/// normal position.
|
|
/// </summary>
|
|
public enum OriginOffsetMode
|
|
{
|
|
/// <summary>
|
|
/// No offset
|
|
/// </summary>
|
|
None,
|
|
|
|
/// <summary>
|
|
/// Origin is shifted by an absolute amount (OriginOffset)
|
|
/// </summary>
|
|
Absolute,
|
|
|
|
/// <summary>
|
|
/// Origin is shifted relative to the major scale amounts.
|
|
/// </summary>
|
|
Relative,
|
|
|
|
/// <summary>
|
|
/// Origin is shifted a percentage of the total axis length.
|
|
/// </summary>
|
|
Percent,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region OverlapLabelMode
|
|
|
|
public enum OverlapLabelMode
|
|
{
|
|
/// <summary>
|
|
/// Default is to Hide overlapping labels.
|
|
/// </summary>
|
|
NotSet = 0,
|
|
|
|
/// <summary>
|
|
/// Overlapping labels will be staggered.
|
|
/// </summary>
|
|
Stagger,
|
|
|
|
/// <summary>
|
|
/// Overlapping labels may be hidden.
|
|
/// </summary>
|
|
Hide,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|