//------------------------------------------------------------- // // Copyright © Microsoft Corporation. All Rights Reserved. // //------------------------------------------------------------- // @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 /// /// An enumeration of tick mark styles. /// public enum TickMarkStyle { /// /// Tickmarks are disabled. /// None, /// /// Tickmarks are located outside of the chart area. /// OutsideArea, /// /// Tickmarks are located inside of the chart area. /// InsideArea, /// /// Tickmarks are set across the axis line. /// AcrossAxis }; #endregion /// /// 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. /// [ 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; /// /// Public default constructor /// public TickMark() : base(null, true) { } /// /// Public constructor /// /// Axis which owns the grid or tick mark. /// Major axis element. internal TickMark(Axis axis, bool major) : base(axis, major) { } #endregion #region Tick marks painting method /// /// Draws and hit test for TickMarks. /// /// Reference to the Chart Graphics object. /// Back elements of the axis should be drawn in 3D scene. 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 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’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; } } /// /// This method returns linearized logarithmic value /// which is minimum for range with interval 1. /// /// Current value /// First series attached to axis. /// Returns Minimum for the range which contains current value 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 )); } /// /// Draws and hit test for custom TickMarks from the custom labels collection. /// /// Reference to the Chart Graphics object. /// Back elements of the axis should be drawn in 3D scene. 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); } } } } } } /// /// Draws tick mark line in 3D space. /// /// Reference to the Chart Graphics object. /// First line point. /// Second line point. /// Back elements of the axis should be drawn in 3D scene. 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 /// /// Tick mark style. /// [ 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(); } } /// /// Tick mark size. /// [ 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 } /// /// 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. /// [ 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; /// /// Public default constructor. /// public Grid() { } /// /// Public constructor. /// /// Axis which owns the grid. /// Major axis element. internal Grid(Axis axis, bool major) { Initialize(axis, major); } /// /// Initializes the object. /// /// Axis which owns the grid. /// Major axis element. 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 /// /// Gets axes to which this object attached to /// /// Axis object. internal Axis GetAxis() { return _axis; } /// /// Invalidate chart area the axis belong to. /// internal void Invalidate() { #if Microsoft_CONTROL if(this._axis != null) { this._axis.Invalidate(); } #endif } #endregion #region Grid lines drawing functions /// /// Draws grid lines. /// /// Reference to the Chart Graphics object. 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 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’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; } } /// /// This method returns linearized logarithmic value /// which is minimum for range with interval 1. /// /// Current value /// First series attached to axis. /// Returns Minimum for the range which contains current value 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 )); } /// /// Draw the grid line /// /// Chart Graphics object /// Current position of the gridline 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 ); } } } /// /// Draws custom grid lines from custom labels. /// /// Reference to the Chart Graphics object. 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 /// /// Gets or sets grid or tick mark interval offset. /// [ 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(); } } /// /// Determines if Enabled property should be serialized. /// /// internal bool ShouldSerializeIntervalOffset() { if (this.majorGridTick) { return !double.IsNaN(intervalOffset); } return intervalOffset != 0d; } /// /// Gets the interval offset. /// /// internal double GetIntervalOffset() { if(this.majorGridTick && double.IsNaN(intervalOffset) && this._axis != null) { return this._axis.IntervalOffset; } return intervalOffset; } /// /// Gets or sets the unit of measurement of grid or tick mark offset. /// [ 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(); } } /// /// Determines if IntervalOffsetType property should be serialized. /// /// internal bool ShouldSerializeIntervalOffsetType() { if (this.majorGridTick) { return intervalOffsetType != DateTimeIntervalType.NotSet; } return intervalOffsetType != DateTimeIntervalType.Auto; } /// /// Gets the type of the interval offset. /// /// internal DateTimeIntervalType GetIntervalOffsetType() { if(this.majorGridTick && intervalOffsetType == DateTimeIntervalType.NotSet && this._axis != null) { return this._axis.IntervalOffsetType; } return intervalOffsetType; } /// /// Gets or sets grid or tick mark interval size. /// [ 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(); } } /// /// Determines if IntervalOffsetType property should be serialized. /// /// internal bool ShouldSerializeInterval() { if (this.majorGridTick) { return !double.IsNaN(interval); } return interval != 0d; } /// /// Gets the interval. /// /// internal double GetInterval() { if(this.majorGridTick && double.IsNaN(interval) && this._axis != null) { return this._axis.Interval; } return interval; } /// /// Gets or sets the unit of measurement of grid or tick mark interval. /// [ 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(); } } /// /// Determines if IntervalOffsetType property should be serialized. /// /// internal bool ShouldSerializeIntervalType() { if (this.majorGridTick) { return intervalType != DateTimeIntervalType.NotSet; } return intervalType != DateTimeIntervalType.Auto; } /// /// Gets the type of the interval. /// /// internal DateTimeIntervalType GetIntervalType() { if(this.majorGridTick && intervalType == DateTimeIntervalType.NotSet && this._axis != null) { // Return default value during serialization return this._axis.IntervalType; } return intervalType; } /// /// Gets or sets grid or tick mark line color. /// [ 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(); } } /// /// Gets or sets grid or tick mark line style. /// [ 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(); } } /// /// Gets or sets grid or tick mark line width. /// [ 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(); } } /// /// Gets or sets a flag which indicates if the grid or tick mark is enabled. /// [ 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(); } } /// /// Determines if Enabled property should be serialized. /// /// internal bool ShouldSerializeEnabled() { if (this.majorGridTick) { return !this.Enabled; } return this.Enabled; } /// /// Gets or sets the reference to the Axis object /// internal Axis Axis { get { return _axis; } set { _axis = value; } } #endregion } }