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
{
///
/// Represents the collection of Chart AxesX.
///
[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
}
///
/// Represents the collection of Chart AxesY.
///
[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
}
///
/// Represents the collection of Chart Axes.
///
public class ChartAxesCollection : CustomNamedCollection
{
#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
///
/// Represents an X-Axis element.
///
[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
///
/// Gets the axis MajorGridLines element.
///
[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
///
/// Gets the axis MajorTickmarks element.
///
[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
///
/// Gets the axis MinorGridLines element.
///
[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
///
/// Gets the axis MinorTickmarks element.
///
[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
///
/// Gets the chart Point from the given axis data value.
///
///
///
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
///
/// Ensures the given data value is visible and
/// optionally centered on screen.
///
///
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
///
/// Creates a copy of the axis.
///
///
public override ChartVisualElement Copy()
{
ChartAxisX copy = new ChartAxisX();
CopyTo(copy);
return (copy);
}
///
/// Copies the current axis properties to the
/// given "copy" axis.
///
///
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
///
/// Represents a Y-Axis element.
///
[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
///
/// Gets the axis MajorGridLines element.
///
[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
///
/// Gets the axis MajorTickmarks element.
///
[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
///
/// Gets the axis MinorGridLines element.
///
[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
///
/// Gets the axis MinorTickmarks element.
///
[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
///
/// Gets the chart Point from the given axis data value.
///
///
///
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
///
/// Ensures the given data value is visible and
/// optionally centered on screen.
///
///
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
///
/// Creates a copy of the axis.
///
///
public override ChartVisualElement Copy()
{
ChartAxisY copy = new ChartAxisY();
CopyTo(copy);
return (copy);
}
///
/// Copies each axis property to the given "copy".
///
///
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 _EffectiveAxisStyle;
private CrosshairValueVisualStyle _CrosshairLabelVisualStyle;
private EffectiveStyle _EffectiveCrosshairLabelStyle;
private List