2047 lines
64 KiB
C#
2047 lines
64 KiB
C#
|
//-------------------------------------------------------------
|
|||
|
// <copyright company=<3D>Microsoft Corporation<6F>>
|
|||
|
// Copyright <20> Microsoft Corporation. All Rights Reserved.
|
|||
|
// </copyright>
|
|||
|
//-------------------------------------------------------------
|
|||
|
// @owner=alexgor, deliant
|
|||
|
//=================================================================
|
|||
|
// File: GridTickMarks.cs
|
|||
|
//
|
|||
|
// Namespace: DataVisualization.Charting
|
|||
|
//
|
|||
|
// Classes: TickMark, Grid
|
|||
|
//
|
|||
|
// Purpose: Axis tick marks and grid lines a very similar chart
|
|||
|
// elements and most of the functionality is located
|
|||
|
// in the Grid class. TickMark class is derived from
|
|||
|
// the Grid class and provides tick mark specific
|
|||
|
// functionality.
|
|||
|
//
|
|||
|
// Reviewed: AG - Jul 31, 2002
|
|||
|
// AG - Microsoft 14, 2007
|
|||
|
//
|
|||
|
//===================================================================
|
|||
|
|
|||
|
#region Used namespaces
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Specialized;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.ComponentModel;
|
|||
|
using System.ComponentModel.Design;
|
|||
|
using System.Data;
|
|||
|
using System.Drawing;
|
|||
|
using System.Drawing.Design;
|
|||
|
using System.Drawing.Drawing2D;
|
|||
|
|
|||
|
#if Microsoft_CONTROL
|
|||
|
using System.Windows.Forms.DataVisualization.Charting;
|
|||
|
using System.Windows.Forms.DataVisualization.Charting.Data;
|
|||
|
using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
|
|||
|
using System.Windows.Forms.DataVisualization.Charting.Utilities;
|
|||
|
using System.Windows.Forms.DataVisualization.Charting.Borders3D;
|
|||
|
#else
|
|||
|
using System.Web;
|
|||
|
using System.Web.UI;
|
|||
|
using System.Web.UI.DataVisualization.Charting;
|
|||
|
using System.Web.UI.DataVisualization.Charting.Data;
|
|||
|
using System.Web.UI.DataVisualization.Charting.Utilities;
|
|||
|
using System.Web.UI.DataVisualization.Charting.ChartTypes;
|
|||
|
#endif
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#if Microsoft_CONTROL
|
|||
|
namespace System.Windows.Forms.DataVisualization.Charting
|
|||
|
#else
|
|||
|
namespace System.Web.UI.DataVisualization.Charting
|
|||
|
#endif
|
|||
|
|
|||
|
{
|
|||
|
#region Tick marks style enumeration
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// An enumeration of tick mark styles.
|
|||
|
/// </summary>
|
|||
|
public enum TickMarkStyle
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Tickmarks are disabled.
|
|||
|
/// </summary>
|
|||
|
None,
|
|||
|
/// <summary>
|
|||
|
/// Tickmarks are located outside of the chart area.
|
|||
|
/// </summary>
|
|||
|
OutsideArea,
|
|||
|
/// <summary>
|
|||
|
/// Tickmarks are located inside of the chart area.
|
|||
|
/// </summary>
|
|||
|
InsideArea,
|
|||
|
/// <summary>
|
|||
|
/// Tickmarks are set across the axis line.
|
|||
|
/// </summary>
|
|||
|
AcrossAxis
|
|||
|
};
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The TickMark class represents axis tick marks which are drawn next to
|
|||
|
/// the axis line. TickMark shares many common properties with the Grid
|
|||
|
/// class. This class also contains methods for tick marks drawing.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
DefaultProperty("Enabled"),
|
|||
|
SRDescription("DescriptionAttributeTickMark_TickMark"),
|
|||
|
]
|
|||
|
#if ASPPERM_35
|
|||
|
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
|||
|
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
|||
|
#endif
|
|||
|
public class TickMark : Grid
|
|||
|
{
|
|||
|
#region Private fields and Constructors
|
|||
|
|
|||
|
// Tick marks style
|
|||
|
private TickMarkStyle _style = TickMarkStyle.OutsideArea;
|
|||
|
|
|||
|
// Tick marks size
|
|||
|
private float _size = 1;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Public default constructor
|
|||
|
/// </summary>
|
|||
|
public TickMark() : base(null, true)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Public constructor
|
|||
|
/// </summary>
|
|||
|
/// <param name="axis">Axis which owns the grid or tick mark.</param>
|
|||
|
/// <param name="major">Major axis element.</param>
|
|||
|
internal TickMark(Axis axis, bool major) : base(axis, major)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Tick marks painting method
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Draws and hit test for TickMarks.
|
|||
|
/// </summary>
|
|||
|
/// <param name="graph">Reference to the Chart Graphics object.</param>
|
|||
|
/// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
|
|||
|
internal void Paint( ChartGraphics graph, bool backElements )
|
|||
|
{
|
|||
|
PointF first = PointF.Empty; // The First point of a tick mark
|
|||
|
PointF second = PointF.Empty; // The Second point of a tick mark
|
|||
|
float axisPosition; // Axis position.
|
|||
|
|
|||
|
// Tick Marks are disabled
|
|||
|
if( !this.enabled )
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// ****************************************************************
|
|||
|
// This code creates auto interval for auto tick marks and
|
|||
|
// gridlines. If type is not date there are always four tickmarks
|
|||
|
// or gridlines between major gridlines and tickmarks. For date
|
|||
|
// type interval is calculated using CalcInterval function.
|
|||
|
// ****************************************************************
|
|||
|
double oldInterval = this.interval;
|
|||
|
DateTimeIntervalType oldIntervalType = this.intervalType;
|
|||
|
double oldIntervalOffset = this.intervalOffset;
|
|||
|
DateTimeIntervalType oldIntervalOffsetType = this.intervalOffsetType;
|
|||
|
if( !this.majorGridTick && ( this.interval == 0 || double.IsNaN(this.interval) ) )
|
|||
|
{
|
|||
|
// Number type
|
|||
|
if (this.Axis.majorGrid.GetIntervalType() == DateTimeIntervalType.Auto)
|
|||
|
{
|
|||
|
this.interval = this.Axis.majorGrid.GetInterval() / Grid.NumberOfIntervals;
|
|||
|
}
|
|||
|
// Date type
|
|||
|
else
|
|||
|
{
|
|||
|
DateTimeIntervalType localIntervalType = this.Axis.majorGrid.GetIntervalType();
|
|||
|
this.interval = Axis.CalcInterval(
|
|||
|
this.Axis.ViewMinimum,
|
|||
|
this.Axis.ViewMinimum + (this.Axis.ViewMaximum - this.Axis.ViewMinimum) / Grid.NumberOfDateTimeIntervals,
|
|||
|
true,
|
|||
|
out localIntervalType,
|
|||
|
ChartValueType.DateTime );
|
|||
|
this.intervalType = localIntervalType;
|
|||
|
this.intervalOffsetType = this.Axis.majorGrid.GetIntervalOffsetType();
|
|||
|
this.intervalOffset = this.Axis.majorGrid.GetIntervalOffset();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( _style == TickMarkStyle.None )
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Check if custom tick marks should be drawn from custom labels
|
|||
|
if (Axis.IsCustomTickMarks())
|
|||
|
{
|
|||
|
PaintCustom(graph, backElements);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Get first series attached to this axis
|
|||
|
Series axisSeries = null;
|
|||
|
if (Axis.axisType == AxisName.X || Axis.axisType == AxisName.X2)
|
|||
|
{
|
|||
|
List<string> seriesArray = Axis.ChartArea.GetXAxesSeries((Axis.axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, Axis.SubAxisName);
|
|||
|
if(seriesArray.Count > 0)
|
|||
|
{
|
|||
|
axisSeries = Axis.Common.DataManager.Series[seriesArray[0]];
|
|||
|
if(axisSeries != null && !axisSeries.IsXValueIndexed)
|
|||
|
{
|
|||
|
axisSeries = null;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Current position for tick mark is minimum
|
|||
|
double current = Axis.ViewMinimum;
|
|||
|
|
|||
|
// Get offse type
|
|||
|
DateTimeIntervalType offsetType = (GetIntervalOffsetType() == DateTimeIntervalType.Auto) ? GetIntervalType() : GetIntervalOffsetType();
|
|||
|
|
|||
|
|
|||
|
// ***********************************
|
|||
|
// Check if the AJAX zooming and scrolling mode is enabled.
|
|||
|
// ***********************************
|
|||
|
|
|||
|
// Adjust start position depending on the interval type
|
|||
|
if (!Axis.ChartArea.chartAreaIsCurcular ||
|
|||
|
Axis.axisType == AxisName.Y ||
|
|||
|
Axis.axisType == AxisName.Y2)
|
|||
|
{
|
|||
|
current = ChartHelper.AlignIntervalStart(current, this.GetInterval(), this.GetIntervalType(), axisSeries, this.majorGridTick);
|
|||
|
}
|
|||
|
|
|||
|
// The Current position is start position, not minimum
|
|||
|
if (GetIntervalOffset() != 0 && !double.IsNaN(GetIntervalOffset()) && axisSeries == null)
|
|||
|
{
|
|||
|
current += ChartHelper.GetIntervalSize(current, GetIntervalOffset(),
|
|||
|
offsetType, axisSeries, 0, DateTimeIntervalType.Number, true, false);
|
|||
|
}
|
|||
|
|
|||
|
// Too many tick marks
|
|||
|
if ((Axis.ViewMaximum - Axis.ViewMinimum) / ChartHelper.GetIntervalSize(current, this.GetInterval(), this.GetIntervalType(), axisSeries, 0, DateTimeIntervalType.Number, true) > ChartHelper.MaxNumOfGridlines)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// If Maximum, minimum and interval don<6F>t have
|
|||
|
// proper value do not draw tick marks.
|
|||
|
if (Axis.ViewMaximum <= Axis.ViewMinimum)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Axis scroll bar will increase size of the Outside and Cross style tick marks
|
|||
|
float scrollBarSize = 0;
|
|||
|
|
|||
|
#if Microsoft_CONTROL
|
|||
|
|
|||
|
if (this.Axis.ScrollBar.IsVisible &&
|
|||
|
this.Axis.ScrollBar.IsPositionedInside &&
|
|||
|
(this.Axis.IsAxisOnAreaEdge || !this.Axis.IsMarksNextToAxis))
|
|||
|
{
|
|||
|
scrollBarSize = (float)this.Axis.ScrollBar.GetScrollBarRelativeSize();
|
|||
|
}
|
|||
|
|
|||
|
#endif // Microsoft_CONTROL
|
|||
|
|
|||
|
// Left tickmarks
|
|||
|
if (Axis.AxisPosition == AxisPosition.Left)
|
|||
|
{
|
|||
|
// The tick marks will follow axis or they will
|
|||
|
// be always on the border of the chart area.
|
|||
|
if (Axis.GetIsMarksNextToAxis())
|
|||
|
axisPosition = (float)Axis.GetAxisPosition();
|
|||
|
else
|
|||
|
axisPosition = Axis.PlotAreaPosition.X;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
first.X = axisPosition;
|
|||
|
second.X = axisPosition + _size;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
first.X = axisPosition - _size - scrollBarSize;
|
|||
|
second.X = axisPosition;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
first.X = axisPosition - _size/2 - scrollBarSize;
|
|||
|
second.X = axisPosition + _size/2;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Right tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Right)
|
|||
|
{
|
|||
|
// The tick marks will follow axis or they will
|
|||
|
// be always on the border of the chart area.
|
|||
|
if (Axis.GetIsMarksNextToAxis())
|
|||
|
axisPosition = (float)Axis.GetAxisPosition();
|
|||
|
else
|
|||
|
axisPosition = Axis.PlotAreaPosition.Right;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
first.X = axisPosition - _size;
|
|||
|
second.X = axisPosition;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
first.X = axisPosition;
|
|||
|
second.X = axisPosition + _size + scrollBarSize;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
first.X = axisPosition - _size/2;
|
|||
|
second.X = axisPosition + _size/2 + scrollBarSize;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Top tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Top)
|
|||
|
{
|
|||
|
// The tick marks will follow axis or they will
|
|||
|
// be always on the border of the chart area.
|
|||
|
if (Axis.GetIsMarksNextToAxis())
|
|||
|
axisPosition = (float)Axis.GetAxisPosition();
|
|||
|
else
|
|||
|
axisPosition = Axis.PlotAreaPosition.Y;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
first.Y = axisPosition;
|
|||
|
second.Y = axisPosition + _size;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
first.Y = axisPosition - _size - scrollBarSize;
|
|||
|
second.Y = axisPosition;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
first.Y = axisPosition - _size/2 - scrollBarSize;
|
|||
|
second.Y = axisPosition + _size/2;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Bottom tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
{
|
|||
|
// The tick marks will follow axis or they will
|
|||
|
// be always on the border of the chart area.
|
|||
|
if (Axis.GetIsMarksNextToAxis())
|
|||
|
axisPosition = (float)Axis.GetAxisPosition();
|
|||
|
else
|
|||
|
axisPosition = Axis.PlotAreaPosition.Bottom;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
first.Y = axisPosition - _size;
|
|||
|
second.Y = axisPosition;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
first.Y = axisPosition;
|
|||
|
second.Y = axisPosition + _size + scrollBarSize;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
first.Y = axisPosition - _size/2;
|
|||
|
second.Y = axisPosition + _size/2 + scrollBarSize;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Loop for drawing grid tick marks
|
|||
|
int counter = 0;
|
|||
|
int logStep = 1;
|
|||
|
double oldCurrent = current;
|
|||
|
double interval = 0;
|
|||
|
while (current <= Axis.ViewMaximum)
|
|||
|
{
|
|||
|
double logInterval = 0;
|
|||
|
|
|||
|
// Take an interval between gridlines. Interval
|
|||
|
// depends on interval type.
|
|||
|
if (this.majorGridTick || this.Axis.IsLogarithmic == false)
|
|||
|
{
|
|||
|
// Take an interval between tickmarks. Interval
|
|||
|
// depends on interval type.
|
|||
|
interval = ChartHelper.GetIntervalSize(current, this.GetInterval(), this.GetIntervalType(), axisSeries, this.GetIntervalOffset(), offsetType, true);
|
|||
|
|
|||
|
}
|
|||
|
// Code for linear minor gridlines and tickmarks
|
|||
|
// if scale is logarithmic.
|
|||
|
else
|
|||
|
{
|
|||
|
// This code is used only for logarithmic scale and minor tick marks or
|
|||
|
// gridlines which have linear minor scale in logarithmic major scale.
|
|||
|
// This code is used to find minimum value for the interval. For example
|
|||
|
// if logarithmic base is 2 and interval is between 4 and 8; current value
|
|||
|
// is 5.6; this method will return linearised value for 4. This code works
|
|||
|
// like Math.Floor for logarithmic scale.
|
|||
|
double logMinimum = this.GetLogMinimum( current, axisSeries );
|
|||
|
|
|||
|
if( oldCurrent != logMinimum )
|
|||
|
{
|
|||
|
oldCurrent = logMinimum;
|
|||
|
logStep = 1;
|
|||
|
}
|
|||
|
|
|||
|
// Find interval for logarithmic linearised scale
|
|||
|
logInterval = Math.Log(1 + this.interval * logStep, Axis.logarithmBase);
|
|||
|
|
|||
|
current = oldCurrent;
|
|||
|
|
|||
|
interval = logInterval;
|
|||
|
|
|||
|
logStep++;
|
|||
|
|
|||
|
// Reset current position if major interval is passed.
|
|||
|
if( this.GetLogMinimum( current + logInterval, axisSeries ) != logMinimum )
|
|||
|
{
|
|||
|
current += logInterval;
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// For indexed series do not draw the last tickmark
|
|||
|
if (current == Axis.ViewMaximum && axisSeries != null)
|
|||
|
{
|
|||
|
current += interval;
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// Check interval size
|
|||
|
if( interval == 0 )
|
|||
|
{
|
|||
|
throw (new InvalidOperationException(SR.ExceptionTickMarksIntervalIsZero));
|
|||
|
}
|
|||
|
|
|||
|
// Check if we do not exceed max number of elements
|
|||
|
if (counter++ > ChartHelper.MaxNumOfGridlines)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// Do not draw the very first tick mark for circular chart area
|
|||
|
if (this.Axis != null && this.Axis.ChartArea != null)
|
|||
|
{
|
|||
|
if (this.Axis.ChartArea.chartAreaIsCurcular &&
|
|||
|
((this.Axis.IsReversed == false && current == Axis.ViewMinimum) ||
|
|||
|
(this.Axis.IsReversed == true && current == Axis.ViewMaximum)))
|
|||
|
{
|
|||
|
current += interval;
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!this.majorGridTick && this.Axis.IsLogarithmic)
|
|||
|
{
|
|||
|
current += logInterval;
|
|||
|
|
|||
|
if (current > Axis.ViewMaximum)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((decimal)current >= (decimal)Axis.ViewMinimum)
|
|||
|
{
|
|||
|
// Left tickmarks
|
|||
|
if (Axis.AxisPosition == AxisPosition.Left)
|
|||
|
{
|
|||
|
first.Y = (float)Axis.GetLinearPosition(current);
|
|||
|
second.Y = first.Y;
|
|||
|
}
|
|||
|
|
|||
|
// Right tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Right)
|
|||
|
{
|
|||
|
first.Y = (float)Axis.GetLinearPosition(current);
|
|||
|
second.Y = first.Y;
|
|||
|
}
|
|||
|
|
|||
|
// Top tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Top)
|
|||
|
{
|
|||
|
first.X = (float)Axis.GetLinearPosition(current);
|
|||
|
second.X = first.X;
|
|||
|
}
|
|||
|
|
|||
|
// Bottom tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
{
|
|||
|
first.X = (float)Axis.GetLinearPosition(current);
|
|||
|
second.X = first.X;
|
|||
|
}
|
|||
|
|
|||
|
if (Axis.Common.ProcessModeRegions)
|
|||
|
{
|
|||
|
if (this.Axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
RectangleF rect = new RectangleF( first.X - 0.5f, first.Y - 0.5f, Math.Abs( second.X - first.X ) + 1, Math.Abs( second.Y - first.Y ) + 1 );
|
|||
|
using (GraphicsPath path = new GraphicsPath())
|
|||
|
{
|
|||
|
path.AddRectangle(graph.GetAbsoluteRectangle(rect));
|
|||
|
path.Transform(graph.Transform);
|
|||
|
this.Axis.Common.HotRegionsList.AddHotRegion(
|
|||
|
path,
|
|||
|
false,
|
|||
|
ChartElementType.TickMarks,
|
|||
|
this);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (!this.Axis.ChartArea.Area3DStyle.Enable3D || this.Axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
RectangleF rect = new RectangleF( first.X - 0.5f, first.Y - 0.5f, Math.Abs( second.X - first.X ) + 1, Math.Abs( second.Y - first.Y ) + 1 );
|
|||
|
|
|||
|
Axis.Common.HotRegionsList.AddHotRegion(rect, this, ChartElementType.TickMarks, true);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!Axis.Common.ProcessModePaint) //if ProcessModePaint is true it will be called later
|
|||
|
Draw3DTickLine(graph, first, second, backElements);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (Axis.Common.ProcessModePaint)
|
|||
|
{
|
|||
|
// Draw grid line
|
|||
|
if (!this.Axis.ChartArea.Area3DStyle.Enable3D || this.Axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
graph.DrawLineRel( borderColor, borderWidth, borderDashStyle, first, second );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Draw3DTickLine(graph, first, second, backElements);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Move position
|
|||
|
if (this.majorGridTick || this.Axis.IsLogarithmic == false)
|
|||
|
{
|
|||
|
current += interval;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Used for auto interval for auto tick marks and
|
|||
|
// gridlines
|
|||
|
if( !this.majorGridTick )
|
|||
|
{
|
|||
|
this.interval = oldInterval;
|
|||
|
this.intervalType = oldIntervalType;
|
|||
|
this.intervalOffset = oldIntervalOffset;
|
|||
|
this.intervalOffsetType = oldIntervalOffsetType;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// This method returns linearized logarithmic value
|
|||
|
/// which is minimum for range with interval 1.
|
|||
|
/// </summary>
|
|||
|
/// <param name="current">Current value</param>
|
|||
|
/// <param name="axisSeries">First series attached to axis.</param>
|
|||
|
/// <returns>Returns Minimum for the range which contains current value</returns>
|
|||
|
private double GetLogMinimum( double current, Series axisSeries )
|
|||
|
{
|
|||
|
double viewMinimum = Axis.ViewMinimum;
|
|||
|
DateTimeIntervalType offsetType = (GetIntervalOffsetType() == DateTimeIntervalType.Auto) ? GetIntervalType() : GetIntervalOffsetType();
|
|||
|
if( GetIntervalOffset() != 0 && axisSeries == null)
|
|||
|
{
|
|||
|
viewMinimum += ChartHelper.GetIntervalSize(viewMinimum, GetIntervalOffset(),
|
|||
|
offsetType, axisSeries, 0, DateTimeIntervalType.Number, true, false);
|
|||
|
}
|
|||
|
|
|||
|
return viewMinimum + Math.Floor( ( current - viewMinimum ));
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Draws and hit test for custom TickMarks from the custom labels collection.
|
|||
|
/// </summary>
|
|||
|
/// <param name="graph">Reference to the Chart Graphics object.</param>
|
|||
|
/// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
|
|||
|
internal void PaintCustom( ChartGraphics graph, bool backElements )
|
|||
|
{
|
|||
|
PointF first = PointF.Empty; // The First point of a tick mark
|
|||
|
PointF second = PointF.Empty; // The Second point of a tick mark
|
|||
|
float axisPosition; // Axis position.
|
|||
|
|
|||
|
// Axis scroll bar will increase size of the Outside and Cross style tick marks
|
|||
|
float scrollBarSize = 0;
|
|||
|
|
|||
|
#if Microsoft_CONTROL
|
|||
|
|
|||
|
if (this.Axis.ScrollBar.IsVisible && this.Axis.ScrollBar.IsPositionedInside && this.Axis.IsAxisOnAreaEdge)
|
|||
|
{
|
|||
|
scrollBarSize = (float)this.Axis.ScrollBar.GetScrollBarRelativeSize();
|
|||
|
}
|
|||
|
|
|||
|
#endif // Microsoft_CONTROL
|
|||
|
|
|||
|
// Left tickmarks
|
|||
|
if (Axis.AxisPosition == AxisPosition.Left)
|
|||
|
{
|
|||
|
// The tick marks will follow axis or they will
|
|||
|
// be always on the border of the chart area.
|
|||
|
if (Axis.GetIsMarksNextToAxis())
|
|||
|
axisPosition = (float)Axis.GetAxisPosition();
|
|||
|
else
|
|||
|
axisPosition = Axis.PlotAreaPosition.X;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
first.X = axisPosition;
|
|||
|
second.X = axisPosition + _size;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
first.X = axisPosition - _size - scrollBarSize;
|
|||
|
second.X = axisPosition;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
first.X = axisPosition - _size/2 - scrollBarSize;
|
|||
|
second.X = axisPosition + _size/2;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Right tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Right)
|
|||
|
{
|
|||
|
// The tick marks will follow axis or they will
|
|||
|
// be always on the border of the chart area.
|
|||
|
if (Axis.GetIsMarksNextToAxis())
|
|||
|
axisPosition = (float)Axis.GetAxisPosition();
|
|||
|
else
|
|||
|
axisPosition = Axis.PlotAreaPosition.Right;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
first.X = axisPosition - _size;
|
|||
|
second.X = axisPosition;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
first.X = axisPosition;
|
|||
|
second.X = axisPosition + _size + scrollBarSize;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
first.X = axisPosition - _size/2;
|
|||
|
second.X = axisPosition + _size/2 + scrollBarSize;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Top tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Top)
|
|||
|
{
|
|||
|
// The tick marks will follow axis or they will
|
|||
|
// be always on the border of the chart area.
|
|||
|
if (Axis.GetIsMarksNextToAxis())
|
|||
|
axisPosition = (float)Axis.GetAxisPosition();
|
|||
|
else
|
|||
|
axisPosition = Axis.PlotAreaPosition.Y;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
first.Y = axisPosition;
|
|||
|
second.Y = axisPosition + _size;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
first.Y = axisPosition - _size - scrollBarSize;
|
|||
|
second.Y = axisPosition;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
first.Y = axisPosition - _size/2 - scrollBarSize;
|
|||
|
second.Y = axisPosition + _size/2;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Bottom tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
{
|
|||
|
// The tick marks will follow axis or they will
|
|||
|
// be always on the border of the chart area.
|
|||
|
if (Axis.GetIsMarksNextToAxis())
|
|||
|
axisPosition = (float)Axis.GetAxisPosition();
|
|||
|
else
|
|||
|
axisPosition = Axis.PlotAreaPosition.Bottom;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
first.Y = axisPosition - _size;
|
|||
|
second.Y = axisPosition;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
first.Y = axisPosition;
|
|||
|
second.Y = axisPosition + _size + scrollBarSize;
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
first.Y = axisPosition - _size/2;
|
|||
|
second.Y = axisPosition + _size/2 + scrollBarSize;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Loop through all custom labels
|
|||
|
foreach (CustomLabel label in Axis.CustomLabels)
|
|||
|
{
|
|||
|
if((label.GridTicks & GridTickTypes.TickMark) == GridTickTypes.TickMark)
|
|||
|
{
|
|||
|
double position = (label.ToPosition + label.FromPosition) / 2.0;
|
|||
|
if (position >= Axis.ViewMinimum && position <= Axis.ViewMaximum)
|
|||
|
{
|
|||
|
// Left tickmarks
|
|||
|
if (Axis.AxisPosition == AxisPosition.Left)
|
|||
|
{
|
|||
|
first.Y = (float)Axis.GetLinearPosition(position);
|
|||
|
second.Y = first.Y;
|
|||
|
}
|
|||
|
|
|||
|
// Right tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Right)
|
|||
|
{
|
|||
|
first.Y = (float)Axis.GetLinearPosition(position);
|
|||
|
second.Y = first.Y;
|
|||
|
}
|
|||
|
|
|||
|
// Top tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Top)
|
|||
|
{
|
|||
|
first.X = (float)Axis.GetLinearPosition(position);
|
|||
|
second.X = first.X;
|
|||
|
}
|
|||
|
|
|||
|
// Bottom tickmarks
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
{
|
|||
|
first.X = (float)Axis.GetLinearPosition(position);
|
|||
|
second.X = first.X;
|
|||
|
}
|
|||
|
|
|||
|
if (Axis.Common.ProcessModeRegions)
|
|||
|
{
|
|||
|
if (!this.Axis.ChartArea.Area3DStyle.Enable3D || this.Axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
RectangleF rect = new RectangleF( first.X - 0.5f, first.Y - 0.5f, Math.Abs( second.X - first.X ) + 1, Math.Abs( second.Y - first.Y ) + 1 );
|
|||
|
|
|||
|
Axis.Common.HotRegionsList.AddHotRegion(rect, this, ChartElementType.TickMarks, true);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Draw3DTickLine(graph, first, second, backElements);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Axis.Common.ProcessModePaint)
|
|||
|
{
|
|||
|
// Draw grid line
|
|||
|
if (!this.Axis.ChartArea.Area3DStyle.Enable3D || this.Axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
graph.DrawLineRel( borderColor, borderWidth, borderDashStyle, first, second );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Draw3DTickLine(graph, first, second, backElements);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Draws tick mark line in 3D space.
|
|||
|
/// </summary>
|
|||
|
/// <param name="graph">Reference to the Chart Graphics object.</param>
|
|||
|
/// <param name="point1">First line point.</param>
|
|||
|
/// <param name="point2">Second line point.</param>
|
|||
|
/// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
|
|||
|
internal void Draw3DTickLine(
|
|||
|
ChartGraphics graph,
|
|||
|
PointF point1,
|
|||
|
PointF point2,
|
|||
|
bool backElements
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
ChartArea area = this.Axis.ChartArea;
|
|||
|
|
|||
|
//*****************************************************************
|
|||
|
//** Set the tick marks line depth
|
|||
|
//*****************************************************************
|
|||
|
bool axisOnEdge;
|
|||
|
float wallZPosition = Axis.GetMarksZPosition(out axisOnEdge);
|
|||
|
|
|||
|
//*****************************************************************
|
|||
|
//** Check if tick mark should be drawn as back or front element
|
|||
|
//*****************************************************************
|
|||
|
|
|||
|
// Check if axis tick marks are drawn inside plotting area
|
|||
|
bool tickMarksOnEdge = axisOnEdge;
|
|||
|
if(tickMarksOnEdge &&
|
|||
|
this.Axis.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis ||
|
|||
|
this.Axis.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea ||
|
|||
|
this.Axis.MinorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis ||
|
|||
|
this.Axis.MinorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
|
|||
|
{
|
|||
|
tickMarksOnEdge = false;
|
|||
|
}
|
|||
|
|
|||
|
SurfaceNames surfaceName = (wallZPosition == 0f) ? SurfaceNames.Back : SurfaceNames.Front;
|
|||
|
if( !area.ShouldDrawOnSurface(surfaceName, backElements, tickMarksOnEdge) )
|
|||
|
{
|
|||
|
// Skip drawing
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//*****************************************************************
|
|||
|
//** Add area scene wall width to the length of the tick mark
|
|||
|
//*****************************************************************
|
|||
|
if (Axis.AxisPosition == AxisPosition.Bottom &&
|
|||
|
(!Axis.GetIsMarksNextToAxis() || axisOnEdge) &&
|
|||
|
area.IsBottomSceneWallVisible())
|
|||
|
{
|
|||
|
point2.Y += area.areaSceneWallWidth.Height;
|
|||
|
}
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Left &&
|
|||
|
(!Axis.GetIsMarksNextToAxis() || axisOnEdge) &&
|
|||
|
area.IsSideSceneWallOnLeft())
|
|||
|
{
|
|||
|
point1.X -= area.areaSceneWallWidth.Width;
|
|||
|
}
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Right &&
|
|||
|
(!Axis.GetIsMarksNextToAxis() || axisOnEdge) &&
|
|||
|
!area.IsSideSceneWallOnLeft())
|
|||
|
{
|
|||
|
point2.X += area.areaSceneWallWidth.Width;
|
|||
|
}
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Top &&
|
|||
|
(!Axis.GetIsMarksNextToAxis() || axisOnEdge))
|
|||
|
{
|
|||
|
point1.Y -= area.areaSceneWallWidth.Height;
|
|||
|
}
|
|||
|
|
|||
|
//*****************************************************************
|
|||
|
//** Adjust grid line direction for the Top axis
|
|||
|
//*****************************************************************
|
|||
|
Point3D point3 = null, point4 = null;
|
|||
|
if(axisOnEdge && area.areaSceneWallWidth.Width != 0f)
|
|||
|
{
|
|||
|
if (Axis.AxisPosition == AxisPosition.Top)
|
|||
|
{
|
|||
|
// Always use plot area position to draw tick mark
|
|||
|
float axisPosition = Axis.PlotAreaPosition.Y;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
point1.Y = axisPosition;
|
|||
|
point2.Y = axisPosition + _size;
|
|||
|
|
|||
|
point3 = new Point3D(point1.X, point1.Y, - area.areaSceneWallWidth.Width);
|
|||
|
point4 = new Point3D(point1.X, point1.Y, 0f);
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
point1.Y = axisPosition;
|
|||
|
point2.Y = axisPosition;
|
|||
|
|
|||
|
point3 = new Point3D(point1.X, axisPosition, wallZPosition);
|
|||
|
point4 = new Point3D(point1.X, point1.Y, - _size - area.areaSceneWallWidth.Width);
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
point1.Y = axisPosition;
|
|||
|
point2.Y = axisPosition + _size/2;
|
|||
|
|
|||
|
point3 = new Point3D(point1.X, axisPosition, wallZPosition);
|
|||
|
point4 = new Point3D(point1.X, point1.Y, - _size/2 - area.areaSceneWallWidth.Width);
|
|||
|
}
|
|||
|
|
|||
|
// Do not show "bent" tick marks on the top surface
|
|||
|
if(area.ShouldDrawOnSurface(SurfaceNames.Top, backElements, false))
|
|||
|
{
|
|||
|
point3 = null;
|
|||
|
point4 = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//*****************************************************************
|
|||
|
//** Adjust grid line direction for the Left axis
|
|||
|
//*****************************************************************
|
|||
|
if (Axis.AxisPosition == AxisPosition.Left && !area.IsSideSceneWallOnLeft())
|
|||
|
{
|
|||
|
// Always use plot area position to draw tick mark
|
|||
|
float axisPosition = Axis.PlotAreaPosition.X;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
point1.X = axisPosition;
|
|||
|
point2.X = axisPosition + _size;
|
|||
|
|
|||
|
point3 = new Point3D(point1.X, point1.Y, - area.areaSceneWallWidth.Width);
|
|||
|
point4 = new Point3D(point1.X, point1.Y, 0f);
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
point1.X = axisPosition;
|
|||
|
point2.X = axisPosition;
|
|||
|
|
|||
|
point3 = new Point3D(axisPosition, point1.Y, wallZPosition);
|
|||
|
point4 = new Point3D(axisPosition, point1.Y, - _size - area.areaSceneWallWidth.Width);
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
point1.X = axisPosition;
|
|||
|
point2.X = axisPosition + _size/2;
|
|||
|
|
|||
|
point3 = new Point3D(axisPosition, point1.Y, wallZPosition);
|
|||
|
point4 = new Point3D(axisPosition, point1.Y, - _size/2 - area.areaSceneWallWidth.Width);
|
|||
|
}
|
|||
|
|
|||
|
// Do not show "bent" tick marks on the left surface
|
|||
|
if(area.ShouldDrawOnSurface(SurfaceNames.Left, backElements, false))
|
|||
|
{
|
|||
|
point3 = null;
|
|||
|
point4 = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//*****************************************************************
|
|||
|
//** Adjust grid line direction for the Right axis
|
|||
|
//*****************************************************************
|
|||
|
else if (Axis.AxisPosition == AxisPosition.Right && area.IsSideSceneWallOnLeft())
|
|||
|
{
|
|||
|
// Always use plot area position to draw tick mark
|
|||
|
float axisPosition = Axis.PlotAreaPosition.Right;
|
|||
|
|
|||
|
if( _style == TickMarkStyle.InsideArea )
|
|||
|
{
|
|||
|
point1.X = axisPosition - _size;
|
|||
|
point2.X = axisPosition;
|
|||
|
|
|||
|
point3 = new Point3D(point2.X, point2.Y, - area.areaSceneWallWidth.Width);
|
|||
|
point4 = new Point3D(point2.X, point2.Y, 0f);
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.OutsideArea )
|
|||
|
{
|
|||
|
point1.X = axisPosition;
|
|||
|
point2.X = axisPosition;
|
|||
|
|
|||
|
point3 = new Point3D(axisPosition, point1.Y, wallZPosition);
|
|||
|
point4 = new Point3D(axisPosition, point1.Y, - _size - area.areaSceneWallWidth.Width);
|
|||
|
|
|||
|
}
|
|||
|
else if( _style == TickMarkStyle.AcrossAxis )
|
|||
|
{
|
|||
|
point1.X = axisPosition - _size/2;
|
|||
|
point2.X = axisPosition;
|
|||
|
|
|||
|
point3 = new Point3D(axisPosition, point1.Y, wallZPosition);
|
|||
|
point4 = new Point3D(axisPosition, point1.Y, - _size/2 - area.areaSceneWallWidth.Width);
|
|||
|
}
|
|||
|
|
|||
|
// Do not show "bent" tick marks on the right surface
|
|||
|
if(area.ShouldDrawOnSurface(SurfaceNames.Right, backElements, false))
|
|||
|
{
|
|||
|
point3 = null;
|
|||
|
point4 = null;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//*****************************************************************
|
|||
|
//** Draw tick mark (first line)
|
|||
|
//*****************************************************************
|
|||
|
graph.Draw3DLine(
|
|||
|
area.matrix3D,
|
|||
|
borderColor, borderWidth, borderDashStyle,
|
|||
|
new Point3D(point1.X, point1.Y, wallZPosition),
|
|||
|
new Point3D(point2.X, point2.Y, wallZPosition),
|
|||
|
Axis.Common,
|
|||
|
this,
|
|||
|
ChartElementType.TickMarks
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//*****************************************************************
|
|||
|
//** Draw tick mark (second line)
|
|||
|
//*****************************************************************
|
|||
|
if(point3 != null && point4 != null)
|
|||
|
{
|
|||
|
graph.Draw3DLine(
|
|||
|
area.matrix3D,
|
|||
|
borderColor, borderWidth, borderDashStyle,
|
|||
|
point3,
|
|||
|
point4,
|
|||
|
Axis.Common,
|
|||
|
this,
|
|||
|
ChartElementType.TickMarks
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region TickMark properties
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Tick mark style.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
Bindable(true),
|
|||
|
DefaultValue(TickMarkStyle.OutsideArea),
|
|||
|
SRDescription("DescriptionAttributeTickMark_Style"),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
#endif
|
|||
|
]
|
|||
|
public TickMarkStyle TickMarkStyle
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _style;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_style = value;
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Tick mark size.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
Bindable(true),
|
|||
|
DefaultValue(1.0F),
|
|||
|
SRDescription("DescriptionAttributeTickMark_Size"),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
#endif
|
|||
|
]
|
|||
|
public float Size
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _size;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_size = value;
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The Grid class represents axis grid lines which are drawn in the
|
|||
|
/// plotting area. It contains grid interval and visual appearance
|
|||
|
/// properties. This class also contains methods for grid lines drawing.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
DefaultProperty("Enabled"),
|
|||
|
SRDescription("DescriptionAttributeGrid_Grid"),
|
|||
|
]
|
|||
|
#if ASPPERM_35
|
|||
|
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
|||
|
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
|||
|
#endif
|
|||
|
public class Grid
|
|||
|
{
|
|||
|
#region Grid fields and Constructors
|
|||
|
|
|||
|
// Reference to the Axis object
|
|||
|
private Axis _axis = null;
|
|||
|
|
|||
|
// Flags indicate that interval properties where changed
|
|||
|
internal bool intervalOffsetChanged = false;
|
|||
|
internal bool intervalChanged = false;
|
|||
|
internal bool intervalTypeChanged = false;
|
|||
|
internal bool intervalOffsetTypeChanged = false;
|
|||
|
|
|||
|
internal bool enabledChanged = false;
|
|||
|
|
|||
|
// Data members, which store properties values
|
|||
|
internal double intervalOffset = 0;
|
|||
|
internal double interval = 0;
|
|||
|
internal DateTimeIntervalType intervalType = DateTimeIntervalType.Auto;
|
|||
|
internal DateTimeIntervalType intervalOffsetType = DateTimeIntervalType.Auto;
|
|||
|
internal Color borderColor = Color.Black;
|
|||
|
internal int borderWidth = 1;
|
|||
|
internal ChartDashStyle borderDashStyle = ChartDashStyle.Solid;
|
|||
|
internal bool enabled = true;
|
|||
|
|
|||
|
// Indicates that object describes Major Tick Mark or Grid Line
|
|||
|
internal bool majorGridTick = false;
|
|||
|
|
|||
|
// Common number of intervals on the numeric and date-time axis
|
|||
|
internal const double NumberOfIntervals = 5.0;
|
|||
|
internal const double NumberOfDateTimeIntervals = 4.0;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Public default constructor.
|
|||
|
/// </summary>
|
|||
|
public Grid()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Public constructor.
|
|||
|
/// </summary>
|
|||
|
/// <param name="axis">Axis which owns the grid.</param>
|
|||
|
/// <param name="major">Major axis element.</param>
|
|||
|
internal Grid(Axis axis, bool major)
|
|||
|
{
|
|||
|
Initialize(axis, major);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Initializes the object.
|
|||
|
/// </summary>
|
|||
|
/// <param name="axis">Axis which owns the grid.</param>
|
|||
|
/// <param name="major">Major axis element.</param>
|
|||
|
internal void Initialize(Axis axis, bool major)
|
|||
|
{
|
|||
|
// Minor elements are disabled by default
|
|||
|
if(!this.enabledChanged &&
|
|||
|
this._axis == null &&
|
|||
|
!major)
|
|||
|
{
|
|||
|
enabled = false;
|
|||
|
}
|
|||
|
|
|||
|
// If object was first created and populated with data and then added into the axis
|
|||
|
// we need to remember changed values.
|
|||
|
// NOTE: Fixes issue #6237
|
|||
|
if(this._axis == null)
|
|||
|
{
|
|||
|
TickMark tickMark = this as TickMark;
|
|||
|
|
|||
|
if(this.interval != 0)
|
|||
|
{
|
|||
|
if (tickMark != null)
|
|||
|
{
|
|||
|
if(major)
|
|||
|
{
|
|||
|
axis.tempMajorTickMarkInterval = this.interval;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
axis.tempMinorTickMarkInterval = this.interval;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if(major)
|
|||
|
{
|
|||
|
axis.tempMajorGridInterval = this.interval;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
axis.tempMinorGridInterval = this.interval;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if(this.intervalType != DateTimeIntervalType.Auto)
|
|||
|
{
|
|||
|
if(tickMark != null)
|
|||
|
{
|
|||
|
if(major)
|
|||
|
{
|
|||
|
axis.tempTickMarkIntervalType = this.intervalType;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if(major)
|
|||
|
{
|
|||
|
axis.tempGridIntervalType = this.intervalType;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Set axis object reference
|
|||
|
this._axis = axis;
|
|||
|
|
|||
|
// Set a flag if this object represent minor or major tick
|
|||
|
this.majorGridTick = major;
|
|||
|
|
|||
|
// internal double interval = 0;
|
|||
|
// internal DateTimeIntervalType intervalType = DateTimeIntervalType.Auto;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Grid helper functions
|
|||
|
/// <summary>
|
|||
|
/// Gets axes to which this object attached to
|
|||
|
/// </summary>
|
|||
|
/// <returns>Axis object.</returns>
|
|||
|
internal Axis GetAxis()
|
|||
|
{
|
|||
|
return _axis;
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// Invalidate chart area the axis belong to.
|
|||
|
/// </summary>
|
|||
|
internal void Invalidate()
|
|||
|
{
|
|||
|
#if Microsoft_CONTROL
|
|||
|
|
|||
|
if(this._axis != null)
|
|||
|
{
|
|||
|
this._axis.Invalidate();
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Grid lines drawing functions
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Draws grid lines.
|
|||
|
/// </summary>
|
|||
|
/// <param name="graph">Reference to the Chart Graphics object.</param>
|
|||
|
internal void Paint( ChartGraphics graph )
|
|||
|
{
|
|||
|
// Grids are disabled
|
|||
|
if( !this.enabled )
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Check if custom grid lines should be drawn from custom labels
|
|||
|
if(_axis.IsCustomGridLines())
|
|||
|
{
|
|||
|
PaintCustom( graph );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
double gridInterval; // Grid interval
|
|||
|
double current; // Current position
|
|||
|
|
|||
|
// Get first series attached to this axis
|
|||
|
Series axisSeries = null;
|
|||
|
if(_axis.axisType == AxisName.X || _axis.axisType == AxisName.X2)
|
|||
|
{
|
|||
|
List<string> seriesArray = _axis.ChartArea.GetXAxesSeries((_axis.axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, _axis.SubAxisName);
|
|||
|
if(seriesArray.Count > 0)
|
|||
|
{
|
|||
|
axisSeries = _axis.Common.DataManager.Series[seriesArray[0]];
|
|||
|
if(axisSeries != null && !axisSeries.IsXValueIndexed)
|
|||
|
{
|
|||
|
axisSeries = null;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// ****************************************************************
|
|||
|
// This code creates auto interval for auto tick marks and
|
|||
|
// gridlines. If type is not date there are always four tickmarks
|
|||
|
// or gridlines between major gridlines and tickmarks. For date
|
|||
|
// type interval is calculated using CalcInterval function.
|
|||
|
// ****************************************************************
|
|||
|
double oldInterval = this.interval;
|
|||
|
DateTimeIntervalType oldIntervalType = this.intervalType;
|
|||
|
double oldIntervalOffset = this.intervalOffset;
|
|||
|
DateTimeIntervalType oldIntervalOffsetType = this.intervalOffsetType;
|
|||
|
if( !this.majorGridTick && ( this.interval == 0 || double.IsNaN(this.interval) ) )
|
|||
|
{
|
|||
|
// Number type
|
|||
|
if( this._axis.majorGrid.GetIntervalType() == DateTimeIntervalType.Auto )
|
|||
|
{
|
|||
|
this.interval = this._axis.majorGrid.GetInterval() / Grid.NumberOfIntervals;
|
|||
|
}
|
|||
|
// Date type
|
|||
|
else
|
|||
|
{
|
|||
|
DateTimeIntervalType localIntervalType = this._axis.majorGrid.GetIntervalType();
|
|||
|
this.interval = _axis.CalcInterval(
|
|||
|
this._axis.minimum,
|
|||
|
this._axis.minimum + (this._axis.maximum - this._axis.minimum) / Grid.NumberOfDateTimeIntervals,
|
|||
|
true,
|
|||
|
out localIntervalType,
|
|||
|
ChartValueType.DateTime);
|
|||
|
this.intervalType = localIntervalType;
|
|||
|
this.intervalOffsetType = this._axis.majorGrid.GetIntervalOffsetType();
|
|||
|
this.intervalOffset = this._axis.majorGrid.GetIntervalOffset();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Current position for grid lines is minimum
|
|||
|
current = _axis.ViewMinimum;
|
|||
|
|
|||
|
|
|||
|
// ***********************************
|
|||
|
// Check if the AJAX zooming and scrolling mode is enabled.
|
|||
|
// ***********************************
|
|||
|
|
|||
|
// Adjust start position depending on the interval type
|
|||
|
if(!_axis.ChartArea.chartAreaIsCurcular ||
|
|||
|
_axis.axisType == AxisName.Y ||
|
|||
|
_axis.axisType == AxisName.Y2 )
|
|||
|
{
|
|||
|
current = ChartHelper.AlignIntervalStart(current, this.GetInterval(), this.GetIntervalType(), axisSeries, this.majorGridTick);
|
|||
|
}
|
|||
|
|
|||
|
// The Current position is start position, not minimum
|
|||
|
DateTimeIntervalType offsetType = (GetIntervalOffsetType() == DateTimeIntervalType.Auto) ? GetIntervalType() : GetIntervalOffsetType();
|
|||
|
if (GetIntervalOffset() != 0 && !double.IsNaN(GetIntervalOffset()) && axisSeries == null)
|
|||
|
{
|
|||
|
current += ChartHelper.GetIntervalSize(current, GetIntervalOffset(), offsetType, axisSeries, 0, DateTimeIntervalType.Number, true, false);
|
|||
|
}
|
|||
|
|
|||
|
// Too many gridlines
|
|||
|
if( ( _axis.ViewMaximum - _axis.ViewMinimum ) / ChartHelper.GetIntervalSize( current, this.GetInterval(), this.GetIntervalType(), axisSeries, 0, DateTimeIntervalType.Number, true ) > ChartHelper.MaxNumOfGridlines )
|
|||
|
return;
|
|||
|
|
|||
|
// If Maximum, minimum and interval don<6F>t have
|
|||
|
// proper value do not draw grid lines.
|
|||
|
if( _axis.ViewMaximum <= _axis.ViewMinimum )
|
|||
|
return;
|
|||
|
|
|||
|
if( this.GetInterval() <= 0 )
|
|||
|
return;
|
|||
|
|
|||
|
// Loop for drawing grid lines
|
|||
|
int counter = 0;
|
|||
|
int logStep = 1;
|
|||
|
double oldCurrent = current;
|
|||
|
decimal viewMaximum = (decimal)_axis.ViewMaximum;
|
|||
|
while( (decimal)current <= viewMaximum )
|
|||
|
{
|
|||
|
// Take an interval between gridlines. Interval
|
|||
|
// depends on interval type.
|
|||
|
if( this.majorGridTick || this._axis.IsLogarithmic == false )
|
|||
|
{
|
|||
|
double autoInterval = this.GetInterval();
|
|||
|
|
|||
|
gridInterval = ChartHelper.GetIntervalSize(current, autoInterval, this.GetIntervalType(), axisSeries, this.GetIntervalOffset(), offsetType, true);
|
|||
|
|
|||
|
// Check interval size
|
|||
|
if (gridInterval == 0)
|
|||
|
{
|
|||
|
throw (new InvalidOperationException(SR.ExceptionTickMarksIntervalIsZero));
|
|||
|
}
|
|||
|
|
|||
|
// Draw between min & max values only
|
|||
|
if((decimal)current >= (decimal)_axis.ViewMinimum)
|
|||
|
{
|
|||
|
DrawGrid( graph, current );
|
|||
|
}
|
|||
|
|
|||
|
// Move position
|
|||
|
current += gridInterval;
|
|||
|
}
|
|||
|
// Code for linear minor gridlines and tickmarks
|
|||
|
// if scale is logarithmic.
|
|||
|
else
|
|||
|
{
|
|||
|
// This code is used only for logarithmic scale and minor tick marks or
|
|||
|
// gridlines which have linear minor scale in logarithmic major scale.
|
|||
|
// This code is used to find minimum value for the interval. For example
|
|||
|
// if logarithmic base is 2 and interval is between 4 and 8; current value
|
|||
|
// is 5.6; this method will return linearised value for 4. This code works
|
|||
|
// like Math.Floor for logarithmic scale.
|
|||
|
double logMinimum = this.GetLogMinimum( current, axisSeries );
|
|||
|
|
|||
|
if( oldCurrent != logMinimum )
|
|||
|
{
|
|||
|
oldCurrent = logMinimum;
|
|||
|
logStep = 1;
|
|||
|
}
|
|||
|
|
|||
|
// Find interval for logarithmic linearised scale
|
|||
|
double logInterval = Math.Log( 1 + this.interval * logStep, _axis.logarithmBase );
|
|||
|
|
|||
|
current = oldCurrent;
|
|||
|
|
|||
|
// Move position
|
|||
|
current += logInterval;
|
|||
|
|
|||
|
logStep++;
|
|||
|
|
|||
|
// Reset current position if major interval is passed.
|
|||
|
if( this.GetLogMinimum( current, axisSeries ) != logMinimum )
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// Check interval size
|
|||
|
if (logInterval == 0)
|
|||
|
{
|
|||
|
throw (new InvalidOperationException(SR.ExceptionTickMarksIntervalIsZero));
|
|||
|
}
|
|||
|
|
|||
|
// Draw between min & max values only
|
|||
|
if( (decimal)current >= (decimal)_axis.ViewMinimum && (decimal)current <= (decimal)_axis.ViewMaximum )
|
|||
|
{
|
|||
|
DrawGrid( graph, current );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Check if we do not exceed max number of elements
|
|||
|
if (counter++ > ChartHelper.MaxNumOfGridlines)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Used for auto interval for auto tick marks and
|
|||
|
// gridlines
|
|||
|
if( !this.majorGridTick )
|
|||
|
{
|
|||
|
this.interval = oldInterval;
|
|||
|
this.intervalType = oldIntervalType;
|
|||
|
this.intervalOffset = oldIntervalOffset;
|
|||
|
this.intervalOffsetType = oldIntervalOffsetType;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// This method returns linearized logarithmic value
|
|||
|
/// which is minimum for range with interval 1.
|
|||
|
/// </summary>
|
|||
|
/// <param name="current">Current value</param>
|
|||
|
/// <param name="axisSeries">First series attached to axis.</param>
|
|||
|
/// <returns>Returns Minimum for the range which contains current value</returns>
|
|||
|
private double GetLogMinimum( double current, Series axisSeries )
|
|||
|
{
|
|||
|
double viewMinimum = _axis.ViewMinimum;
|
|||
|
DateTimeIntervalType offsetType = (GetIntervalOffsetType() == DateTimeIntervalType.Auto) ? GetIntervalType() : GetIntervalOffsetType();
|
|||
|
if( GetIntervalOffset() != 0 && axisSeries == null)
|
|||
|
{
|
|||
|
viewMinimum += ChartHelper.GetIntervalSize(viewMinimum, GetIntervalOffset(),
|
|||
|
offsetType, axisSeries, 0, DateTimeIntervalType.Number, true, false);
|
|||
|
}
|
|||
|
|
|||
|
return viewMinimum + Math.Floor( ( current - viewMinimum ));
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Draw the grid line
|
|||
|
/// </summary>
|
|||
|
/// <param name="graph">Chart Graphics object</param>
|
|||
|
/// <param name="current">Current position of the gridline</param>
|
|||
|
private void DrawGrid( ChartGraphics graph, double current )
|
|||
|
{
|
|||
|
// Common elements
|
|||
|
CommonElements common = this._axis.Common;
|
|||
|
|
|||
|
PointF first = PointF.Empty; // The First point of a grid line
|
|||
|
PointF second = PointF.Empty; // The Second point of a grid line
|
|||
|
RectangleF plotArea; // Plot area position
|
|||
|
|
|||
|
plotArea = _axis.PlotAreaPosition.ToRectangleF();
|
|||
|
|
|||
|
// Horizontal gridlines
|
|||
|
if( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right )
|
|||
|
{
|
|||
|
first.X = plotArea.X;
|
|||
|
second.X = plotArea.Right;
|
|||
|
first.Y = (float)_axis.GetLinearPosition( current );
|
|||
|
second.Y = first.Y;
|
|||
|
}
|
|||
|
|
|||
|
// Vertical gridlines
|
|||
|
if( _axis.AxisPosition == AxisPosition.Top || _axis.AxisPosition == AxisPosition.Bottom )
|
|||
|
{
|
|||
|
first.Y = plotArea.Y;
|
|||
|
second.Y = plotArea.Bottom;
|
|||
|
first.X = (float)_axis.GetLinearPosition( current );
|
|||
|
second.X = first.X;
|
|||
|
}
|
|||
|
|
|||
|
if( common.ProcessModeRegions )
|
|||
|
{
|
|||
|
if( this._axis.ChartArea.Area3DStyle.Enable3D && !this._axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
if(!common.ProcessModePaint) //if ProcessModePaint is true it will be called later
|
|||
|
graph.Draw3DGridLine(this._axis.ChartArea, borderColor, borderWidth, borderDashStyle, first, second, ( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right ), common, this );
|
|||
|
}
|
|||
|
else if(!this._axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
using (GraphicsPath path = new GraphicsPath())
|
|||
|
{
|
|||
|
if (Math.Abs(first.X - second.X) > Math.Abs(first.Y - second.Y))
|
|||
|
{
|
|||
|
path.AddLine(first.X, first.Y - 1, second.X, second.Y - 1);
|
|||
|
path.AddLine(second.X, second.Y + 1, first.X, first.Y + 1);
|
|||
|
path.CloseAllFigures();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
path.AddLine(first.X - 1, first.Y, second.X - 1, second.Y);
|
|||
|
path.AddLine(second.X + 1, second.Y, first.X + 1, first.Y);
|
|||
|
path.CloseAllFigures();
|
|||
|
|
|||
|
}
|
|||
|
common.HotRegionsList.AddHotRegion(path, true, ChartElementType.Gridlines, this);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( common.ProcessModePaint )
|
|||
|
{
|
|||
|
// Check if grid lines should be drawn for circular chart area
|
|||
|
if(_axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
if(_axis.axisType == AxisName.Y)
|
|||
|
{
|
|||
|
_axis.DrawCircularLine( this, graph, borderColor, borderWidth, borderDashStyle, first.Y );
|
|||
|
}
|
|||
|
if(_axis.axisType == AxisName.X)
|
|||
|
{
|
|||
|
ICircularChartType chartType = this._axis.ChartArea.GetCircularChartType();
|
|||
|
if(chartType != null && chartType.RadialGridLinesSupported())
|
|||
|
{
|
|||
|
_axis.DrawRadialLine( this, graph, borderColor, borderWidth, borderDashStyle, current );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else if(!this._axis.ChartArea.Area3DStyle.Enable3D || this._axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
graph.DrawLineRel( borderColor, borderWidth, borderDashStyle, first, second );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
graph.Draw3DGridLine( this._axis.ChartArea, borderColor, borderWidth, borderDashStyle, first, second, ( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right ), _axis.Common, this );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Draws custom grid lines from custom labels.
|
|||
|
/// </summary>
|
|||
|
/// <param name="graph">Reference to the Chart Graphics object.</param>
|
|||
|
internal void PaintCustom( ChartGraphics graph )
|
|||
|
{
|
|||
|
// Common Elements
|
|||
|
CommonElements common = this._axis.Common;
|
|||
|
|
|||
|
PointF first = PointF.Empty; // The First point of a grid line
|
|||
|
PointF second = PointF.Empty; // The Second point of a grid line
|
|||
|
RectangleF plotArea = _axis.PlotAreaPosition.ToRectangleF(); // Plot area position
|
|||
|
|
|||
|
|
|||
|
// Loop through all custom labels
|
|||
|
foreach(CustomLabel label in _axis.CustomLabels)
|
|||
|
{
|
|||
|
if((label.GridTicks & GridTickTypes.Gridline) == GridTickTypes.Gridline)
|
|||
|
{
|
|||
|
double position = (label.ToPosition + label.FromPosition) / 2.0;
|
|||
|
if(position >= _axis.ViewMinimum && position <= _axis.ViewMaximum)
|
|||
|
{
|
|||
|
// Horizontal gridlines
|
|||
|
if( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right )
|
|||
|
{
|
|||
|
first.X = plotArea.X;
|
|||
|
second.X = plotArea.Right;
|
|||
|
first.Y = (float)_axis.GetLinearPosition( position );
|
|||
|
second.Y = first.Y;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// Vertical gridlines
|
|||
|
if( _axis.AxisPosition == AxisPosition.Top || _axis.AxisPosition == AxisPosition.Bottom )
|
|||
|
{
|
|||
|
first.Y = plotArea.Y;
|
|||
|
second.Y = plotArea.Bottom;
|
|||
|
first.X = (float)_axis.GetLinearPosition( position );
|
|||
|
second.X = first.X;
|
|||
|
}
|
|||
|
|
|||
|
if( common.ProcessModeRegions )
|
|||
|
{
|
|||
|
if( !this._axis.ChartArea.Area3DStyle.Enable3D || this._axis.ChartArea.chartAreaIsCurcular )
|
|||
|
{
|
|||
|
using (GraphicsPath path = new GraphicsPath())
|
|||
|
{
|
|||
|
|
|||
|
if (Math.Abs(first.X - second.X) > Math.Abs(first.Y - second.Y))
|
|||
|
{
|
|||
|
path.AddLine(first.X, first.Y - 1, second.X, second.Y - 1);
|
|||
|
path.AddLine(second.X, second.Y + 1, first.X, first.Y + 1);
|
|||
|
path.CloseAllFigures();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
path.AddLine(first.X - 1, first.Y, second.X - 1, second.Y);
|
|||
|
path.AddLine(second.X + 1, second.Y, first.X + 1, first.Y);
|
|||
|
path.CloseAllFigures();
|
|||
|
|
|||
|
}
|
|||
|
common.HotRegionsList.AddHotRegion(path, true, ChartElementType.Gridlines, this);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
graph.Draw3DGridLine(this._axis.ChartArea, borderColor, borderWidth, borderDashStyle, first, second, ( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right ), common, this );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( common.ProcessModePaint )
|
|||
|
{
|
|||
|
if(!this._axis.ChartArea.Area3DStyle.Enable3D || this._axis.ChartArea.chartAreaIsCurcular)
|
|||
|
{
|
|||
|
graph.DrawLineRel( borderColor, borderWidth, borderDashStyle, first, second );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
graph.Draw3DGridLine(this._axis.ChartArea, borderColor, borderWidth, borderDashStyle, first, second, ( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right ), _axis.Common, this );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Grid properties
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets grid or tick mark interval offset.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeData"),
|
|||
|
Bindable(true),
|
|||
|
SRDescription("DescriptionAttributeIntervalOffset3"),
|
|||
|
TypeConverter(typeof(AxisElementIntervalValueConverter)),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute),
|
|||
|
#endif
|
|||
|
]
|
|||
|
public double IntervalOffset
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return intervalOffset;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
intervalOffset = value;
|
|||
|
intervalOffsetChanged = true;
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Determines if Enabled property should be serialized.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal bool ShouldSerializeIntervalOffset()
|
|||
|
{
|
|||
|
if (this.majorGridTick)
|
|||
|
{
|
|||
|
return !double.IsNaN(intervalOffset);
|
|||
|
}
|
|||
|
return intervalOffset != 0d;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the interval offset.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal double GetIntervalOffset()
|
|||
|
{
|
|||
|
if(this.majorGridTick && double.IsNaN(intervalOffset) && this._axis != null)
|
|||
|
{
|
|||
|
|
|||
|
return this._axis.IntervalOffset;
|
|||
|
}
|
|||
|
return intervalOffset;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets the unit of measurement of grid or tick mark offset.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeData"),
|
|||
|
Bindable(true),
|
|||
|
SRDescription("DescriptionAttributeIntervalOffsetType6"),
|
|||
|
RefreshPropertiesAttribute(RefreshProperties.All),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
#endif
|
|||
|
]
|
|||
|
public DateTimeIntervalType IntervalOffsetType
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return intervalOffsetType;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
intervalOffsetType = value;
|
|||
|
intervalOffsetTypeChanged = true;
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Determines if IntervalOffsetType property should be serialized.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal bool ShouldSerializeIntervalOffsetType()
|
|||
|
{
|
|||
|
if (this.majorGridTick)
|
|||
|
{
|
|||
|
return intervalOffsetType != DateTimeIntervalType.NotSet;
|
|||
|
}
|
|||
|
return intervalOffsetType != DateTimeIntervalType.Auto;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the type of the interval offset.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal DateTimeIntervalType GetIntervalOffsetType()
|
|||
|
{
|
|||
|
if(this.majorGridTick && intervalOffsetType == DateTimeIntervalType.NotSet && this._axis != null)
|
|||
|
{
|
|||
|
return this._axis.IntervalOffsetType;
|
|||
|
}
|
|||
|
return intervalOffsetType;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets grid or tick mark interval size.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeData"),
|
|||
|
Bindable(true),
|
|||
|
SRDescription("DescriptionAttributeInterval6"),
|
|||
|
TypeConverter(typeof(AxisElementIntervalValueConverter)),
|
|||
|
RefreshProperties(RefreshProperties.All),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
#endif
|
|||
|
]
|
|||
|
public double Interval
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return interval;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
// Validation
|
|||
|
if (value < 0.0)
|
|||
|
throw (new ArgumentException(SR.ExceptionTickMarksIntervalIsNegative, "value"));
|
|||
|
|
|||
|
interval = value;
|
|||
|
intervalChanged = true;
|
|||
|
|
|||
|
// Enable minor elements
|
|||
|
if (!this.majorGridTick && value != 0.0 && !Double.IsNaN(value))
|
|||
|
{
|
|||
|
// Prevent grids enabling during the serialization
|
|||
|
if (this._axis != null)
|
|||
|
{
|
|||
|
if (this._axis.Chart != null && this._axis.Chart.serializing != false)
|
|||
|
{
|
|||
|
this.Enabled = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Reset original property value fields
|
|||
|
if (this._axis != null)
|
|||
|
{
|
|||
|
if (this is TickMark)
|
|||
|
{
|
|||
|
if (this.majorGridTick)
|
|||
|
{
|
|||
|
this._axis.tempMajorTickMarkInterval = interval;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
this._axis.tempMinorTickMarkInterval = interval;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (this.majorGridTick)
|
|||
|
{
|
|||
|
this._axis.tempMajorGridInterval = interval;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
this._axis.tempMinorGridInterval = interval;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Determines if IntervalOffsetType property should be serialized.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal bool ShouldSerializeInterval()
|
|||
|
{
|
|||
|
if (this.majorGridTick)
|
|||
|
{
|
|||
|
return !double.IsNaN(interval);
|
|||
|
}
|
|||
|
return interval != 0d;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the interval.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal double GetInterval()
|
|||
|
{
|
|||
|
if(this.majorGridTick && double.IsNaN(interval) && this._axis != null)
|
|||
|
{
|
|||
|
return this._axis.Interval;
|
|||
|
}
|
|||
|
return interval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets the unit of measurement of grid or tick mark interval.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeData"),
|
|||
|
Bindable(true),
|
|||
|
SRDescription("DescriptionAttributeIntervalType3"),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute),
|
|||
|
#endif
|
|||
|
RefreshPropertiesAttribute(RefreshProperties.All)
|
|||
|
]
|
|||
|
public DateTimeIntervalType IntervalType
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return intervalType;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
intervalType = value;
|
|||
|
intervalTypeChanged = true;
|
|||
|
|
|||
|
// Reset original property value fields
|
|||
|
if (this._axis != null)
|
|||
|
{
|
|||
|
if (this is TickMark)
|
|||
|
{
|
|||
|
this._axis.tempTickMarkIntervalType = intervalType;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
this._axis.tempGridIntervalType = intervalType;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Determines if IntervalOffsetType property should be serialized.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal bool ShouldSerializeIntervalType()
|
|||
|
{
|
|||
|
if (this.majorGridTick)
|
|||
|
{
|
|||
|
return intervalType != DateTimeIntervalType.NotSet;
|
|||
|
}
|
|||
|
return intervalType != DateTimeIntervalType.Auto;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the type of the interval.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal DateTimeIntervalType GetIntervalType()
|
|||
|
{
|
|||
|
if(this.majorGridTick && intervalType == DateTimeIntervalType.NotSet && this._axis != null)
|
|||
|
{
|
|||
|
// Return default value during serialization
|
|||
|
return this._axis.IntervalType;
|
|||
|
}
|
|||
|
return intervalType;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets grid or tick mark line color.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
Bindable(true),
|
|||
|
DefaultValue(typeof(Color), "Black"),
|
|||
|
SRDescription("DescriptionAttributeLineColor"),
|
|||
|
TypeConverter(typeof(ColorConverter)),
|
|||
|
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
#endif
|
|||
|
]
|
|||
|
public Color LineColor
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return borderColor;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
borderColor = value;
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets grid or tick mark line style.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
Bindable(true),
|
|||
|
DefaultValue(ChartDashStyle.Solid),
|
|||
|
SRDescription("DescriptionAttributeLineDashStyle"),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
#endif
|
|||
|
]
|
|||
|
public ChartDashStyle LineDashStyle
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return borderDashStyle;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
borderDashStyle = value;
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets grid or tick mark line width.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
Bindable(true),
|
|||
|
DefaultValue(1),
|
|||
|
SRDescription("DescriptionAttributeLineWidth"),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
#endif
|
|||
|
]
|
|||
|
public int LineWidth
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return borderWidth;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
borderWidth = value;
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets a flag which indicates if the grid or tick mark is enabled.
|
|||
|
/// </summary>
|
|||
|
[
|
|||
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
Bindable(true),
|
|||
|
SRDescription("DescriptionAttributeEnabled5"),
|
|||
|
#if !Microsoft_CONTROL
|
|||
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
#endif
|
|||
|
]
|
|||
|
public bool Enabled
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
//// Never serialize this property for minor elements
|
|||
|
//// "Disabled" property should be serialized instead.
|
|||
|
//if(this.axis != null && this.axis.IsSerializing())
|
|||
|
//{
|
|||
|
// if(!this.majorGridTick)
|
|||
|
// {
|
|||
|
// // Return default value to prevent serialization
|
|||
|
// return true;
|
|||
|
// }
|
|||
|
//}
|
|||
|
|
|||
|
return enabled;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
enabled = value;
|
|||
|
enabledChanged = true;
|
|||
|
this.Invalidate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Determines if Enabled property should be serialized.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal bool ShouldSerializeEnabled()
|
|||
|
{
|
|||
|
if (this.majorGridTick)
|
|||
|
{
|
|||
|
return !this.Enabled;
|
|||
|
}
|
|||
|
return this.Enabled;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets the reference to the Axis object
|
|||
|
/// </summary>
|
|||
|
internal Axis Axis
|
|||
|
{
|
|||
|
get { return _axis; }
|
|||
|
set { _axis = value; }
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|