2741 lines
78 KiB
C#
2741 lines
78 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Drawing.Design;
|
|
using System.Drawing.Drawing2D;
|
|
using DevComponents.DotNetBar.Charts.Style;
|
|
|
|
namespace DevComponents.DotNetBar.Charts
|
|
{
|
|
#region MajorTickmarks
|
|
|
|
#region MajorTickmarksX
|
|
|
|
/// <summary>
|
|
/// Represents a chart MajorTickmark on the X-Axis.
|
|
/// </summary>
|
|
public class MajorTickmarksX : MajorTickmarks
|
|
{
|
|
public MajorTickmarksX()
|
|
: base(AxisOrientation.X)
|
|
{
|
|
}
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
ChartTickmarkVisualStyle tstyle = EffectiveStyle;
|
|
|
|
Rectangle bounds = Rectangle.Empty;
|
|
|
|
MeasureTickmarks(layoutInfo, chartAxis);
|
|
|
|
if (TickmarkLayout.MajorCount > 0)
|
|
{
|
|
bounds = MeasureTickmarkLabels(layoutInfo, chartAxis);
|
|
|
|
float angle = GetLabelAngle();
|
|
|
|
if (angle == 0)
|
|
CullOverlappingLabels();
|
|
}
|
|
|
|
BoundsRelative = bounds;
|
|
}
|
|
|
|
#region MeasureTickmarks
|
|
|
|
private void MeasureTickmarks(ChartLayoutInfo layoutInfo, ChartAxis chartAxis)
|
|
{
|
|
TickmarkLayout layout = TickmarkLayout;
|
|
|
|
if (layout.MajorCount > 0)
|
|
{
|
|
Graphics g = layoutInfo.Graphics;
|
|
Rectangle bounds = layoutInfo.LayoutBounds;
|
|
|
|
layout.TickmarkStart = GetStartIndex();
|
|
layout.TickmarkEnd = layout.TickmarkStart + (int)Math.Ceiling((bounds.Width + layout.MarginOffset) / layout.MajorInterval) + 3;
|
|
|
|
UpdateTickmarkTicks(g, chartAxis, bounds, layout);
|
|
|
|
ArrangeTickmarks();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MeasureTickmarkLabels
|
|
|
|
private Rectangle MeasureTickmarkLabels(
|
|
ChartLayoutInfo layoutInfo, ChartAxis chartAxis)
|
|
{
|
|
ChartTickmarkVisualStyle tstyle = EffectiveStyle;
|
|
|
|
int labelHeight = GetTotalLabelHeight();
|
|
int tickmarkHeight = Dpi.Height(GetMaxTickmarkLength(chartAxis, false));
|
|
|
|
if (tickmarkHeight == 0)
|
|
tickmarkHeight = Dpi.Height4;
|
|
|
|
Rectangle bounds = layoutInfo.LayoutBounds;
|
|
bounds.Height = (labelHeight + tickmarkHeight);
|
|
|
|
ChartXy chartXy = chartAxis.Parent as ChartXy;
|
|
|
|
if (chartXy.DropShadowDisplayed == true)
|
|
bounds.Width -= 3;
|
|
|
|
Rectangle r = bounds;
|
|
|
|
if (chartAxis.GetAxisAlignment() == AxisAlignment.Far)
|
|
{
|
|
LabelBounds = new Rectangle(r.X, r.Y, r.Width, labelHeight);
|
|
|
|
r.Y += labelHeight;
|
|
r.Height -= labelHeight;
|
|
|
|
TickmarkBounds = r;
|
|
}
|
|
else
|
|
{
|
|
r.Y = layoutInfo.LayoutBounds.Bottom - labelHeight;
|
|
bounds.Y = r.Y;
|
|
|
|
LabelBounds = new Rectangle(r.X, r.Y, r.Width, labelHeight);
|
|
|
|
r.Y -= tickmarkHeight;
|
|
r.Height = tickmarkHeight;
|
|
|
|
TickmarkBounds = r;
|
|
}
|
|
|
|
if (chartAxis.EdgeAxis == false)
|
|
bounds.Height += Dpi.Height(GetMaxTickmarkLength(chartAxis, true)) + 2;
|
|
|
|
return (bounds);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ArrangeTickmarks
|
|
|
|
protected override void ArrangeTickmarks()
|
|
{
|
|
TickmarkLayout layout = TickmarkLayout;
|
|
|
|
if (layout.Ticks != null)
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
|
|
Rectangle tmBounds = TickmarkBounds;
|
|
Rectangle lbounds = LabelBounds;
|
|
|
|
AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
|
|
|
|
Point tickPoint = new Point(0,
|
|
(axisAlignment == AxisAlignment.Near) ? tmBounds.Y : tmBounds.Bottom + 1);
|
|
|
|
float angle = GetLabelAngle();
|
|
|
|
for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
|
|
{
|
|
TickmarkTick tick = layout.Ticks[i - layout.TickmarkStart];
|
|
|
|
tickPoint.X = (int)(tmBounds.Location.X + (i * layout.MajorInterval) - layout.MarginOffset);
|
|
tick.TickPoint = tickPoint;
|
|
|
|
if (tick.Label != null)
|
|
{
|
|
tick.LabelPoint = tickPoint;
|
|
tick.LabelPoint.Y = lbounds.Y;
|
|
|
|
int height = LabelBounds.Height;
|
|
|
|
if (LabelsAreStaggered == true)
|
|
{
|
|
double value = GetTickmarkValue(chartAxis, tick);
|
|
int n = (int)(Math.Ceiling(value / TickmarkLayout.MajorSpacing));
|
|
|
|
if ((tick.Index % 2) != (axisAlignment == AxisAlignment.Far ? 0 : 1))
|
|
{
|
|
height -= MaxLabelSize[0].Height;
|
|
tick.LabelPoint.Y += MaxLabelSize[0].Height;
|
|
}
|
|
else
|
|
{
|
|
height -= MaxLabelSize[1].Height;
|
|
}
|
|
}
|
|
|
|
if (axisAlignment == AxisAlignment.Far)
|
|
tick.LabelPoint.Y += (height - tick.LabelSize.Height);
|
|
|
|
if (angle == 0)
|
|
tick.LabelPoint.X -= (tick.LabelSize.Width / 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region CullOverlappingLabels
|
|
|
|
private void CullOverlappingLabels()
|
|
{
|
|
TickmarkLayout layout = TickmarkLayout;
|
|
|
|
for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
|
|
{
|
|
TickmarkTick tick = layout.Ticks[i - layout.TickmarkStart];
|
|
|
|
if (tick.LabelVisible == true)
|
|
{
|
|
for (int j = i + 1; j < layout.TickmarkEnd; j++)
|
|
{
|
|
TickmarkTick tick2 = layout.Ticks[j - layout.TickmarkStart];
|
|
|
|
if (tick2.LabelVisible == true)
|
|
{
|
|
if (tick2.LabelPoint.X < tick.LabelPoint.X + tick.LabelSize.Width - 1)
|
|
{
|
|
if ((LabelsAreStaggered == false) ||
|
|
(tick.LabelIndex % 2 == tick2.LabelIndex % 2))
|
|
{
|
|
tick2.LabelVisible = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
base.RenderOverride(renderInfo);
|
|
|
|
Graphics g = renderInfo.Graphics;
|
|
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
ChartTickmarkVisualStyle tstyle = EffectiveStyle;
|
|
|
|
if (CanRenderTickmarks(tstyle) == true)
|
|
RenderTickmarks(g, tstyle, chartAxis);
|
|
|
|
if (TickmarkLayout.MajorCount > 0)
|
|
RenderTickmarkLabels(g, chartAxis);
|
|
}
|
|
|
|
#region RenderTickmarks
|
|
|
|
private void RenderTickmarks(Graphics g,
|
|
ChartTickmarkVisualStyle tstyle, ChartAxis chartAxis)
|
|
{
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.None;
|
|
|
|
using (Pen pen = new Pen(tstyle.TickmarkColor, Dpi.Width(tstyle.TickmarkThickness)))
|
|
{
|
|
int tlen = Dpi.Width(tstyle.TickmarkLength - ((tstyle.TickmarkThickness > 1) ? 0 : 1));
|
|
|
|
AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
|
|
|
|
Point pt = GetLocalAdjustedPoint(Point.Empty);
|
|
|
|
if ((tstyle.TickmarkAlignment == LineAlignment.Center) ||
|
|
(axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Near) ||
|
|
(axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Far))
|
|
{
|
|
// Bottom
|
|
|
|
RenderMarks(g, pen, chartAxis, pt, 0, tlen, axisAlignment == AxisAlignment.Far);
|
|
}
|
|
|
|
if ((tstyle.TickmarkAlignment == LineAlignment.Center) ||
|
|
(axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Far) ||
|
|
(axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Near))
|
|
{
|
|
// Top
|
|
|
|
ChartXy chartXy = chartAxis.Parent as ChartXy;
|
|
|
|
if (axisAlignment == AxisAlignment.Near)
|
|
{
|
|
int n = 1;
|
|
|
|
if (chartAxis.EdgeAxis == true)
|
|
n = chartXy.GetScBorderThickness(XyAlignment.Bottom) + 1;
|
|
|
|
RenderMarks(g, pen, chartAxis, pt, -(n + tlen), tlen, true);
|
|
}
|
|
else
|
|
{
|
|
int n = 1;
|
|
|
|
RenderMarks(g, pen, chartAxis, pt, -(n + tlen), tlen, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
g.SmoothingMode = sm;
|
|
}
|
|
|
|
#region RenderMarks
|
|
|
|
private void RenderMarks(Graphics g,
|
|
Pen pen, ChartAxis chartAxis, Point pt, int voff, int len, bool skipFirst)
|
|
{
|
|
foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
|
|
{
|
|
Point pt1 = tmi.TickPoint;
|
|
pt1.X += pt.X;
|
|
pt1.Y += (pt.Y + voff);
|
|
|
|
if (pt1.X >= chartAxis.AxisLineBounds.X - ScrollOffset.X &&
|
|
pt1.X < chartAxis.AxisLineBounds.Right - ScrollOffset.X)
|
|
{
|
|
if (tmi.Index > 0 || skipFirst == false)
|
|
{
|
|
Point pt2 = pt1;
|
|
pt2.Y += len;
|
|
|
|
g.DrawLine(pen, pt1, pt2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderTickmarkLabels
|
|
|
|
private void RenderTickmarkLabels(Graphics g, ChartAxis chartAxis)
|
|
{
|
|
if (LabelBounds.IsEmpty == false)
|
|
{
|
|
TickmarkLabelVisualStyle lstyle = EffectiveLabelStyle;
|
|
|
|
Point pt = GetLocalAdjustedPoint(Point.Empty);
|
|
float angle = GetLabelAngle();
|
|
|
|
using (SolidBrush br = new SolidBrush(lstyle.TextColor))
|
|
{
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
ChartXy chartXy = chartAxis.Parent as ChartXy;
|
|
Rectangle alb = chartXy.GetScrollBounds(chartAxis.AxisLineBounds);
|
|
|
|
foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
|
|
{
|
|
if (tmi.LabelVisible == true)
|
|
{
|
|
if ((tmi.TickPoint.X + pt.X >= alb.X) &&
|
|
(tmi.TickPoint.X + pt.X < alb.Right))
|
|
{
|
|
if (tmi.LabelColor.IsEmpty == true)
|
|
{
|
|
RenderLabel(g, tmi, pt, angle, br, lstyle.Font);
|
|
}
|
|
else
|
|
{
|
|
using (SolidBrush br2 = new SolidBrush(tmi.LabelColor))
|
|
RenderLabel(g, tmi, pt, angle, br2, lstyle.Font);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
g.SmoothingMode = sm;
|
|
}
|
|
}
|
|
}
|
|
|
|
#region RenderLabel
|
|
|
|
private void RenderLabel(Graphics g,
|
|
TickmarkTick tmi, Point pt, float angle, Brush br, Font font)
|
|
{
|
|
Rectangle r = new Rectangle(tmi.LabelPoint, tmi.LabelSize);
|
|
r.X += pt.X;
|
|
r.Y += pt.Y;
|
|
|
|
if (angle == 0)
|
|
{
|
|
g.DrawString(tmi.Label, font, br, r);
|
|
}
|
|
else
|
|
{
|
|
Point pt1 = Point.Empty;
|
|
|
|
if (angle > 0)
|
|
{
|
|
if (angle > 90)
|
|
{
|
|
angle = angle - 180;
|
|
|
|
pt1.X = -(int)tmi.TextSize.Width;
|
|
}
|
|
|
|
pt1.Y = -(int)((Math.Abs(angle) / 90f) * (font.Height / 2));
|
|
|
|
g.TranslateTransform(r.X, r.Y);
|
|
}
|
|
else
|
|
{
|
|
if (angle < -90)
|
|
{
|
|
angle = angle + 180;
|
|
|
|
pt1.X = -(int)tmi.TextSize.Width + 4;
|
|
}
|
|
|
|
pt1.Y = -(int)(tmi.TextSize.Height -
|
|
(Math.Abs(angle) / 90f) * (tmi.TextSize.Height / 2));
|
|
|
|
g.TranslateTransform(r.X, LabelBounds.Bottom - 1);
|
|
}
|
|
|
|
g.RotateTransform(angle);
|
|
|
|
g.DrawString(tmi.Label, font, br, pt1);
|
|
|
|
g.ResetTransform();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetStartIndex
|
|
|
|
internal override int GetStartIndex()
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
ChartXy chartXy = chartAxis.Parent as ChartXy;
|
|
|
|
return (GetStartIndexEx(chartXy.HScrollBar));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Copy/CopyTo
|
|
|
|
/// <summary>
|
|
/// Create a copy of the chart element.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override ChartVisualElement Copy()
|
|
{
|
|
MajorTickmarksX copy = new MajorTickmarksX();
|
|
|
|
CopyTo(copy);
|
|
|
|
return (copy);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies the chart element to the given "copy".
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
MajorTickmarksX c = copy as MajorTickmarksX;
|
|
|
|
if (c != null)
|
|
base.CopyTo(c);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MajorTickmarksY
|
|
|
|
/// <summary>
|
|
/// Represents a chart MajorTickmark on the Y-Axis.
|
|
/// </summary>
|
|
public class MajorTickmarksY : MajorTickmarks
|
|
{
|
|
public MajorTickmarksY()
|
|
: base(AxisOrientation.Y)
|
|
{
|
|
}
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
ChartTickmarkVisualStyle tstyle = EffectiveStyle;
|
|
|
|
Rectangle bounds = Rectangle.Empty;
|
|
|
|
MeasureTickmarks(layoutInfo, chartAxis);
|
|
|
|
if (TickmarkLayout.MajorCount > 0)
|
|
bounds = MeasureTickmarkLabels(layoutInfo, chartAxis);
|
|
|
|
BoundsRelative = bounds;
|
|
}
|
|
|
|
#region MeasureTickmarks
|
|
|
|
private void MeasureTickmarks(ChartLayoutInfo layoutInfo, ChartAxis chartAxis)
|
|
{
|
|
TickmarkLayout layout = TickmarkLayout;
|
|
|
|
if (layout.MajorCount > 0)
|
|
{
|
|
Graphics g = layoutInfo.Graphics;
|
|
Rectangle bounds = layoutInfo.LayoutBounds;
|
|
|
|
layout.TickmarkStart = GetStartIndex();
|
|
layout.TickmarkEnd = layout.TickmarkStart + (int)((Math.Ceiling(bounds.Height / layout.MajorInterval))) + 3;
|
|
|
|
UpdateTickmarkTicks(g, chartAxis, bounds, layout);
|
|
|
|
ArrangeTickmarks();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MeasureTickmarkLabels
|
|
|
|
private Rectangle MeasureTickmarkLabels(ChartLayoutInfo layoutInfo, ChartAxis chartAxis)
|
|
{
|
|
Rectangle bounds = layoutInfo.LayoutBounds;
|
|
|
|
int labelWidth = GetTotalLabelWidth();
|
|
int tickmarkWidth = Dpi.Width(GetMaxTickmarkLength(chartAxis, false));
|
|
|
|
bounds.Width = (labelWidth + tickmarkWidth);
|
|
|
|
ChartXy chartXy = chartAxis.Parent as ChartXy;
|
|
|
|
if (chartXy.DropShadowDisplayed == true)
|
|
bounds.Height -= 3;
|
|
|
|
Rectangle r = bounds;
|
|
|
|
AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
|
|
|
|
if (axisAlignment == AxisAlignment.Far)
|
|
{
|
|
LabelBounds = new Rectangle(r.X, r.Y, labelWidth, r.Height);
|
|
|
|
r.X += labelWidth;
|
|
r.Width -= labelWidth;
|
|
|
|
TickmarkBounds = r;
|
|
}
|
|
else
|
|
{
|
|
r.X = layoutInfo.LayoutBounds.Right - labelWidth;
|
|
bounds.X = r.X;
|
|
|
|
LabelBounds = new Rectangle(r.X, r.Y, labelWidth, r.Height);
|
|
|
|
r.X -= tickmarkWidth;
|
|
r.Width = tickmarkWidth;
|
|
|
|
TickmarkBounds = r;
|
|
}
|
|
|
|
if (chartAxis.EdgeAxis == false)
|
|
bounds.Width += Dpi.Width(GetMaxTickmarkLength(chartAxis, true)) + 2;
|
|
|
|
return (bounds);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ArrangeTickmarks
|
|
|
|
protected override void ArrangeTickmarks()
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
|
|
Rectangle tmBounds = TickmarkBounds;
|
|
Rectangle lbounds = LabelBounds;
|
|
TickmarkLayout layout = TickmarkLayout;
|
|
|
|
AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
|
|
Point tickPoint = new Point((axisAlignment == AxisAlignment.Near) ? tmBounds.X : tmBounds.Right + 1, 0);
|
|
|
|
float angle = GetLabelAngle();
|
|
|
|
for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
|
|
{
|
|
TickmarkTick tick = layout.Ticks[i - layout.TickmarkStart];
|
|
|
|
tickPoint.Y = (int)(tmBounds.Bottom - 1 - (i * layout.MajorInterval) + layout.MarginOffset);
|
|
|
|
tick.TickPoint = tickPoint;
|
|
|
|
tick.LabelPoint = tickPoint;
|
|
tick.LabelPoint.X = lbounds.X;
|
|
|
|
int width = LabelBounds.Width;
|
|
|
|
if (LabelsAreStaggered == true)
|
|
{
|
|
double value = GetTickmarkValue(chartAxis, tick);
|
|
int n = (int)(Math.Ceiling(value / TickmarkLayout.MajorSpacing));
|
|
|
|
if ((n % 2) != (axisAlignment == AxisAlignment.Near ? 0 : 1))
|
|
{
|
|
width -= MaxLabelSize[0].Width;
|
|
tick.LabelPoint.X += MaxLabelSize[0].Width;
|
|
}
|
|
else
|
|
{
|
|
width -= MaxLabelSize[1].Width;
|
|
}
|
|
}
|
|
|
|
if (axisAlignment == AxisAlignment.Far)
|
|
tick.LabelPoint.X += (width - tick.LabelSize.Width);
|
|
|
|
if ((angle + 90) % 180 == 0)
|
|
tick.LabelPoint.Y -= (tick.LabelSize.Height / 2);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
base.RenderOverride(renderInfo);
|
|
|
|
Graphics g = renderInfo.Graphics;
|
|
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
ChartTickmarkVisualStyle tstyle = EffectiveStyle;
|
|
|
|
if (CanRenderTickmarks(tstyle) == true)
|
|
RenderTickmarks(g, tstyle, chartAxis);
|
|
|
|
if (TickmarkLayout.MajorCount > 0)
|
|
RenderTickmarkLabels(g, chartAxis);
|
|
}
|
|
|
|
#region RenderTickmarks
|
|
|
|
private void RenderTickmarks(Graphics g,
|
|
ChartTickmarkVisualStyle tstyle, ChartAxis chartAxis)
|
|
{
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.None;
|
|
|
|
using (Pen pen = new Pen(tstyle.TickmarkColor, Dpi.Height(tstyle.TickmarkThickness)))
|
|
{
|
|
int tlen = Dpi.Height(tstyle.TickmarkLength) - ((tstyle.TickmarkThickness > 1) ? 0 : 1);
|
|
|
|
Point pt = GetLocalAdjustedPoint(Point.Empty);
|
|
|
|
AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
|
|
|
|
if (tstyle.TickmarkAlignment == LineAlignment.Center ||
|
|
(axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Near) ||
|
|
(axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Far))
|
|
{
|
|
// Right
|
|
|
|
RenderMarks(g, pen, chartAxis, pt, 0, tlen, axisAlignment == AxisAlignment.Far);
|
|
}
|
|
|
|
if (tstyle.TickmarkAlignment == LineAlignment.Center ||
|
|
(axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Far) ||
|
|
(axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Near))
|
|
{
|
|
// Left
|
|
|
|
ChartXy chartXy = chartAxis.Parent as ChartXy;
|
|
|
|
if (axisAlignment == AxisAlignment.Near)
|
|
{
|
|
int n = 1;
|
|
|
|
if (chartAxis.EdgeAxis == true)
|
|
n = chartXy.GetScBorderThickness(XyAlignment.Right) + 1;
|
|
|
|
RenderMarks(g, pen, chartAxis, pt, -(n + tlen), tlen, true);
|
|
}
|
|
else
|
|
{
|
|
int n = 2;
|
|
|
|
RenderMarks(g, pen, chartAxis, pt, -(n + tlen), tlen, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
g.SmoothingMode = sm;
|
|
}
|
|
|
|
#region RenderMarks
|
|
|
|
private void RenderMarks(Graphics g,
|
|
Pen pen, ChartAxis chartAxis, Point pt, int hoff, int len, bool skipFirst)
|
|
{
|
|
foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
|
|
{
|
|
Point pt1 = tmi.TickPoint;
|
|
pt1.X += (pt.X + hoff);
|
|
pt1.Y += pt.Y;
|
|
|
|
if (pt1.Y >= chartAxis.AxisLineBounds.Y - ScrollOffset.Y &&
|
|
pt1.Y < chartAxis.AxisLineBounds.Bottom - ScrollOffset.Y)
|
|
{
|
|
if (tmi.Index > 0 || skipFirst == false)
|
|
{
|
|
Point pt2 = pt1;
|
|
pt2.X += len;
|
|
|
|
g.DrawLine(pen, pt1, pt2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderTickmarkLabels
|
|
|
|
private void RenderTickmarkLabels(Graphics g, ChartAxis chartAxis)
|
|
{
|
|
if (LabelBounds.IsEmpty == false)
|
|
{
|
|
TickmarkLabelVisualStyle lstyle = EffectiveLabelStyle;
|
|
|
|
Point pt = GetLocalAdjustedPoint(Point.Empty);
|
|
AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
|
|
|
|
float angle = GetLabelAngle();
|
|
|
|
using (SolidBrush br = new SolidBrush(lstyle.TextColor))
|
|
{
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
Rectangle bounds = chartAxis.Bounds;
|
|
|
|
foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
|
|
{
|
|
if (tmi.LabelVisible == true)
|
|
{
|
|
if (tmi.TickPoint.Y + pt.Y < bounds.Y)
|
|
break;
|
|
|
|
if (tmi.TickPoint.Y + pt.Y > bounds.Bottom)
|
|
continue;
|
|
|
|
if (tmi.LabelColor.IsEmpty == true)
|
|
{
|
|
RenderLabel(g, tmi, pt, axisAlignment, angle, br, lstyle.Font);
|
|
}
|
|
else
|
|
{
|
|
using (SolidBrush br2 = new SolidBrush(tmi.LabelColor))
|
|
RenderLabel(g, tmi, pt, axisAlignment, angle, br2, lstyle.Font);
|
|
}
|
|
}
|
|
}
|
|
|
|
g.SmoothingMode = sm;
|
|
}
|
|
}
|
|
}
|
|
|
|
#region RenderLabel
|
|
|
|
private void RenderLabel(Graphics g, TickmarkTick tmi,
|
|
Point pt, AxisAlignment axisAlignment, float angle, Brush br, Font font)
|
|
{
|
|
Rectangle r = new Rectangle(tmi.LabelPoint, tmi.LabelSize);
|
|
r.X += pt.X;
|
|
r.Y += pt.Y;
|
|
|
|
int n = (int)(tmi.TextSize.Height / 2);
|
|
|
|
if (angle == 0)
|
|
{
|
|
r.Y -= n;
|
|
g.DrawString(tmi.Label, font, br, r);
|
|
}
|
|
else
|
|
{
|
|
Point pt1 = Point.Empty;
|
|
|
|
if (angle > 0)
|
|
{
|
|
if (angle > 90)
|
|
{
|
|
angle = angle - 180;
|
|
|
|
pt1.Y -= (int)(((90 + angle) / 90f) * (font.Height / 2));
|
|
}
|
|
else
|
|
{
|
|
pt1.Y -= (n + (int)((Math.Abs(angle) / 90f) * (font.Height / 2)));
|
|
}
|
|
|
|
g.TranslateTransform(r.X, r.Y);
|
|
}
|
|
else
|
|
{
|
|
if (angle < -90)
|
|
{
|
|
angle = angle + 180;
|
|
|
|
pt1.Y -= ((int)((Math.Abs(90 - angle) / 90f) * (tmi.TextSize.Height / 2)));
|
|
}
|
|
else
|
|
{
|
|
pt1.Y -= (n + (int)((Math.Abs(angle) / 90f) * (font.Height / 2)));
|
|
}
|
|
|
|
pt1.X = -(int)tmi.TextSize.Width;
|
|
|
|
g.TranslateTransform(r.Right, r.Y);
|
|
}
|
|
|
|
g.RotateTransform(angle);
|
|
|
|
g.DrawString(tmi.Label, font, br, pt1);
|
|
|
|
g.ResetTransform();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetStartIndex
|
|
|
|
internal override int GetStartIndex()
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
ChartXy chartXy = chartAxis.Parent as ChartXy;
|
|
|
|
return (GetStartIndexEx(chartXy.VScrollBar));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Copy/CopyTo
|
|
|
|
/// <summary>
|
|
/// Creates a copy of the chart element.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override ChartVisualElement Copy()
|
|
{
|
|
MajorTickmarksY copy = new MajorTickmarksY();
|
|
|
|
CopyTo(copy);
|
|
|
|
return (copy);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies the chart element to the given "copy".
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
MajorTickmarksY c = copy as MajorTickmarksY;
|
|
|
|
if (c != null)
|
|
base.CopyTo(c);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MajorTickmarks
|
|
|
|
/// <summary>
|
|
/// Represents a chart MajorTickmark.
|
|
/// </summary>
|
|
public class MajorTickmarks : ChartTickmarks
|
|
{
|
|
#region Private variables
|
|
|
|
private MajorStates _MajorStates;
|
|
|
|
private float _LabelAngle;
|
|
private int _MinLabelGap = 4;
|
|
private int _LabelSkip;
|
|
|
|
private Rectangle _LabelBounds;
|
|
private Size[] _MaxLabelSize;
|
|
|
|
private TickmarkLabelVisualStyle _LabelVisualStyle;
|
|
private EffectiveStyle<TickmarkLabelVisualStyle> _EffectiveLabelStyle;
|
|
|
|
#endregion
|
|
|
|
public MajorTickmarks(AxisOrientation orientation)
|
|
: base(orientation)
|
|
{
|
|
InitDefaultStates();
|
|
|
|
_EffectiveLabelStyle = new EffectiveStyle<TickmarkLabelVisualStyle>(this);
|
|
}
|
|
|
|
#region InitDefaultStates
|
|
|
|
private void InitDefaultStates()
|
|
{
|
|
SetState(MajorStates.AutoLayout, true);
|
|
SetState(MajorStates.ShowLabels, true);
|
|
SetState(MajorStates.StaggerLabels, true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
#region AutoTickmarkLayout
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether Major Tickmark layout is automatic.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Appearance")]
|
|
[Description("Indicates whether Major Tickmark layout is automatic.")]
|
|
public bool AutoTickmarkLayout
|
|
{
|
|
get { return (TestState(MajorStates.AutoLayout)); }
|
|
|
|
set
|
|
{
|
|
if (value != AutoTickmarkLayout)
|
|
{
|
|
SetState(MajorStates.AutoLayout, value);
|
|
|
|
OnPropertyChangedEx("AutoTickmarkLayout", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EffectiveLabelStyles
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the Tickmark Label's Effective (cached, composite) style.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public TickmarkLabelVisualStyle EffectiveLabelStyle
|
|
{
|
|
get { return (_EffectiveLabelStyle.Style); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LabelAngle
|
|
|
|
///<summary>
|
|
/// Gets or sets the angle at which the Tickmark labels are displayed.
|
|
///</summary>
|
|
[DefaultValue(0f), Category("Layout")]
|
|
[Description("Indicates the angle at which the Tickmark labels are displayed.")]
|
|
[Editor("DevComponents.Charts.Design.AngleRangeValueEditor, DevComponents.Charts.Design, " +
|
|
"Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
|
|
public float LabelAngle
|
|
{
|
|
get { return (_LabelAngle); }
|
|
|
|
set
|
|
{
|
|
if (value != _LabelAngle)
|
|
{
|
|
_LabelAngle = value;
|
|
|
|
OnPropertyChangedEx("LabelAngle", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LabelSkip
|
|
|
|
/// <summary>
|
|
/// Gets or sets the number of inter-labels to skip.
|
|
/// </summary>
|
|
[DefaultValue(0), Category("Layout")]
|
|
[Description("Indicates the number of inter-labels to skip.")]
|
|
public int LabelSkip
|
|
{
|
|
get { return (_LabelSkip); }
|
|
|
|
set
|
|
{
|
|
if (value != _LabelSkip)
|
|
{
|
|
_LabelSkip = value;
|
|
|
|
OnPropertyChangedEx("LabelSkip", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LabelVisualStyle
|
|
|
|
/// <summary>
|
|
/// Gets or sets the visual style for the Tickmark Labels.
|
|
/// </summary>
|
|
[Category("Style")]
|
|
[Description("Indicates the visual style for the Tickmark Labels.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public TickmarkLabelVisualStyle LabelVisualStyle
|
|
{
|
|
get
|
|
{
|
|
if (_LabelVisualStyle == null)
|
|
{
|
|
_LabelVisualStyle = new TickmarkLabelVisualStyle();
|
|
|
|
StyleVisualChangeHandler(null, _LabelVisualStyle);
|
|
}
|
|
|
|
return (_LabelVisualStyle);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_LabelVisualStyle != value)
|
|
{
|
|
TickmarkLabelVisualStyle oldValue = _LabelVisualStyle;
|
|
|
|
_LabelVisualStyle = value;
|
|
|
|
OnStyleChanged("LabelVisualStyle", oldValue, value);
|
|
|
|
if (oldValue != null)
|
|
oldValue.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinLabelGap
|
|
|
|
/// <summary>
|
|
/// Gets or sets the minimum gap between tickmark labels.
|
|
/// </summary>
|
|
[DefaultValue(4), Category("Layout")]
|
|
[Description("Indicates the minimum gap between tickmark labels.")]
|
|
public int MinLabelGap
|
|
{
|
|
get { return (_MinLabelGap); }
|
|
|
|
set
|
|
{
|
|
if (value != _MinLabelGap)
|
|
{
|
|
_MinLabelGap = value;
|
|
|
|
OnPropertyChangedEx("MinLabelGap", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowLabels
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether Tickmark labels are shown.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Layout")]
|
|
[Description("Indicates whether Tickmark labels are shown.")]
|
|
public bool ShowLabels
|
|
{
|
|
get { return (TestState(MajorStates.ShowLabels)); }
|
|
|
|
set
|
|
{
|
|
if (value != ShowLabels)
|
|
{
|
|
SetState(MajorStates.ShowLabels, value);
|
|
|
|
OnPropertyChangedEx("ShowLabels", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region StaggerLabels
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether overlapping labels are staggered.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Layout")]
|
|
[Description("Indicates whether overlapping labels are staggered.")]
|
|
public bool StaggerLabels
|
|
{
|
|
get { return (TestState(MajorStates.StaggerLabels)); }
|
|
|
|
set
|
|
{
|
|
if (value != StaggerLabels)
|
|
{
|
|
SetState(MajorStates.StaggerLabels, value);
|
|
|
|
OnPropertyChangedEx("StaggerLabels", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Internal properties
|
|
|
|
#region LabelBounds
|
|
|
|
internal Rectangle LabelBounds
|
|
{
|
|
get { return (_LabelBounds); }
|
|
set { _LabelBounds = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LabelsAreStaggered
|
|
|
|
internal bool LabelsAreStaggered
|
|
{
|
|
get { return (TestState(MajorStates.LabelsAreStaggered)); }
|
|
set { SetState(MajorStates.LabelsAreStaggered, value); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MaxLabelSize
|
|
|
|
internal Size[] MaxLabelSize
|
|
{
|
|
get { return (_MaxLabelSize); }
|
|
set { _MaxLabelSize = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region UpdateTickmarkTicks
|
|
|
|
internal void UpdateTickmarkTicks(Graphics g,
|
|
ChartAxis chartAxis, Rectangle bounds, TickmarkLayout layout)
|
|
{
|
|
TickmarkTick[] ticks = new TickmarkTick[layout.TickmarkEnd - layout.TickmarkStart];
|
|
|
|
CalculateBaseValue(chartAxis, layout);
|
|
|
|
if (ShowLabels == true)
|
|
{
|
|
TickmarkLabelVisualStyle lbstyle = EffectiveLabelStyle;
|
|
|
|
using (StringFormat sf = new StringFormat())
|
|
{
|
|
lbstyle.GetStringFormatFlags(sf);
|
|
|
|
if (lbstyle.MaxLineCount <= 1)
|
|
sf.FormatFlags |= StringFormatFlags.NoWrap;
|
|
|
|
int maxLabelWidth = lbstyle.MaxWidth < 0 ? 0 : lbstyle.MaxWidth;
|
|
|
|
float angle = GetLabelAngle();
|
|
|
|
int skip = (LabelSkip > 0 ? LabelSkip + 1 : 0);
|
|
|
|
for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
|
|
{
|
|
TickmarkTick tmi = new TickmarkTick();
|
|
|
|
tmi.Index = i;
|
|
|
|
SetTickValue(chartAxis, layout, lbstyle, tmi);
|
|
|
|
if ((tmi.Label != null) && (skip <= 0 || (tmi.LabelIndex) % skip == 0))
|
|
{
|
|
lbstyle.GetStringFormatFlags(sf);
|
|
|
|
tmi.TextSize = g.MeasureString(tmi.Label, lbstyle.Font, maxLabelWidth, sf);
|
|
|
|
if (tmi.TextSize.IsEmpty == false)
|
|
{
|
|
tmi.TextSize.Width++;
|
|
tmi.TextSize.Height++;
|
|
}
|
|
|
|
if (lbstyle.MaxLineCount > 1)
|
|
{
|
|
int lineHeight = (int)(Math.Ceiling(lbstyle.Font.GetHeight())) * lbstyle.MaxLineCount;
|
|
|
|
if (tmi.TextSize.Height > lineHeight)
|
|
tmi.TextSize.Height = lineHeight;
|
|
}
|
|
|
|
if (angle != 0)
|
|
{
|
|
double radians = MathHelper.ToRadians(angle);
|
|
|
|
tmi.LabelSize.Width = (int)(Math.Abs(tmi.TextSize.Width * Math.Cos(radians)) + Math.Abs(tmi.TextSize.Height * Math.Sin(radians)));
|
|
tmi.LabelSize.Height = (int)(Math.Abs(tmi.TextSize.Width * Math.Sin(radians)) + Math.Abs(tmi.TextSize.Height * Math.Cos(radians)));
|
|
}
|
|
else
|
|
{
|
|
tmi.LabelSize = tmi.TextSize.ToSize();
|
|
}
|
|
|
|
tmi.LabelVisible = true;
|
|
}
|
|
else
|
|
{
|
|
tmi.LabelVisible = false;
|
|
}
|
|
|
|
ticks[i - layout.TickmarkStart] = tmi;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = layout.TickmarkStart; i < layout.TickmarkEnd; i++)
|
|
{
|
|
TickmarkTick tmi = new TickmarkTick();
|
|
|
|
tmi.Index = i;
|
|
|
|
SetTickValue(chartAxis, layout, null, tmi);
|
|
|
|
ticks[i - layout.TickmarkStart] = tmi;
|
|
}
|
|
}
|
|
|
|
layout.Ticks = ticks;
|
|
}
|
|
|
|
#region CalculateBaseValue
|
|
|
|
private void CalculateBaseValue(ChartAxis axis, TickmarkLayout layout)
|
|
{
|
|
switch (axis.ScaleType)
|
|
{
|
|
case ScaleType.Qualitative:
|
|
int iminValue = (int)layout.MinValue;
|
|
int ivalue = (int)Math.Floor(iminValue / layout.GridSpacing);
|
|
|
|
layout.BaseValue = (int)(ivalue * layout.GridSpacing);
|
|
break;
|
|
|
|
case ScaleType.DateTime:
|
|
layout.BaseValue = layout.MinValue;
|
|
break;
|
|
|
|
default:
|
|
Type otype = layout.MinValue.GetType();
|
|
|
|
double dminValue = Convert.ToDouble(layout.MinValue);
|
|
double n = dminValue < 0 ? -1 : 1;
|
|
double dvalue = Math.Floor(Math.Abs(dminValue) / layout.MajorSpacing);
|
|
|
|
layout.BaseValue = Convert.ChangeType((int)dvalue * layout.MajorSpacing * n, otype);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SetTickValue
|
|
|
|
private void SetTickValue(ChartAxis chartAxis,
|
|
TickmarkLayout layout, TickmarkLabelVisualStyle lbstyle, TickmarkTick tmi)
|
|
{
|
|
tmi.LabelIndex = -1;
|
|
|
|
switch (chartAxis.ScaleType)
|
|
{
|
|
case ScaleType.Qualitative:
|
|
tmi.Value = (int)layout.BaseValue + tmi.Index;
|
|
|
|
if (ShowLabels == true)
|
|
{
|
|
int i = (int)tmi.Value;
|
|
|
|
if ((uint)i < chartAxis.QualitativeValues.Count)
|
|
{
|
|
object value = chartAxis.QualitativeValues[i];
|
|
|
|
if (string.IsNullOrEmpty(lbstyle.TextFormat) == false)
|
|
tmi.Label = string.Format(lbstyle.TextFormat, value);
|
|
else
|
|
tmi.Label = value.ToString();
|
|
|
|
tmi.LabelIndex = i;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ScaleType.DateTime:
|
|
tmi.Value = chartAxis.GetDateTime((DateTime)layout.BaseValue, tmi.Index * layout.MajorSpacing);
|
|
|
|
if (ShowLabels == true)
|
|
{
|
|
DateTime dt = (DateTime)tmi.Value;
|
|
|
|
if (string.IsNullOrEmpty(lbstyle.TextFormat) == false)
|
|
tmi.Label = dt.ToString(lbstyle.TextFormat);
|
|
else
|
|
tmi.Label = chartAxis.GetDateTimeLabel(dt);
|
|
|
|
tmi.LabelIndex = tmi.Index;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Type otype = layout.BaseValue.GetType();
|
|
double dbase = Convert.ToDouble(layout.BaseValue);
|
|
|
|
tmi.Value = dbase + (tmi.Index * layout.MajorSpacing);
|
|
|
|
if (ShowLabels == true)
|
|
{
|
|
if (string.IsNullOrEmpty(lbstyle.TextFormat) == false)
|
|
tmi.Label = String.Format("{0:" + lbstyle.TextFormat + "}", tmi.Value);
|
|
else
|
|
tmi.Label = tmi.Value.ToString();
|
|
|
|
tmi.LabelIndex = tmi.Index;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (ShowLabels == true && tmi.LabelIndex >= 0)
|
|
{
|
|
ChartControl chartControl = ChartControl;
|
|
|
|
chartControl.DoGetTickmarkLabelEvent(chartAxis, tmi.Value, ref tmi.Label, ref tmi.LabelColor);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetTickmarkValue
|
|
|
|
internal double GetTickmarkValue(ChartAxis chartAxis, TickmarkTick tick)
|
|
{
|
|
switch (chartAxis.ScaleType)
|
|
{
|
|
case ScaleType.DateTime:
|
|
return (chartAxis.GetDateTimeValue((DateTime)tick.Value));
|
|
|
|
case ScaleType.Qualitative:
|
|
return ((int)tick.Value + TickmarkLayout.MajorSpacing / 2);
|
|
|
|
default:
|
|
return (Convert.ToDouble(tick.Value) + TickmarkLayout.MajorSpacing / 2);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetLabelAngle
|
|
|
|
protected virtual float GetLabelAngle()
|
|
{
|
|
float angle = LabelAngle % 180;
|
|
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
|
|
|
|
if (axisAlignment == AxisAlignment.Near)
|
|
{
|
|
if (angle < -90)
|
|
angle += 180;
|
|
}
|
|
else
|
|
{
|
|
if (angle > 0)
|
|
angle -= 180;
|
|
}
|
|
|
|
return (angle);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetStartIndex
|
|
|
|
internal virtual int GetStartIndex()
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
internal int GetStartIndexEx(ScrollBarLite srollBar)
|
|
{
|
|
int offset = srollBar.Value;
|
|
|
|
if (offset <= 0)
|
|
return (0);
|
|
|
|
int range = TickmarkLayout.MajorCount - 1;
|
|
int smax = srollBar.Maximum;
|
|
|
|
double dx = (((double)(offset * range)) / smax);
|
|
|
|
return (int)(dx);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ArrangeTickmarks
|
|
|
|
protected virtual void ArrangeTickmarks()
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ArrangeOverride
|
|
|
|
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
ChartAxis axis = Parent as ChartAxis;
|
|
ChartXy chartXy = axis.Parent as ChartXy;
|
|
|
|
if (TickmarkLayout.TickmarkStart != GetStartIndex())
|
|
{
|
|
Rectangle bounds = layoutInfo.LayoutBounds;
|
|
layoutInfo.LayoutBounds = chartXy.BoundsRelative;
|
|
|
|
chartXy.Measure(layoutInfo);
|
|
chartXy.Arrange(layoutInfo);
|
|
|
|
layoutInfo.LayoutBounds = bounds;
|
|
|
|
if (layoutInfo.LayoutBoundsAdjusted == true)
|
|
{
|
|
layoutInfo.LayoutBoundsAdjusted = false;
|
|
|
|
chartXy.InvalidateRender();
|
|
}
|
|
}
|
|
|
|
ArrangeTickmarks();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetTotalLabelHeight
|
|
|
|
internal int GetTotalLabelHeight()
|
|
{
|
|
return (GetTotalLabelSize().Height);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetTotalLabelWidth
|
|
|
|
internal int GetTotalLabelWidth()
|
|
{
|
|
return (GetTotalLabelSize().Width);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetTotalLabelSize
|
|
|
|
internal Size GetTotalLabelSize()
|
|
{
|
|
_MaxLabelSize = new Size[2];
|
|
_MaxLabelSize[0] = Size.Empty;
|
|
_MaxLabelSize[1] = Size.Empty;
|
|
|
|
TickmarkTick lastTmi = null;
|
|
|
|
LabelsAreStaggered = false;
|
|
|
|
float angle = GetLabelAngle();
|
|
|
|
int minLabelGap = Dpi.Width(MinLabelGap);
|
|
|
|
foreach (TickmarkTick tmi in TickmarkLayout.Ticks)
|
|
{
|
|
if (tmi.LabelVisible == true && tmi.LabelPoint.IsEmpty == false && tmi.LabelIndex >= 0)
|
|
{
|
|
int n = tmi.Index % 2;
|
|
|
|
if (tmi.LabelSize.Height > _MaxLabelSize[n].Height)
|
|
_MaxLabelSize[n].Height = tmi.LabelSize.Height;
|
|
|
|
if (tmi.LabelSize.Width > _MaxLabelSize[n].Width)
|
|
_MaxLabelSize[n].Width = tmi.LabelSize.Width;
|
|
|
|
if (StaggerLabels == true && LabelsAreStaggered == false)
|
|
{
|
|
if (lastTmi != null)
|
|
{
|
|
if (AxisOrientation == AxisOrientation.X)
|
|
{
|
|
if (angle % 180 == 0)
|
|
{
|
|
if (lastTmi.LabelPoint.X +
|
|
lastTmi.LabelSize.Width + minLabelGap > tmi.LabelPoint.X)
|
|
{
|
|
LabelsAreStaggered = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((angle + 90) % 180 == 0)
|
|
{
|
|
if (tmi.LabelPoint.Y +
|
|
tmi.LabelSize.Height + minLabelGap > lastTmi.LabelPoint.Y)
|
|
{
|
|
LabelsAreStaggered = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lastTmi = tmi;
|
|
}
|
|
}
|
|
}
|
|
|
|
Size maxSize = Size.Empty;
|
|
|
|
if (LabelsAreStaggered == true)
|
|
{
|
|
if (AxisOrientation == AxisOrientation.X)
|
|
maxSize.Height = _MaxLabelSize[0].Height + _MaxLabelSize[1].Height;
|
|
else
|
|
maxSize.Width = _MaxLabelSize[0].Width + _MaxLabelSize[1].Width;
|
|
}
|
|
else
|
|
{
|
|
maxSize.Height = Math.Max(_MaxLabelSize[0].Height, _MaxLabelSize[1].Height);
|
|
maxSize.Width = Math.Max(_MaxLabelSize[0].Width, _MaxLabelSize[1].Width);
|
|
}
|
|
|
|
return (maxSize);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Style handling
|
|
|
|
#region ApplyStyles
|
|
|
|
public override void ApplyStyles(BaseVisualStyle style)
|
|
{
|
|
base.ApplyStyles(style);
|
|
|
|
TickmarkLabelVisualStyle lstyle = style as TickmarkLabelVisualStyle;
|
|
|
|
if (lstyle != null)
|
|
{
|
|
ApplyParentStyles(lstyle, Parent as ChartContainer);
|
|
|
|
lstyle.ApplyStyle(LabelVisualStyle);
|
|
|
|
if (lstyle.Font == null)
|
|
lstyle.Font = SystemFonts.DefaultFont;
|
|
|
|
if (lstyle.TextColor.IsEmpty)
|
|
lstyle.TextColor = Color.Black;
|
|
}
|
|
}
|
|
|
|
#region ApplyParentStyles
|
|
|
|
private void ApplyParentStyles(
|
|
TickmarkLabelVisualStyle pstyle, ChartContainer item)
|
|
{
|
|
if (item != null)
|
|
{
|
|
ApplyParentStyles(pstyle, item.Parent as ChartContainer);
|
|
}
|
|
else
|
|
{
|
|
pstyle.ApplyStyle(ChartControl.BaseVisualStyles.TickmarkLabelVisualStyle);
|
|
pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.TickmarkLabelVisualStyle);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ClearEffectiveStyles
|
|
|
|
protected override void ClearEffectiveStyles()
|
|
{
|
|
base.ClearEffectiveStyles();
|
|
|
|
_EffectiveLabelStyle.InvalidateStyle();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Copy/CopyTo
|
|
|
|
/// <summary>
|
|
/// Copies the chart element to the given "copy".
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
MajorTickmarks c = copy as MajorTickmarks;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyTo(c);
|
|
|
|
c.AutoTickmarkLayout = AutoTickmarkLayout;
|
|
c.LabelAngle = LabelAngle;
|
|
|
|
c.LabelVisualStyle = (_LabelVisualStyle != null) ? LabelVisualStyle.Copy() : null;
|
|
|
|
c.MinLabelGap = MinLabelGap;
|
|
c.ShowLabels = ShowLabels;
|
|
c.StaggerLabels = StaggerLabels;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSerialData
|
|
|
|
internal override SerialElementCollection GetSerialData(string serialName)
|
|
{
|
|
SerialElementCollection sec = new SerialElementCollection();
|
|
|
|
if (serialName != null)
|
|
{
|
|
if (serialName.Equals("") == true)
|
|
serialName = "MajorTickmarks";
|
|
|
|
sec.AddStartElement(serialName);
|
|
}
|
|
|
|
sec.AddValue("AutoTickmarkLayout", AutoTickmarkLayout, true);
|
|
sec.AddValue("LabelAngle", LabelAngle, 0f);
|
|
sec.AddValue("LabelSkip", LabelSkip, 0);
|
|
|
|
if (_LabelVisualStyle != null && _LabelVisualStyle.IsEmpty == false)
|
|
sec.AddElement(_LabelVisualStyle.GetSerialData("LabelVisualStyle"));
|
|
|
|
sec.AddValue("MinLabelGap", MinLabelGap, 4);
|
|
sec.AddValue("ShowLabels", ShowLabels, true);
|
|
sec.AddValue("StaggerLabels", StaggerLabels, true);
|
|
|
|
sec.AddElement(base.GetSerialData(null));
|
|
|
|
if (serialName != null)
|
|
sec.AddEndElement(serialName);
|
|
|
|
return (sec);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PutSerialData
|
|
|
|
#region ProcessValue
|
|
|
|
internal override void ProcessValue(SerialElement se)
|
|
{
|
|
switch (se.Name)
|
|
{
|
|
case "AutoTickmarkLayout":
|
|
AutoTickmarkLayout = bool.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "LabelAngle":
|
|
LabelAngle = float.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "LabelSkip":
|
|
LabelSkip = int.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "MinLabelGap":
|
|
MinLabelGap = int.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "ShowLabels":
|
|
ShowLabels = bool.Parse(se.StringValue);
|
|
break;
|
|
|
|
case "StaggerLabels":
|
|
StaggerLabels = 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 "LabelVisualStyle":
|
|
sec.PutSerialData(LabelVisualStyle);
|
|
break;
|
|
|
|
default:
|
|
base.ProcessCollection(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MajorStates
|
|
|
|
[Flags]
|
|
protected enum MajorStates : uint
|
|
{
|
|
AutoLayout = (1U << 0),
|
|
ShowLabels = (1U << 1),
|
|
StaggerLabels = (1U << 2),
|
|
|
|
//--------
|
|
|
|
LabelsAreStaggered = (1U << 3),
|
|
}
|
|
|
|
#region TestState
|
|
|
|
protected bool TestState(MajorStates state)
|
|
{
|
|
return ((_MajorStates & state) == state);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SetState
|
|
|
|
protected void SetState(MajorStates state, bool value)
|
|
{
|
|
if (value == true)
|
|
_MajorStates |= state;
|
|
else
|
|
_MajorStates &= ~state;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region IDisposable
|
|
|
|
public override void Dispose()
|
|
{
|
|
LabelVisualStyle = null;
|
|
|
|
base.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MinorTickmarks
|
|
|
|
#region MinorTickmarksX
|
|
|
|
/// <summary>
|
|
/// Represents a Minor tickmark on the X-Axis.
|
|
/// </summary>
|
|
public class MinorTickmarksX : MinorTickmarks
|
|
{
|
|
public MinorTickmarksX()
|
|
: base(AxisOrientation.X)
|
|
{
|
|
}
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
Rectangle bounds = Rectangle.Empty;
|
|
|
|
if (TickmarkCount > 0)
|
|
{
|
|
bounds = layoutInfo.LayoutBounds;
|
|
bounds.Height = Dpi.Height(GetMaxTickmarkLength(chartAxis, false));
|
|
}
|
|
|
|
BoundsRelative = bounds;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
TickmarkTick[] ticks = TickmarkLayout.Ticks;
|
|
|
|
if (ticks.Length > 1)
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
ChartTickmarkVisualStyle tstyle = EffectiveStyle;
|
|
|
|
if (CanRenderTickmarks(tstyle) == true)
|
|
{
|
|
Graphics g = renderInfo.Graphics;
|
|
Point pt = GetLocalAdjustedPoint(Point.Empty);
|
|
|
|
AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
|
|
|
|
using (Pen pen = new Pen(tstyle.TickmarkColor, Dpi.Width(tstyle.TickmarkThickness)))
|
|
{
|
|
int tlen = Dpi.Width(tstyle.TickmarkLength);
|
|
|
|
if ((tstyle.TickmarkAlignment == LineAlignment.Center) ||
|
|
(axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Near) ||
|
|
(axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Far))
|
|
{
|
|
// Bottom
|
|
|
|
RenderMarks(g, pen, chartAxis, pt, ticks, 0, tlen - 1);
|
|
}
|
|
|
|
if ((tstyle.TickmarkAlignment == LineAlignment.Center) ||
|
|
(axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Far) ||
|
|
(axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Near))
|
|
{
|
|
// Top
|
|
|
|
ChartXy chartXy = chartAxis.Parent as ChartXy;
|
|
|
|
if (axisAlignment == AxisAlignment.Near)
|
|
{
|
|
int n = 1;
|
|
|
|
if (chartAxis.EdgeAxis == true)
|
|
n = chartXy.GetScBorderThickness(XyAlignment.Bottom);
|
|
|
|
RenderMarks(g, pen, chartAxis, pt, ticks, -(n + tlen), tlen - 1);
|
|
}
|
|
else
|
|
{
|
|
int n = 0;
|
|
|
|
RenderMarks(g, pen, chartAxis, pt, ticks, -(n + tlen), tlen - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region CanRenderTickmarks
|
|
|
|
protected override bool CanRenderTickmarks(ChartTickmarkVisualStyle tstyle)
|
|
{
|
|
if (TickmarkCount <= 0)
|
|
return (false);
|
|
|
|
return (base.CanRenderTickmarks(tstyle));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderMarks
|
|
|
|
private void RenderMarks(Graphics g,
|
|
Pen pen, ChartAxis chartAxis, Point pt, TickmarkTick[] ticks, int voff, int len)
|
|
{
|
|
ChartAxis axis = Parent as ChartAxis;
|
|
|
|
int minorTickCount = TickmarkLayout.MinorCount;
|
|
|
|
for (int i = 0; i < ticks.Length - 1; i++)
|
|
{
|
|
TickmarkTick tick = ticks[i];
|
|
|
|
Point pt1 = tick.TickPoint;
|
|
pt1.Y += (pt.Y + voff);
|
|
|
|
Point pt2 = pt1;
|
|
pt2.Y += len;
|
|
|
|
double dx = (double)(ticks[i + 1].TickPoint.X - tick.TickPoint.X) / (minorTickCount + 1);
|
|
double ddx = dx;
|
|
|
|
for (int j = 0; j < minorTickCount; j++)
|
|
{
|
|
pt1.X = pt.X + (int)(tick.TickPoint.X + ddx);
|
|
pt2.X = pt1.X;
|
|
|
|
ddx += dx;
|
|
|
|
if (pt1.X >= chartAxis.AxisLineBounds.X - ScrollOffset.X &&
|
|
pt1.X < chartAxis.AxisLineBounds.Right - ScrollOffset.X)
|
|
{
|
|
if (pt1.Equals(pt2) == true)
|
|
pt1.Y--;
|
|
|
|
g.DrawLine(pen, pt1, pt2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Copy/CopyTo
|
|
|
|
/// <summary>
|
|
/// Creates a copy of the chart element.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override ChartVisualElement Copy()
|
|
{
|
|
MinorTickmarksX copy = new MinorTickmarksX();
|
|
|
|
CopyTo(copy);
|
|
|
|
return (copy);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies the chart element to the given "copy".
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
MinorTickmarksX c = copy as MinorTickmarksX;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyTo(c);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinorTickmarksY
|
|
|
|
/// <summary>
|
|
/// Represents a Minor tickmark on the Y-Axis.
|
|
/// </summary>
|
|
public class MinorTickmarksY : MinorTickmarks
|
|
{
|
|
public MinorTickmarksY()
|
|
: base(AxisOrientation.Y)
|
|
{
|
|
}
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
|
|
Rectangle bounds = Rectangle.Empty;
|
|
|
|
if (TickmarkCount > 0)
|
|
{
|
|
bounds = layoutInfo.LayoutBounds;
|
|
bounds.Width = Dpi.Width(GetMaxTickmarkLength(chartAxis, false));
|
|
|
|
if (chartAxis.AxisAlignment == AxisAlignment.Near)
|
|
bounds.X = layoutInfo.LayoutBounds.Right - bounds.Width;
|
|
}
|
|
|
|
BoundsRelative = bounds;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
TickmarkTick[] ticks = TickmarkLayout.Ticks;
|
|
|
|
if (ticks.Length > 1)
|
|
{
|
|
ChartAxis chartAxis = Parent as ChartAxis;
|
|
ChartTickmarkVisualStyle tstyle = EffectiveStyle;
|
|
|
|
if (CanRenderTickmarks(tstyle) == true)
|
|
{
|
|
Graphics g = renderInfo.Graphics;
|
|
|
|
AxisAlignment axisAlignment = chartAxis.GetAxisAlignment();
|
|
|
|
using (Pen pen = new Pen(tstyle.TickmarkColor, Dpi.Height(tstyle.TickmarkThickness)))
|
|
{
|
|
int tlen = Dpi.Height(tstyle.TickmarkLength);
|
|
|
|
if (tstyle.TickmarkAlignment == LineAlignment.Center ||
|
|
(axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Near) ||
|
|
(axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Far))
|
|
{
|
|
// Right
|
|
|
|
RenderMarks(g, pen, chartAxis, ticks, 0, tlen - 1);
|
|
}
|
|
|
|
if (tstyle.TickmarkAlignment == LineAlignment.Center ||
|
|
(axisAlignment == AxisAlignment.Far && tstyle.TickmarkAlignment == LineAlignment.Far) ||
|
|
(axisAlignment == AxisAlignment.Near && tstyle.TickmarkAlignment == LineAlignment.Near))
|
|
{
|
|
// Left
|
|
|
|
ChartXy chartXy = chartAxis.Parent as ChartXy;
|
|
|
|
if (axisAlignment == AxisAlignment.Near)
|
|
{
|
|
int n = 1;
|
|
|
|
if (chartAxis.EdgeAxis == true)
|
|
n = chartXy.GetScBorderThickness(XyAlignment.Right);
|
|
|
|
RenderMarks(g, pen, chartAxis, ticks, -(n + tlen), tlen - 1);
|
|
}
|
|
else
|
|
{
|
|
int n = 1;
|
|
|
|
RenderMarks(g, pen, chartAxis, ticks, -(n + tlen), tlen);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region CanRenderTickmarks
|
|
|
|
protected override bool CanRenderTickmarks(ChartTickmarkVisualStyle tstyle)
|
|
{
|
|
if (TickmarkCount <= 0)
|
|
return (false);
|
|
|
|
return (base.CanRenderTickmarks(tstyle));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderMarks
|
|
|
|
private void RenderMarks(Graphics g,
|
|
Pen pen, ChartAxis chartAxis, TickmarkTick[] ticks, int hoff, int len)
|
|
{
|
|
ChartAxis axis = Parent as ChartAxis;
|
|
|
|
int minorTickCount = TickmarkLayout.MinorCount;
|
|
|
|
Point pt = GetLocalAdjustedPoint(Point.Empty);
|
|
|
|
for (int i = 0; i < ticks.Length - 1; i++)
|
|
{
|
|
TickmarkTick tick = ticks[i];
|
|
|
|
Point pt1 = tick.TickPoint;
|
|
pt1.X += (pt.X + hoff);
|
|
|
|
Point pt2 = pt1;
|
|
pt2.X += len;
|
|
|
|
double dy = (double)(ticks[i + 1].TickPoint.Y - tick.TickPoint.Y) / (minorTickCount + 1);
|
|
double ddy = dy;
|
|
|
|
for (int j = 0; j < minorTickCount; j++)
|
|
{
|
|
pt1.Y = pt.Y + (int)(tick.TickPoint.Y + ddy);
|
|
pt2.Y = pt1.Y;
|
|
|
|
ddy += dy;
|
|
|
|
if (pt1.Y >= chartAxis.AxisLineBounds.Y - ScrollOffset.Y &&
|
|
pt1.Y < chartAxis.AxisLineBounds.Bottom - ScrollOffset.Y)
|
|
{
|
|
g.DrawLine(pen, pt1, pt2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Copy/CopyTo
|
|
|
|
/// <summary>
|
|
/// Creates a copy of the chart element.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override ChartVisualElement Copy()
|
|
{
|
|
MinorTickmarksY copy = new MinorTickmarksY();
|
|
|
|
CopyTo(copy);
|
|
|
|
return (copy);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies the chart element to the given "copy".
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
MinorTickmarksY c = copy as MinorTickmarksY;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyTo(c);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinorTickmarks
|
|
|
|
/// <summary>
|
|
/// Represents a Minor tickmark.
|
|
/// </summary>
|
|
public class MinorTickmarks : ChartTickmarks
|
|
{
|
|
#region Private variables
|
|
|
|
private int _TickmarkCount = 3;
|
|
|
|
#endregion
|
|
|
|
public MinorTickmarks(AxisOrientation orientation)
|
|
: base(orientation)
|
|
{
|
|
}
|
|
|
|
#region Public properties
|
|
|
|
#region TickmarkCount
|
|
|
|
///<summary>
|
|
/// Gets or sets the number of Tickmarks presented between Majortickmarks.
|
|
///</summary>
|
|
[DefaultValue(3), Category("Layout")]
|
|
[Description("Indicates the number of Tickmarks presented between Majortickmarks.")]
|
|
public int TickmarkCount
|
|
{
|
|
get { return (_TickmarkCount); }
|
|
|
|
set
|
|
{
|
|
if (value != _TickmarkCount)
|
|
{
|
|
_TickmarkCount = value;
|
|
|
|
OnPropertyChangedEx("TickmarkCount", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region CopyTo
|
|
|
|
/// <summary>
|
|
/// Copies the chart element to the given "copy".
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
MinorTickmarks c = copy as MinorTickmarks;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyTo(c);
|
|
|
|
c.TickmarkCount = TickmarkCount;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSerialData
|
|
|
|
internal override SerialElementCollection GetSerialData(string serialName)
|
|
{
|
|
SerialElementCollection sec = new SerialElementCollection();
|
|
|
|
if (serialName != null)
|
|
{
|
|
if (serialName.Equals("") == true)
|
|
serialName = "MinorTickmarks";
|
|
|
|
sec.AddStartElement(serialName);
|
|
}
|
|
|
|
sec.AddElement(base.GetSerialData(null));
|
|
|
|
sec.AddValue("TickmarkCount", TickmarkCount, 3);
|
|
|
|
if (serialName != null)
|
|
sec.AddEndElement(serialName);
|
|
|
|
return (sec);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PutSerialData
|
|
|
|
#region ProcessValue
|
|
|
|
internal override void ProcessValue(SerialElement se)
|
|
{
|
|
switch (se.Name)
|
|
{
|
|
case "TickmarkCount":
|
|
TickmarkCount = int.Parse(se.StringValue);
|
|
break;
|
|
|
|
default:
|
|
base.ProcessValue(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ChartTickmarks
|
|
|
|
[TypeConverter(typeof(BlankExpandableObjectConverter))]
|
|
public abstract class ChartTickmarks : ChartVisualElement
|
|
{
|
|
#region Private variables
|
|
|
|
private States _States;
|
|
|
|
private AxisOrientation _AxisOrientation;
|
|
|
|
private Rectangle _TickmarkBounds;
|
|
private TickmarkLayout _TickmarkLayout;
|
|
|
|
private ChartTickmarkVisualStyle _ChartTickmarkVisualStyle;
|
|
private EffectiveStyle<ChartTickmarkVisualStyle> _EffectiveStyle;
|
|
|
|
#endregion
|
|
|
|
public ChartTickmarks(AxisOrientation orientation)
|
|
{
|
|
_AxisOrientation = orientation;
|
|
|
|
InitDefaultStates();
|
|
|
|
_EffectiveStyle = new EffectiveStyle<ChartTickmarkVisualStyle>(this);
|
|
|
|
Visible = true;
|
|
}
|
|
|
|
#region InitDefaultStates
|
|
|
|
private void InitDefaultStates()
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
#region AxisOrientation
|
|
|
|
///<summary>
|
|
/// Gets the axis orientation (X/Y).
|
|
///</summary>
|
|
[Browsable(false)]
|
|
[Description("Indicates the axis orientation (X/Y).")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public AxisOrientation AxisOrientation
|
|
{
|
|
get { return (_AxisOrientation); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EffectiveStyle
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the Tickmark's Effective (cached, composite) style.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[Description("Indicates a reference to the Tickmark's Effective (cached, composite) style.")]
|
|
public ChartTickmarkVisualStyle EffectiveStyle
|
|
{
|
|
get { return (_EffectiveStyle.Style); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ChartTickmarkVisualStyle
|
|
|
|
/// <summary>
|
|
/// Gets or sets the visual styles for the Tickmarks.
|
|
/// </summary>
|
|
[Category("Style")]
|
|
[Description("Indicates the visual styles for the Tickmarks.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public ChartTickmarkVisualStyle ChartTickmarkVisualStyle
|
|
{
|
|
get
|
|
{
|
|
if (_ChartTickmarkVisualStyle == null)
|
|
{
|
|
_ChartTickmarkVisualStyle = new ChartTickmarkVisualStyle();
|
|
|
|
StyleVisualChangeHandler(null, _ChartTickmarkVisualStyle);
|
|
}
|
|
|
|
return (_ChartTickmarkVisualStyle);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_ChartTickmarkVisualStyle != value)
|
|
{
|
|
ChartTickmarkVisualStyle oldValue = _ChartTickmarkVisualStyle;
|
|
|
|
_ChartTickmarkVisualStyle = value;
|
|
|
|
OnVisualStyleChanged("ChartTickmarkVisualStyle", oldValue, value);
|
|
|
|
if (oldValue != null)
|
|
oldValue.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Internal properties
|
|
|
|
#region TickmarkBounds
|
|
|
|
internal Rectangle TickmarkBounds
|
|
{
|
|
get { return (_TickmarkBounds); }
|
|
set { _TickmarkBounds = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TickmarkLayout
|
|
|
|
internal TickmarkLayout TickmarkLayout
|
|
{
|
|
get { return (_TickmarkLayout); }
|
|
set { _TickmarkLayout = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ArrangeOverride
|
|
|
|
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CanRenderTickmarks
|
|
|
|
protected virtual bool CanRenderTickmarks(ChartTickmarkVisualStyle tstyle)
|
|
{
|
|
if (Visible == false || tstyle.TickmarkThickness <= 0 || tstyle.TickmarkColor.IsEmpty == true)
|
|
return (false);
|
|
|
|
return (true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Render
|
|
|
|
internal override void Render(ChartRenderInfo renderInfo)
|
|
{
|
|
if (Displayed == true)
|
|
RenderOverride(renderInfo);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetMaxTickmarkLength
|
|
|
|
internal int GetMaxTickmarkLength(ChartAxis chartAxis, bool inner)
|
|
{
|
|
int length = (inner == false) ? 4 : 0;
|
|
|
|
if (Visible == true)
|
|
{
|
|
ChartTickmarkVisualStyle tstyle = EffectiveStyle;
|
|
|
|
if (chartAxis.EdgeAxis == false)
|
|
{
|
|
length = tstyle.TickmarkLength;
|
|
}
|
|
else
|
|
{
|
|
switch (tstyle.TickmarkAlignment)
|
|
{
|
|
case LineAlignment.Near:
|
|
if (inner == true)
|
|
length = tstyle.TickmarkLength;
|
|
break;
|
|
|
|
case LineAlignment.Center:
|
|
length = tstyle.TickmarkLength;
|
|
break;
|
|
|
|
default:
|
|
if (inner == false)
|
|
length = tstyle.TickmarkLength;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (length);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetLocalAdjustedBounds
|
|
|
|
internal Rectangle GetLocalAdjustedBounds(Rectangle bounds)
|
|
{
|
|
bounds.Location = GetLocalAdjustedPoint(bounds.Location);
|
|
|
|
return (bounds);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetLocalAdjustedPoint
|
|
|
|
internal Point GetLocalAdjustedPoint(Point pt)
|
|
{
|
|
ChartAxis axis = Parent as ChartAxis;
|
|
ChartXy chartXy = axis.Parent as ChartXy;
|
|
|
|
if (chartXy != null)
|
|
{
|
|
pt.X -= ScrollOffset.X;
|
|
pt.Y -= ScrollOffset.Y;
|
|
|
|
if (_AxisOrientation == AxisOrientation.X)
|
|
{
|
|
pt.X -= chartXy.HScrollOffset;
|
|
}
|
|
else
|
|
{
|
|
if (chartXy.VScrollBar.Inverted == true)
|
|
pt.Y += chartXy.VScrollOffset;
|
|
else
|
|
pt.Y -= chartXy.VScrollOffset;
|
|
}
|
|
}
|
|
|
|
return (pt);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Style handling
|
|
|
|
#region ApplyStyles
|
|
|
|
public override void ApplyStyles(BaseVisualStyle style)
|
|
{
|
|
ChartTickmarkVisualStyle tstyle = style as ChartTickmarkVisualStyle;
|
|
|
|
if (tstyle != null)
|
|
{
|
|
ApplyParentStyles(tstyle, Parent as ChartContainer);
|
|
|
|
tstyle.ApplyStyle(ChartTickmarkVisualStyle);
|
|
|
|
if (tstyle.TickmarkColor.IsEmpty == true)
|
|
tstyle.TickmarkColor = Color.Gray;
|
|
|
|
if (tstyle.TickmarkThickness < 0)
|
|
tstyle.TickmarkThickness = 1;
|
|
|
|
if (tstyle.TickmarkLength < 0)
|
|
{
|
|
if (this is MajorTickmarks)
|
|
tstyle.TickmarkLength = 5;
|
|
else
|
|
tstyle.TickmarkLength = 2;
|
|
}
|
|
|
|
if (tstyle.TickmarkAlignment == LineAlignment.NotSet)
|
|
tstyle.TickmarkAlignment = LineAlignment.Far;
|
|
}
|
|
}
|
|
|
|
#region ApplyParentStyles
|
|
|
|
private void ApplyParentStyles(
|
|
ChartTickmarkVisualStyle pstyle, ChartContainer item)
|
|
{
|
|
if (item != null)
|
|
{
|
|
ApplyParentStyles(pstyle, item.Parent as ChartContainer);
|
|
|
|
if (item is ChartPanel)
|
|
{
|
|
pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.ChartTickmarkVisualStyle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pstyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartTickmarkVisualStyle);
|
|
pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartTickmarkVisualStyle);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region InvalidateStyle
|
|
|
|
///<summary>
|
|
///Invalidate the cached Style definition
|
|
///</summary>
|
|
public void InvalidateStyle()
|
|
{
|
|
ClearEffectiveStyles();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ClearEffectiveStyles
|
|
|
|
protected override void ClearEffectiveStyles()
|
|
{
|
|
if (_EffectiveStyle.InvalidateStyle() == true)
|
|
InvalidateLayout();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region CopyTo
|
|
|
|
/// <summary>
|
|
/// Copies the chart element to the given "copy".
|
|
/// </summary>
|
|
/// <param name="copy"></param>
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
ChartTickmarks c = copy as ChartTickmarks;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyTo(c);
|
|
|
|
c.ChartTickmarkVisualStyle =
|
|
(_ChartTickmarkVisualStyle != null) ? ChartTickmarkVisualStyle.Copy() : null;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSerialData
|
|
|
|
internal override SerialElementCollection GetSerialData(string serialName)
|
|
{
|
|
SerialElementCollection sec = new SerialElementCollection();
|
|
|
|
if (serialName != null)
|
|
{
|
|
if (serialName.Equals("") == true)
|
|
serialName = "ChartTickmarks";
|
|
|
|
sec.AddStartElement(serialName);
|
|
}
|
|
|
|
if (_ChartTickmarkVisualStyle != null && _ChartTickmarkVisualStyle.IsEmpty == false)
|
|
sec.AddElement(_ChartTickmarkVisualStyle.GetSerialData("ChartTickmarkVisualStyle"));
|
|
|
|
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 "ChartTickmarkVisualStyle":
|
|
sec.PutSerialData(ChartTickmarkVisualStyle);
|
|
break;
|
|
|
|
default:
|
|
base.ProcessCollection(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region States
|
|
|
|
[Flags]
|
|
protected enum States : uint
|
|
{
|
|
}
|
|
|
|
#region TestState
|
|
|
|
protected bool TestState(States state)
|
|
{
|
|
return ((_States & state) == state);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SetState
|
|
|
|
protected void SetState(States state, bool value)
|
|
{
|
|
if (value == true)
|
|
_States |= state;
|
|
else
|
|
_States &= ~state;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
}
|