// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//
// Purpose: Base class for all anotation objects. Provides
// basic set of properties and methods.
//
using System;
using System.Windows.Forms;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Globalization;
using FastReport.DataVisualization.Charting.Utilities;
namespace FastReport.DataVisualization.Charting
{
#region Enumerations
///
/// Annotation object selection points style.
///
///
/// Enumeration is for internal use only and should not be part of the documentation.
///
internal enum SelectionPointsStyle
{
///
/// Selection points are displayed top left and bottom right corners
///
TwoPoints,
///
/// Selection points are displayed on all sides and corners of the rectangle.
///
Rectangle,
}
///
/// Annotation object resizing\moving mode.
///
///
/// Enumeration is for internal use only and should not be part of the documentation.
///
internal enum ResizingMode
{
///
/// Top Left selection handle is used.
///
TopLeftHandle = 0,
///
/// Top selection handle is used.
///
TopHandle = 1,
///
/// Top Right selection handle is used.
///
TopRightHandle = 2,
///
/// Right selection handle is used.
///
RightHandle = 3,
///
/// Bottom Right selection handle is used.
///
BottomRightHandle = 4,
///
/// Bottom selection handle is used.
///
BottomHandle = 5,
///
/// Bottom Left selection handle is used.
///
BottomLeftHandle = 6,
///
/// Left selection handle is used.
///
LeftHandle = 7,
///
/// Anchor selection handle is used.
///
AnchorHandle = 8,
///
/// No selection handles used - moving mode.
///
Moving = 16,
///
/// Moving points of the annotation path.
///
MovingPathPoints = 32,
///
/// No moving or resizing.
///
None = 64,
}
#endregion
///
/// Annotation is an abstract class that defines properties and methods
/// common to all annotations.
///
///
/// All annotations are derived from the Annotation class, which can be
/// used to set properties common to all annotation objects (e.g. color, position,
/// anchoring and others).
///
[
SRDescription("DescriptionAttributeAnnotation_Annotation"),
DefaultProperty("Name"),
]
public abstract class Annotation : ChartNamedElement
{
#region Fields
// Name of the chart area the annotation is clipped to
private string _clipToChartArea = Constants.NotSetValue;
// Indicates that annotation is selected
private bool _isSelected = false;
// Indicates that annotation size is defined in relative chart coordinates
private bool _isSizeAlwaysRelative = true;
// Position attribute fields
private double _x = double.NaN;
private double _y = double.NaN;
private double _width = double.NaN;
private double _height = double.NaN;
// Annotation axes attaching fields
private string _axisXName = String.Empty;
private string _axisYName = String.Empty;
private Axis _axisX = null;
private Axis _axisY = null;
// Visual attribute fields
private bool _visible = true;
private ContentAlignment _alignment = ContentAlignment.MiddleCenter;
private Color _foreColor = Color.Black;
private FontCache _fontCache = new FontCache();
private Font _textFont;
private TextStyle _textStyle = TextStyle.Default;
internal Color lineColor = Color.Black;
private int _lineWidth = 1;
private ChartDashStyle _lineDashStyle = ChartDashStyle.Solid;
private Color _backColor = Color.Empty;
private ChartHatchStyle _backHatchStyle = ChartHatchStyle.None;
private GradientStyle _backGradientStyle = GradientStyle.None;
private Color _backSecondaryColor = Color.Empty;
private Color _shadowColor = Color.FromArgb(128, 0, 0, 0);
private int _shadowOffset = 0;
// Anchor position attribute fields
private string _anchorDataPointName = String.Empty;
private DataPoint _anchorDataPoint = null;
private DataPoint _anchorDataPoint2 = null;
private double _anchorX = double.NaN;
private double _anchorY = double.NaN;
internal double anchorOffsetX = 0.0;
internal double anchorOffsetY = 0.0;
internal ContentAlignment anchorAlignment = ContentAlignment.BottomCenter;
// Selection handles position (starting top-left and moving clockwise)
internal RectangleF[] selectionRects = null;
// Annotation tooltip
private string _tooltip = String.Empty;
// Selection handles size
internal const int selectionMarkerSize = 6;
// Pre calculated relative position of annotation and anchor point
internal RectangleF currentPositionRel = new RectangleF(float.NaN, float.NaN, float.NaN, float.NaN);
internal PointF currentAnchorLocationRel = new PointF(float.NaN, float.NaN);
// Smart labels style
private AnnotationSmartLabelStyle _smartLabelStyle = null;
// Index of last selected point in the annotation path
internal int currentPathPointIndex = -1;
// Group this annotation belongs too
internal AnnotationGroup annotationGroup = null;
// Selection and editing permissions
private bool _allowSelecting = false;
private bool _allowMoving = false;
private bool _allowAnchorMoving = false;
private bool _allowResizing = false;
private bool _allowTextEditing = false;
private bool _allowPathEditing = false;
// Indicates that annotation position was changed. Flag used to fire events.
internal bool positionChanged = false;
// Relative location of last placement position
internal PointF lastPlacementPosition = PointF.Empty;
// Relative location of annotation anchor, when it's started to move
internal PointF startMoveAnchorLocationRel = PointF.Empty;
// Relative position of annotation, when it's started to move/resize
internal RectangleF startMovePositionRel = RectangleF.Empty;
// Relative position of annotation, when it's started to move/resize
internal GraphicsPath startMovePathRel = null;
///
/// Limit of annotation width and height.
///
internal static double WidthHightLimit = 290000000;
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
protected Annotation()
{
_textFont = _fontCache.DefaultFont;
}
#endregion
#region Properties
#region Miscellaneous
///
/// Gets or sets an annotation's unique name.
///
///
/// A string that represents an annotation's unique name.
///
[
SRCategory("CategoryAttributeMisc"),
Bindable(true),
SRDescription("DescriptionAttributeName4"),
ParenthesizePropertyNameAttribute(true),
]
public override string Name
{
get
{
return base.Name;
}
set
{
base.Name = value;
CallOnModifing();
}
}
///
/// Gets or sets an annotation's type name.
///
///
/// This property is used to get the name of each annotation Style
/// (e.g. Line, Rectangle, Ellipse).
///
/// This property is for internal use and is hidden at design and run time.
///
///
[
SRCategory("CategoryAttributeMisc"),
Bindable(true),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeAnnotation_AnnotationType"),
]
public abstract string AnnotationType
{
get;
}
///
/// Gets or sets the name of the chart area which an annotation is clipped to.
///
///
/// A string which represents the name of an existing chart area.
///
///
/// If the chart area name is specified, an annotation will only be drawn inside the
/// plotting area of the chart area specified. All parts of the annotation
/// outside of the plotting area will be clipped.
///
/// To disable chart area clipping, set the property to "NotSet" or an empty string.
///
///
[
SRCategory("CategoryAttributeMisc"),
DefaultValue(Constants.NotSetValue),
SRDescription("DescriptionAttributeAnnotationClipToChartArea"),
TypeConverter(typeof(LegendAreaNameConverter))
]
virtual public string ClipToChartArea
{
get
{
return _clipToChartArea;
}
set
{
if (value != _clipToChartArea)
{
if (String.IsNullOrEmpty(value))
{
_clipToChartArea = Constants.NotSetValue;
}
else
{
if (Chart != null && Chart.ChartAreas != null)
{
Chart.ChartAreas.VerifyNameReference(value);
}
_clipToChartArea = value;
}
this.Invalidate();
CallOnModifing();
}
}
}
///
/// Gets or sets the smart labels style of an annotation.
///
///
/// An object that represents an annotation's
/// smart labels style properties.
///
///
/// Smart labels are used to prevent an annotation from overlapping data point labels
/// and other annotations.
///
/// Note that data point labels must also have smart labels enabled.
///
///
[
Browsable(true),
SRCategory("CategoryAttributeMisc"),
Bindable(true),
SRDescription("DescriptionAttributeSmartLabels"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
]
public AnnotationSmartLabelStyle SmartLabelStyle
{
get
{
if (this._smartLabelStyle == null)
{
this._smartLabelStyle = new AnnotationSmartLabelStyle(this);
}
return _smartLabelStyle;
}
set
{
value.chartElement = this;
_smartLabelStyle = value;
this.Invalidate();
CallOnModifing();
}
}
///
/// Gets the group, if any, the annotation belongs to.
///
[
Browsable(false),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
]
public AnnotationGroup AnnotationGroup
{
get { return this.annotationGroup; }
}
#endregion
#region Position
///
/// Gets or sets a flag that specifies whether the size of an annotation is always
/// defined in relative chart coordinates.
///
///
///
///
/// True if an annotation's and are always
/// in chart relative coordinates, false otherwise.
///
///
/// An annotation's width and height may be set in relative chart or axes coordinates.
/// By default, relative chart coordinates are used.
///
/// To use axes coordinates for size set the IsSizeAlwaysRelative property to
/// false and either anchor the annotation to a data point or set the
/// or properties.
///
///
[
SRCategory("CategoryAttributePosition"),
DefaultValue(true),
SRDescription("DescriptionAttributeSizeAlwaysRelative"),
]
virtual public bool IsSizeAlwaysRelative
{
get
{
return _isSizeAlwaysRelative;
}
set
{
_isSizeAlwaysRelative = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the X coordinate of an annotation.
///
///
///
///
/// A Double value that represents the X coordinate of an annotation.
///
///
/// The X coordinate of an annotation is in relative chart coordinates or axes coordinates. Chart
/// relative coordinates are used by default.
///
/// To use axes coordinates, anchor
/// an annotation to a data point using the property, or
/// set the annotation axes using the or properties.
///
///
/// Set the X position to Double.NaN ("NotSet") to achieve automatic position calculation
/// when the annotation is anchored using the property or
/// the and properties.
///
///
[
SRCategory("CategoryAttributePosition"),
DefaultValue(double.NaN),
SRDescription("DescriptionAttributeAnnotationBaseX"),
RefreshPropertiesAttribute(RefreshProperties.All),
TypeConverter(typeof(DoubleNanValueConverter)),
]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "X")]
virtual public double X
{
get
{
return _x;
}
set
{
_x = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the Y coordinate of an annotation.
///
///
///
///
/// A Double value that represents the Y coordinate of an annotation.
///
///
/// The Y coordinate of an annotation is in relative chart coordinates or axes coordinates. Chart
/// relative coordinates are used by default.
///
/// To use axes coordinates, anchor
/// an annotation to a data point using the property, or
/// set the annotation axes using the or properties.
///
///
/// Set the Y position to Double.NaN ("NotSet") to achieve automatic position calculation
/// when the annotation is anchored using the property or
/// the and properties.
///
///
[
SRCategory("CategoryAttributePosition"),
DefaultValue(double.NaN),
SRDescription("DescriptionAttributeAnnotationBaseY"),
RefreshPropertiesAttribute(RefreshProperties.All),
TypeConverter(typeof(DoubleNanValueConverter)),
]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Y")]
virtual public double Y
{
get
{
return _y;
}
set
{
_y = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets an annotation's width.
///
///
///
///
/// A Double value that represents an annotation's width.
///
///
/// An annotation's width can be a negative value, in which case the annotation orientation
/// is switched.
///
/// Annotation width can be in relative chart or axes coordinates. Chart
/// relative coordinates are used by default.
///
///
/// To use axes coordinates, anchor
/// an annotation to a data point using the property, or
/// set the annotation axes using the or properties
/// and set the property to false.
///
///
/// Set the width to Double.NaN ("NotSet") to achieve automatic size calculation for
/// annotations with text. The size will automatically be calculated based on
/// the annotation text and font size.
///
///
[
SRCategory("CategoryAttributePosition"),
DefaultValue(double.NaN),
SRDescription("DescriptionAttributeAnnotationWidth"),
RefreshPropertiesAttribute(RefreshProperties.All),
TypeConverter(typeof(DoubleNanValueConverter)),
]
virtual public double Width
{
get
{
return _width;
}
set
{
if (value < -WidthHightLimit || value > WidthHightLimit)
{
throw new ArgumentException(SR.ExceptionValueMustBeInRange("Width", (-WidthHightLimit).ToString(CultureInfo.CurrentCulture), WidthHightLimit.ToString(CultureInfo.CurrentCulture)));
}
_width = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets an annotation's height.
///
///
///
///
/// A Double value that represents an annotation's height.
///
///
/// An annotation's height can be a negative value, in which case the annotation orientation
/// is switched.
///
/// Annotation height can be in relative chart or axes coordinates. Chart
/// relative coordinates are used by default.
///
///
/// To use axes coordinates, anchor
/// an annotation to a data point using the property, or
/// set the annotation axes using the or properties
/// and set the property to false.
///
///
/// Set the height to Double.NaN ("NotSet") to achieve automatic size calculation for
/// annotations with text. The size will automatically be calculated based on
/// the annotation text and font size.
///
///
[
SRCategory("CategoryAttributePosition"),
DefaultValue(double.NaN),
SRDescription("DescriptionAttributeAnnotationHeight"),
RefreshPropertiesAttribute(RefreshProperties.All),
TypeConverter(typeof(DoubleNanValueConverter)),
]
virtual public double Height
{
get
{
return _height;
}
set
{
if (value < -WidthHightLimit || value > WidthHightLimit)
{
throw new ArgumentException(SR.ExceptionValueMustBeInRange("Height", (-WidthHightLimit).ToString(CultureInfo.CurrentCulture), WidthHightLimit.ToString(CultureInfo.CurrentCulture)));
}
_height = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets an annotation position's right boundary.
///
///
///
///
/// A Double value that represents the position of an annotation's right boundary.
///
///
/// To use axes coordinates, anchor
/// an annotation to a data point using the property, or
/// set the annotation axes using the or properties
/// and set the property to false.
///
[
SRCategory("CategoryAttributePosition"),
DefaultValue(double.NaN),
SRDescription("DescriptionAttributeRight3"),
RefreshPropertiesAttribute(RefreshProperties.All),
Browsable(false),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
TypeConverter(typeof(DoubleNanValueConverter)),
]
virtual public double Right
{
get
{
return _x + _width;
}
set
{
_width = value - _x;
this.ResetCurrentRelativePosition();
Invalidate();
}
}
///
/// Gets or sets an annotation position's bottom boundary.
///
///
///
///
/// A Double value that represents the position of an annotation's bottom boundary.
///
///
/// To use axes coordinates, anchor
/// an annotation to a data point using the property, or
/// set the annotation axes using the or properties
/// and set the property to false.
///
[
SRCategory("CategoryAttributePosition"),
DefaultValue(double.NaN),
SRDescription("DescriptionAttributeBottom"),
RefreshPropertiesAttribute(RefreshProperties.All),
Browsable(false),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
TypeConverter(typeof(DoubleNanValueConverter)),
]
virtual public double Bottom
{
get
{
return _y + _height;
}
set
{
_height = value - _y;
this.ResetCurrentRelativePosition();
Invalidate();
}
}
#endregion
#region Visual Attributes
///
/// Gets or sets a flag that determines if an annotation is selected.
///
///
///
/// True if the annotation is selected, false otherwise.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(false),
Browsable(false),
SRDescription("DescriptionAttributeSelected"),
]
virtual public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
Invalidate();
}
}
///
/// Gets or sets an annotation selection points style.
///
///
/// A value that represents annotation
/// selection style.
///
///
/// This property is for internal use and is hidden at design and run time.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(SelectionPointsStyle.Rectangle),
ParenthesizePropertyNameAttribute(true),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeSelectionPointsStyle"),
]
virtual internal SelectionPointsStyle SelectionPointsStyle
{
get
{
return SelectionPointsStyle.Rectangle;
}
}
///
/// Gets or sets a flag that specifies whether an annotation is visible.
///
///
/// True if the annotation is visible, false otherwise.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(true),
SRDescription("DescriptionAttributeVisible"),
ParenthesizePropertyNameAttribute(true),
]
virtual public bool Visible
{
get
{
return _visible;
}
set
{
_visible = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets an annotation's content alignment.
///
///
/// A value that represents the content alignment.
///
///
/// This property is used to align text for , ,
/// and objects, and to align
/// a non-scaled image inside an object.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(ContentAlignment), "MiddleCenter"),
SRDescription("DescriptionAttributeAlignment"),
]
virtual public ContentAlignment Alignment
{
get
{
return _alignment;
}
set
{
_alignment = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the text color of an annotation.
///
///
///
/// A value used for the text color of an annotation.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), "Black"),
SRDescription("DescriptionAttributeForeColor"),
TypeConverter(typeof(ColorConverter)),
#if DESIGNER
Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
#endif
]
virtual public Color ForeColor
{
get
{
return _foreColor;
}
set
{
_foreColor = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the font of an annotation's text.
///
///
///
/// A object used for an annotation's text.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
SRDescription("DescriptionAttributeTextFont"),
]
virtual public Font Font
{
get
{
return _textFont;
}
set
{
_textFont = value;
this.Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets an annotation's text style.
///
///
///
///
/// A value used to draw an annotation's text.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(TextStyle), "Default"),
SRDescription("DescriptionAttributeTextStyle"),
]
virtual public TextStyle TextStyle
{
get
{
return _textStyle;
}
set
{
_textStyle = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the color of an annotation line.
///
///
///
///
/// A value used to draw an annotation line.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), "Black"),
SRDescription("DescriptionAttributeLineColor"),
TypeConverter(typeof(ColorConverter)),
#if DESIGNER
Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
#endif
]
virtual public Color LineColor
{
get
{
return lineColor;
}
set
{
lineColor = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the width of an annotation line.
///
///
///
///
/// An integer value defining the width of an annotation line in pixels.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(1),
SRDescription("DescriptionAttributeLineWidth"),
]
virtual public int LineWidth
{
get
{
return _lineWidth;
}
set
{
if (value < 0)
{
throw (new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationLineWidthIsNegative));
}
_lineWidth = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the style of an annotation line.
///
///
///
///
/// A value used to draw an annotation line.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(ChartDashStyle.Solid),
SRDescription("DescriptionAttributeLineDashStyle"),
]
virtual public ChartDashStyle LineDashStyle
{
get
{
return _lineDashStyle;
}
set
{
_lineDashStyle = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the background color of an annotation.
///
///
///
///
///
/// A value used for the background of an annotation.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), ""),
SRDescription("DescriptionAttributeBackColor"),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
#if DESIGNER
Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
#endif
]
virtual public Color BackColor
{
get
{
return _backColor;
}
set
{
_backColor = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the background hatch style of an annotation.
///
///
///
///
///
/// A value used for the background of an annotation.
///
///
/// Two colors are used to draw the hatching, and .
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(ChartHatchStyle.None),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackHatchStyle"),
#if DESIGNER
Editor(typeof(HatchStyleEditor), typeof(UITypeEditor))
#endif
]
virtual public ChartHatchStyle BackHatchStyle
{
get
{
return _backHatchStyle;
}
set
{
_backHatchStyle = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the background gradient style of an annotation.
///
///
///
///
///
/// A value used for the background of an annotation.
///
///
/// Two colors are used to draw the gradient, and .
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(GradientStyle.None),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackGradientStyle"),
#if DESIGNER
Editor(typeof(GradientEditor), typeof(UITypeEditor))
#endif
]
virtual public GradientStyle BackGradientStyle
{
get
{
return _backGradientStyle;
}
set
{
_backGradientStyle = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the secondary background color of an annotation.
///
///
///
///
///
/// A value used for the secondary color of an annotation background with
/// hatching or gradient fill.
///
///
/// This color is used with when or
/// are used.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), ""),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackSecondaryColor"),
TypeConverter(typeof(ColorConverter)),
#if DESIGNER
Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
#endif
]
virtual public Color BackSecondaryColor
{
get
{
return _backSecondaryColor;
}
set
{
_backSecondaryColor = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the color of an annotation's shadow.
///
///
///
/// A value used to draw an annotation's shadow.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), "128,0,0,0"),
SRDescription("DescriptionAttributeShadowColor"),
TypeConverter(typeof(ColorConverter)),
#if DESIGNER
Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
#endif
]
virtual public Color ShadowColor
{
get
{
return _shadowColor;
}
set
{
_shadowColor = value;
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the offset between an annotation and its shadow.
///
///
///
/// An integer value that represents the offset between an annotation and its shadow.
///
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(0),
SRDescription("DescriptionAttributeShadowOffset"),
]
virtual public int ShadowOffset
{
get
{
return _shadowOffset;
}
set
{
_shadowOffset = value;
Invalidate();
CallOnModifing();
}
}
#endregion
#region Axes Attaching
///
/// Gets or sets the name of the X axis which an annotation is attached to.
///
///
/// A string value that represents the name of the X axis which an annotation
/// is attached to.
///
///
/// This property is for internal use and is hidden at design and run time.
///
[
SRCategory("CategoryAttributeAnchorAxes"),
DefaultValue(""),
Browsable(false),
Bindable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
SRDescription("DescriptionAttributeAxisXName"),
]
virtual public string AxisXName
{
get
{
if (_axisXName.Length == 0 && _axisX != null)
{
_axisXName = GetAxisName(_axisX);
}
return _axisXName;
}
set
{
_axisXName = value;
_axisX = null;
this.ResetCurrentRelativePosition();
Invalidate();
}
}
///
/// Gets or sets the name of the Y axis which an annotation is attached to.
///
///
/// A string value that represents the name of the Y axis which an annotation
/// is attached to.
///
///
/// This property is for internal use and is hidden at design and run time.
///
[
SRCategory("CategoryAttributeAnchorAxes"),
Browsable(false),
Bindable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DefaultValue(""),
SRDescription("DescriptionAttributeAxisYName"),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
]
virtual public string AxisYName
{
get
{
// Always return empty string to prevent property serialization
// "YAxisName" property will be used instead.
return string.Empty;
}
set
{
this.YAxisName = value;
}
}
///
/// Gets or sets the name of the Y axis which an annotation is attached to.
/// NOTE: "AxisYName" property was used before but the name was changed to solve the
/// duplicated hash value during the serialization with the "TitleSeparator" property.
///
///
/// A string value that represents the name of the Y axis which an annotation
/// is attached to.
///
///
/// This property is for internal use and is hidden at design and run time.
///
[
SRCategory("CategoryAttributeAnchorAxes"),
Browsable(false),
Bindable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DefaultValue(""),
SRDescription("DescriptionAttributeAxisYName"),
]
virtual public string YAxisName
{
get
{
if (_axisYName.Length == 0 && _axisY != null)
{
_axisYName = GetAxisName(_axisY);
}
return _axisYName;
}
set
{
_axisYName = value;
_axisY = null;
this.ResetCurrentRelativePosition();
Invalidate();
}
}
///
/// Gets or sets the X axis which an annotation is attached to.
///
///
///
///
/// object which an annotation is attached to.
///
///
/// When an annotation is attached to an axis, its X position is always in
/// axis coordinates. To define an annotation's size in axis coordinates as well,
/// make sure the property is set to false.
///
/// Set this value to null or nothing to disable attachment to the axis.
///
///
[
SRCategory("CategoryAttributeAnchorAxes"),
DefaultValue(null),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeAxisX"),
#if DESIGNER
Editor(typeof(AnnotationAxisUITypeEditor), typeof(UITypeEditor)),
#endif
TypeConverter(typeof(AnnotationAxisValueConverter)),
]
virtual public Axis AxisX
{
get
{
if (_axisX == null && _axisXName.Length > 0)
{
_axisX = GetAxisByName(_axisXName);
}
return _axisX;
}
set
{
_axisX = value;
_axisXName = String.Empty;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the Y axis which an annotation is attached to.
///
///
///
///
/// object which an annotation is attached to.
///
///
/// When an annotation is attached to an axis, its Y position is always in
/// axis coordinates. To define an annotation's size in axis coordinates as well,
/// make sure property is set to false.
///
/// Set this value to null or nothing to disable annotation attachment to an axis.
///
///
[
SRCategory("CategoryAttributeAnchorAxes"),
DefaultValue(null),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeAxisY"),
#if DESIGNER
Editor(typeof(AnnotationAxisUITypeEditor), typeof(UITypeEditor)),
#endif
TypeConverter(typeof(AnnotationAxisValueConverter)),
]
virtual public Axis AxisY
{
get
{
if (_axisY == null && _axisYName.Length > 0)
{
_axisY = GetAxisByName(_axisYName);
}
return _axisY;
}
set
{
_axisY = value;
_axisYName = String.Empty;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
#endregion
#region Anchor
///
/// Gets or sets the name of a data point which an annotation is anchored to.
///
///
/// A string value that represents the name of the data point which an
/// annotation is anchored to.
///
///
/// This property is for internal use and is hidden at design and run time.
///
[
SRCategory("CategoryAttributeAnchor"),
Browsable(false),
Bindable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DefaultValue(""),
SRDescription("DescriptionAttributeAnchorDataPointName"),
]
virtual public string AnchorDataPointName
{
get
{
if (_anchorDataPointName.Length == 0 && _anchorDataPoint != null)
{
_anchorDataPointName = GetDataPointName(_anchorDataPoint);
}
return _anchorDataPointName;
}
set
{
_anchorDataPointName = value;
_anchorDataPoint = null;
this.ResetCurrentRelativePosition();
Invalidate();
}
}
///
/// Gets or sets the data point an annotation is anchored to.
///
///
///
///
///
///
///
///
///
/// A object an annotation is anchored to.
///
///
/// The annotation is anchored to the X and Y values of the specified data point,
/// and automatically uses the same axes coordinates as the data point.
///
/// To automatically position an annotation relative to an anchor point, make sure
/// its and properties are set to Double.NaN.
/// The property may be used to change an annotation's
/// automatic position alignment to an anchor point. The and
/// properties may be used to add extra spacing.
///
///
/// When using this property, make sure the and
/// properties are set to Double.NaN (they have precedence).
///
///
/// Set this value to null or nothing to disable annotation anchoring to a data point.
///
///
[
SRCategory("CategoryAttributeAnchor"),
DefaultValue(null),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeAnchorDataPoint"),
#if DESIGNER
Editor(typeof(AnchorPointUITypeEditor), typeof(UITypeEditor)),
#endif
TypeConverter(typeof(AnchorPointValueConverter)),
]
virtual public DataPoint AnchorDataPoint
{
get
{
if (_anchorDataPoint == null && _anchorDataPointName.Length > 0)
{
_anchorDataPoint = GetDataPointByName(_anchorDataPointName);
}
return _anchorDataPoint;
}
set
{
_anchorDataPoint = value;
_anchorDataPointName = String.Empty;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the X coordinate the annotation is anchored to.
///
///
///
///
///
///
///
/// A double value that represents the X coordinate which an annotation is anchored to.
///
///
/// The annotation is anchored to the X coordinate specified in relative or axis coordinates,
/// depending on the property value.
///
/// To automatically position an annotation relative to an anchor point, make sure
/// its property is set to Double.NaN.
/// The property may be used to change the annotation's
/// automatic position alignment to the anchor point. The and
/// properties may be used to add extra spacing.
///
///
/// This property has a higher priority than the property.
///
///
/// Set this value to Double.NaN to disable annotation anchoring to the value.
///
///
[
SRCategory("CategoryAttributeAnchor"),
DefaultValue(double.NaN),
SRDescription("DescriptionAttributeAnchorX"),
RefreshPropertiesAttribute(RefreshProperties.All),
TypeConverter(typeof(DoubleNanValueConverter)),
]
virtual public double AnchorX
{
get
{
return _anchorX;
}
set
{
_anchorX = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the Y coordinate which an annotation is anchored to.
///
///
///
///
///
///
///
/// A double value that represents the Y coordinate which an annotation is anchored to.
///
///
/// The annotation is anchored to the Y coordinate specified in relative or axis coordinates,
/// depending on the property value.
///
/// To automatically position an annotation relative to an anchor point, make sure
/// its property is set to Double.NaN.
/// The property may be used to change the annotation's
/// automatic position alignment to the anchor point. The and
/// properties may be used to add extra spacing.
///
///
/// This property has a higher priority than the property.
///
///
/// Set this value to Double.NaN to disable annotation anchoring to the value.
///
///
[
SRCategory("CategoryAttributeAnchor"),
DefaultValue(double.NaN),
SRDescription("DescriptionAttributeAnchorY"),
RefreshPropertiesAttribute(RefreshProperties.All),
TypeConverter(typeof(DoubleNanValueConverter)),
]
virtual public double AnchorY
{
get
{
return _anchorY;
}
set
{
_anchorY = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the x-coordinate offset between the positions of an annotation and its anchor point.
///
///
///
///
///
///
/// A double value that represents the x-coordinate offset between the positions of an annotation and its anchor point.
///
///
/// The annotation must be anchored using the or
/// properties, and its property must be set
/// to Double.NaN.
///
[
SRCategory("CategoryAttributeAnchor"),
DefaultValue(0.0),
SRDescription("DescriptionAttributeAnchorOffsetX3"),
RefreshPropertiesAttribute(RefreshProperties.All),
]
virtual public double AnchorOffsetX
{
get
{
return anchorOffsetX;
}
set
{
if (value > 100.0 || value < -100.0)
{
throw (new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationAnchorOffsetInvalid));
}
anchorOffsetX = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets the y-coordinate offset between the positions of an annotation and its anchor point.
///
///
///
///
///
///
/// A double value that represents the y-coordinate offset between the positions of an annotation and its anchor point.
///
///
/// Annotation must be anchored using or
/// properties and it's property must be set
/// to Double.NaN.
///
[
SRCategory("CategoryAttributeAnchor"),
DefaultValue(0.0),
SRDescription("DescriptionAttributeAnchorOffsetY3"),
RefreshPropertiesAttribute(RefreshProperties.All),
]
virtual public double AnchorOffsetY
{
get
{
return anchorOffsetY;
}
set
{
if (value > 100.0 || value < -100.0)
{
throw (new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationAnchorOffsetInvalid));
}
anchorOffsetY = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
///
/// Gets or sets an annotation position's alignment to the anchor point.
///
///
///
///
///
///
///
/// A value that represents the annotation's alignment to
/// the anchor point.
///
///
/// The annotation must be anchored using either , or the
/// and properties. Its and
/// properties must be set to Double.NaN.
///
[
SRCategory("CategoryAttributeAnchor"),
DefaultValue(typeof(ContentAlignment), "BottomCenter"),
SRDescription("DescriptionAttributeAnchorAlignment"),
]
virtual public ContentAlignment AnchorAlignment
{
get
{
return anchorAlignment;
}
set
{
anchorAlignment = value;
this.ResetCurrentRelativePosition();
Invalidate();
CallOnModifing();
}
}
#endregion // Anchoring
#region Editing Permissions
///
/// Gets or sets a flag that specifies whether an annotation may be selected
/// with a mouse by the end user.
///
///
/// True if the annotation may be selected, false otherwise.
///
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowSelecting"),
]
virtual public bool AllowSelecting
{
get
{
return _allowSelecting;
}
set
{
_allowSelecting = value;
CallOnModifing();
}
}
///
/// Gets or sets a flag that specifies whether an annotation may be moved
/// with a mouse by the end user.
///
///
/// True if the annotation may be moved, false otherwise.
///
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowMoving"),
]
virtual public bool AllowMoving
{
get
{
return _allowMoving;
}
set
{
_allowMoving = value;
CallOnModifing();
}
}
///
/// Gets or sets a flag that specifies whether an annotation anchor may be moved
/// with a mouse by the end user.
///
///
/// True if the annotation anchor may be moved, false otherwise.
///
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowAnchorMoving3"),
]
virtual public bool AllowAnchorMoving
{
get
{
return _allowAnchorMoving;
}
set
{
_allowAnchorMoving = value;
CallOnModifing();
}
}
///
/// Gets or sets a flag that specifies whether an annotation may be resized
/// with a mouse by the end user.
///
///
/// True if the annotation may be resized, false otherwise.
///
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowResizing"),
]
virtual public bool AllowResizing
{
get
{
return _allowResizing;
}
set
{
_allowResizing = value;
CallOnModifing();
}
}
///
/// Gets or sets a flag that specifies whether an annotation's text may be edited
/// when the end user double clicks on the text.
///
///
/// True if the annotation text may be edited, false otherwise.
///
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowTextEditing"),
]
virtual public bool AllowTextEditing
{
get
{
return _allowTextEditing;
}
set
{
_allowTextEditing = value;
CallOnModifing();
}
}
///
/// Gets or sets a flag that specifies whether a polygon annotation's points
/// may be moved with a mouse by the end user.
///
///
/// True if the polygon annotation's points may be moved, false otherwise.
///
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowPathEditing3"),
]
virtual public bool AllowPathEditing
{
get
{
return _allowPathEditing;
}
set
{
_allowPathEditing = value;
CallOnModifing();
}
}
#endregion
#region Interactivity
///
/// Gets or sets an annotation's tooltip text.
///
///
/// A string value.
///
///
/// Special keywords can be used in the text when an annotation is anchored to
/// a data point using the property. For a listing of
/// these keywords, refer to the "Annotations" help topic.
///
[
SRCategory("CategoryAttributeMisc"),
DefaultValue(""),
SRDescription("DescriptionAttributeToolTip"),
]
virtual public string ToolTip
{
get
{
return _tooltip;
}
set
{
_tooltip = value;
CallOnModifing();
}
}
#endregion // Interactivity
#endregion
#region Methods
#region Painting
///
/// Paints the annotation object using the specified graphics.
///
///
/// A object used to paint the annotation object.
///
///
/// Reference to the annotation's control owner.
///
abstract internal void Paint(Chart chart, ChartGraphics graphics);
///
/// Paints annotation selection markers.
///
/// Chart graphics used for painting.
/// Selection rectangle.
/// Selection path.
virtual internal void PaintSelectionHandles(ChartGraphics chartGraphics, RectangleF rect, GraphicsPath path)
{
// Define markers appearance style
Color markerBorderColor = Color.Black;
Color markerColor = Color.FromArgb(200, 255, 255, 255);
MarkerStyle markerStyle = MarkerStyle.Square;
int markerSize = selectionMarkerSize;
Boolean selected = this.IsSelected;
SizeF markerSizeRel = chartGraphics.GetRelativeSize(new SizeF(markerSize, markerSize));
if (this.Common.ProcessModePaint &&
!this.Common.ChartPicture.isPrinting)
{
// Clear selection rectangles
this.selectionRects = null;
// Check if annotation is selected
if (selected)
{
// Create selection rectangles
this.selectionRects = new RectangleF[9];
// Draw selection handles for single dimension annotations like line.
if (this.SelectionPointsStyle == SelectionPointsStyle.TwoPoints)
{
// Save selection handles position in array elements 0 and 4
this.selectionRects[(int)ResizingMode.TopLeftHandle] = new RectangleF(
rect.X - markerSizeRel.Width / 2f,
rect.Y - markerSizeRel.Height / 2f,
markerSizeRel.Width,
markerSizeRel.Height);
this.selectionRects[(int)ResizingMode.BottomRightHandle] = new RectangleF(
rect.Right - markerSizeRel.Width / 2f,
rect.Bottom - markerSizeRel.Height / 2f,
markerSizeRel.Width,
markerSizeRel.Height);
// Draw selection handle
chartGraphics.DrawMarkerRel(
rect.Location,
markerStyle,
markerSize,
markerColor,
markerBorderColor,
1,
"",
Color.Empty,
0,
Color.FromArgb(128, 0, 0, 0),
RectangleF.Empty);
chartGraphics.DrawMarkerRel(
new PointF(rect.Right, rect.Bottom),
markerStyle,
markerSize,
markerColor,
markerBorderColor,
1,
"",
Color.Empty,
0,
Color.FromArgb(128, 0, 0, 0),
RectangleF.Empty);
}
else if (this.SelectionPointsStyle == SelectionPointsStyle.Rectangle)
{
for (int index = 0; index < 8; index++)
{
// Get handle position
PointF handlePosition = PointF.Empty;
switch ((ResizingMode)index)
{
case ResizingMode.TopLeftHandle:
handlePosition = rect.Location;
break;
case ResizingMode.TopHandle:
handlePosition = new PointF(rect.X + rect.Width / 2f, rect.Y);
break;
case ResizingMode.TopRightHandle:
handlePosition = new PointF(rect.Right, rect.Y);
break;
case ResizingMode.RightHandle:
handlePosition = new PointF(rect.Right, rect.Y + rect.Height / 2f);
break;
case ResizingMode.BottomRightHandle:
handlePosition = new PointF(rect.Right, rect.Bottom);
break;
case ResizingMode.BottomHandle:
handlePosition = new PointF(rect.X + rect.Width / 2f, rect.Bottom);
break;
case ResizingMode.BottomLeftHandle:
handlePosition = new PointF(rect.X, rect.Bottom);
break;
case ResizingMode.LeftHandle:
handlePosition = new PointF(rect.X, rect.Y + rect.Height / 2f);
break;
}
// Save selection handles position in array elements 0 and 4
this.selectionRects[index] = new RectangleF(
handlePosition.X - markerSizeRel.Width / 2f,
handlePosition.Y - markerSizeRel.Height / 2f,
markerSizeRel.Width,
markerSizeRel.Height);
// Draw selection handle
chartGraphics.DrawMarkerRel(
handlePosition,
markerStyle,
markerSize,
markerColor,
markerBorderColor,
1,
"",
Color.Empty,
0,
Color.FromArgb(128, 0, 0, 0),
RectangleF.Empty);
}
}
//********************************************************************
//** Draw anchor selection handle
//********************************************************************
// Get vertical and horizontal axis
Axis vertAxis = null;
Axis horizAxis = null;
GetAxes(ref vertAxis, ref horizAxis);
// Get anchor position
double anchorX = double.NaN;
double anchorY = double.NaN;
bool relativeX = false;
bool relativeY = false;
this.GetAnchorLocation(ref anchorX, ref anchorY, ref relativeX, ref relativeY);
// Convert anchor location to relative coordinates
if (!double.IsNaN(anchorX) && !double.IsNaN(anchorY))
{
if (!relativeX && horizAxis != null)
{
anchorX = horizAxis.ValueToPosition(anchorX);
}
if (!relativeY && vertAxis != null)
{
anchorY = vertAxis.ValueToPosition(anchorY);
}
// Apply 3D transforamtion if required
ChartArea chartArea = null;
if (horizAxis != null && horizAxis.ChartArea != null)
{
chartArea = horizAxis.ChartArea;
}
if (vertAxis != null && vertAxis.ChartArea != null)
{
chartArea = vertAxis.ChartArea;
}
if (chartArea != null &&
chartArea.Area3DStyle.Enable3D == true &&
!chartArea.chartAreaIsCurcular &&
chartArea.requireAxes &&
chartArea.matrix3D.IsInitialized())
{
// Get anotation Z coordinate (use scene depth or anchored point Z position)
float positionZ = chartArea.areaSceneDepth;
if (this.AnchorDataPoint != null && this.AnchorDataPoint.series != null)
{
float depth = 0f;
chartArea.GetSeriesZPositionAndDepth(
this.AnchorDataPoint.series,
out depth,
out positionZ);
positionZ += depth / 2f;
}
// Define 3D points of annotation object
Point3D[] annot3DPoints = new Point3D[1];
annot3DPoints[0] = new Point3D((float)anchorX, (float)anchorY, positionZ);
// Tranform cube coordinates
chartArea.matrix3D.TransformPoints(annot3DPoints);
// Get transformed coordinates
anchorX = annot3DPoints[0].X;
anchorY = annot3DPoints[0].Y;
}
// Save selection handles position in array elements 0 and 4
this.selectionRects[(int)ResizingMode.AnchorHandle] = new RectangleF(
(float)anchorX - markerSizeRel.Width / 2f,
(float)anchorY - markerSizeRel.Height / 2f,
markerSizeRel.Width,
markerSizeRel.Height);
// Draw circular selection handle
chartGraphics.DrawMarkerRel(
new PointF((float)anchorX, (float)anchorY),
MarkerStyle.Cross,
selectionMarkerSize + 3,
markerColor,
markerBorderColor,
1,
"",
Color.Empty,
0,
Color.FromArgb(128, 0, 0, 0),
RectangleF.Empty);
}
//********************************************************************
//** Draw path selection handles
//********************************************************************
if (path != null && AllowPathEditing)
{
// Create selection rectangles for each point
PointF[] pathPoints = path.PathPoints;
RectangleF[] newSelectionRects = new RectangleF[pathPoints.Length + 9];
// Copy previous rectangles (first nine elements)
for (int index = 0; index < this.selectionRects.Length; index++)
{
newSelectionRects[index] = this.selectionRects[index];
}
this.selectionRects = newSelectionRects;
// Loop through all points
for (int index = 0; index < pathPoints.Length; index++)
{
// Get handle position
PointF handlePosition = chartGraphics.GetRelativePoint(pathPoints[index]);
// Save selection handles position in array elements 0 and 4
this.selectionRects[9 + index] = new RectangleF(
handlePosition.X - markerSizeRel.Width / 2f,
handlePosition.Y - markerSizeRel.Height / 2f,
markerSizeRel.Width,
markerSizeRel.Height);
// Draw selection handle
chartGraphics.DrawMarkerRel(
handlePosition,
MarkerStyle.Circle,
selectionMarkerSize + 1,
markerColor,
markerBorderColor,
1,
"",
Color.Empty,
0,
Color.FromArgb(128, 0, 0, 0),
RectangleF.Empty);
}
}
}
}
}
#endregion
#region Position and Size
///
/// Resizes an annotation according to its content size.
///
///
/// Sets the annotation width and height to fit the specified text. This method applies to
/// , ,
/// and objects only.
///
virtual public void ResizeToContent()
{
RectangleF position = GetContentPosition();
if (!double.IsNaN(position.Width))
{
this.Width = position.Width;
}
if (!double.IsNaN(position.Height))
{
this.Height = position.Height;
}
}
///
/// Gets an annotation's content position.
///
/// Annotation's content size.
virtual internal RectangleF GetContentPosition()
{
return new RectangleF(float.NaN, float.NaN, float.NaN, float.NaN);
}
///
/// Gets an annotation's anchor point location.
///
/// Returns the anchor X coordinate.
/// Returns the anchor Y coordinate.
/// Indicates if X coordinate is in relative chart coordinates.
/// Indicates if Y coordinate is in relative chart coordinates.
private void GetAnchorLocation(ref double anchorX, ref double anchorY, ref bool inRelativeAnchorX, ref bool inRelativeAnchorY)
{
anchorX = this.AnchorX;
anchorY = this.AnchorY;
if (this.AnchorDataPoint != null &&
this.AnchorDataPoint.series != null &&
this.Chart != null &&
this.Chart.chartPicture != null)
{
// Anchor data point is not allowed for gropped annotations
if (this.AnnotationGroup != null)
{
throw (new InvalidOperationException(SR.ExceptionAnnotationGroupedAnchorDataPointMustBeEmpty));
}
// Get data point relative coordinate
if (double.IsNaN(anchorX) || double.IsNaN(anchorY))
{
// Get X value from data point
if (double.IsNaN(anchorX))
{
anchorX = this.AnchorDataPoint.positionRel.X;
inRelativeAnchorX = true;
}
// Get Y value from data point
if (double.IsNaN(anchorY))
{
anchorY = this.AnchorDataPoint.positionRel.Y;
inRelativeAnchorY = true;
}
}
}
}
///
/// Gets annotation object position in relative coordinates.
///
/// Returns annotation location.
/// Returns annotation size.
/// Returns annotation anchor point location.
virtual internal void GetRelativePosition(out PointF location, out SizeF size, out PointF anchorLocation)
{
bool saveCurrentPosition = true;
//***********************************************************************
//** Check if position was precalculated
//***********************************************************************
if (!double.IsNaN(currentPositionRel.X) && !double.IsNaN(currentPositionRel.X))
{
location = currentPositionRel.Location;
size = currentPositionRel.Size;
anchorLocation = currentAnchorLocationRel;
return;
}
//***********************************************************************
//** Get vertical and horizontal axis
//***********************************************************************
Axis vertAxis = null;
Axis horizAxis = null;
GetAxes(ref vertAxis, ref horizAxis);
//***********************************************************************
//** Check if annotation was anchored to 2 points.
//***********************************************************************
if (this._anchorDataPoint != null &&
this._anchorDataPoint2 != null)
{
// Annotation size is in axis coordinates
this.IsSizeAlwaysRelative = false;
// Set annotation size
this.Height =
vertAxis.PositionToValue(this._anchorDataPoint2.positionRel.Y, false) -
vertAxis.PositionToValue(this._anchorDataPoint.positionRel.Y, false);
this.Width =
horizAxis.PositionToValue(this._anchorDataPoint2.positionRel.X, false) -
horizAxis.PositionToValue(this._anchorDataPoint.positionRel.X, false);
// Reset second anchor point after setting width and height
this._anchorDataPoint2 = null;
}
//***********************************************************************
//** Flags which indicate that coordinate was already transformed
//** into chart relative coordinate system.
//***********************************************************************
bool inRelativeX = false;
bool inRelativeY = false;
bool inRelativeWidth = (_isSizeAlwaysRelative) ? true : false;
bool inRelativeHeight = (_isSizeAlwaysRelative) ? true : false;
bool inRelativeAnchorX = false;
bool inRelativeAnchorY = false;
//***********************************************************************
//** Get anchoring coordinates from anchored Data Point.
//***********************************************************************
double anchorX = this.AnchorX;
double anchorY = this.AnchorY;
GetAnchorLocation(ref anchorX, ref anchorY, ref inRelativeAnchorX, ref inRelativeAnchorY);
//***********************************************************************
//** Calculate scaling and translation for the annotations in the group.
//***********************************************************************
AnnotationGroup group = this.AnnotationGroup;
PointF groupLocation = PointF.Empty;
double groupScaleX = 1.0;
double groupScaleY = 1.0;
if (group != null)
{
// Do not save relative position of annotations inside the group
saveCurrentPosition = false;
// Take relative position of the group
SizeF groupSize = SizeF.Empty;
PointF groupAnchorLocation = PointF.Empty;
group.GetRelativePosition(out groupLocation, out groupSize, out groupAnchorLocation);
// Calculate Scale
groupScaleX = groupSize.Width / 100.0;
groupScaleY = groupSize.Height / 100.0;
}
//***********************************************************************
//** Get annotation automatic size.
//***********************************************************************
double relativeWidth = this._width;
double relativeHeight = this._height;
// Get annotation content position
RectangleF contentPosition = GetContentPosition();
// Set annotation size if not set to custom value
if (double.IsNaN(relativeWidth))
{
relativeWidth = contentPosition.Width;
inRelativeWidth = true;
}
else
{
relativeWidth *= groupScaleX;
}
if (double.IsNaN(relativeHeight))
{
relativeHeight = contentPosition.Height;
inRelativeHeight = true;
}
else
{
relativeHeight *= groupScaleY;
}
//***********************************************************************
//** Provide "dummy" size at design time
//***********************************************************************
if (this.Chart != null && this.Chart.IsDesignMode())
{
if (this.IsSizeAlwaysRelative ||
(vertAxis == null && horizAxis == null))
{
if (double.IsNaN(relativeWidth))
{
relativeWidth = 20.0;
saveCurrentPosition = false;
}
if (double.IsNaN(relativeHeight))
{
relativeHeight = 20.0;
saveCurrentPosition = false;
}
}
}
//***********************************************************************
//** Get annotation location.
//***********************************************************************
double relativeX = this.X;
double relativeY = this.Y;
// Check if annotation location Y coordinate is defined
if (double.IsNaN(relativeY) && !double.IsNaN(anchorY))
{
inRelativeY = true;
double relativeAnchorY = anchorY;
if (!inRelativeAnchorY && vertAxis != null)
{
relativeAnchorY = vertAxis.ValueToPosition(anchorY);
}
if (this.AnchorAlignment == ContentAlignment.TopCenter ||
this.AnchorAlignment == ContentAlignment.TopLeft ||
this.AnchorAlignment == ContentAlignment.TopRight)
{
relativeY = relativeAnchorY + this.AnchorOffsetY;
relativeY *= groupScaleY;
}
else if (this.AnchorAlignment == ContentAlignment.BottomCenter ||
this.AnchorAlignment == ContentAlignment.BottomLeft ||
this.AnchorAlignment == ContentAlignment.BottomRight)
{
relativeY = relativeAnchorY - this.AnchorOffsetY;
relativeY *= groupScaleY;
if (relativeHeight != 0f && !double.IsNaN(relativeHeight))
{
if (inRelativeHeight)
{
relativeY -= relativeHeight;
}
else if (vertAxis != null)
{
float yValue = (float)vertAxis.PositionToValue(relativeY);
float bottomRel = (float)vertAxis.ValueToPosition(yValue + relativeHeight);
relativeY -= bottomRel - relativeY;
}
}
}
else
{
relativeY = relativeAnchorY + this.AnchorOffsetY;
relativeY *= groupScaleY;
if (relativeHeight != 0f && !double.IsNaN(relativeHeight))
{
if (inRelativeHeight)
{
relativeY -= relativeHeight / 2f;
}
else if (vertAxis != null)
{
float yValue = (float)vertAxis.PositionToValue(relativeY);
float bottomRel = (float)vertAxis.ValueToPosition(yValue + relativeHeight);
relativeY -= (bottomRel - relativeY) / 2f;
}
}
}
}
else
{
relativeY *= groupScaleY;
}
// Check if annotation location X coordinate is defined
if (double.IsNaN(relativeX) && !double.IsNaN(anchorX))
{
inRelativeX = true;
double relativeAnchorX = anchorX;
if (!inRelativeAnchorX && horizAxis != null)
{
relativeAnchorX = horizAxis.ValueToPosition(anchorX);
}
if (this.AnchorAlignment == ContentAlignment.BottomLeft ||
this.AnchorAlignment == ContentAlignment.MiddleLeft ||
this.AnchorAlignment == ContentAlignment.TopLeft)
{
relativeX = relativeAnchorX + this.AnchorOffsetX;
relativeX *= groupScaleX;
}
else if (this.AnchorAlignment == ContentAlignment.BottomRight ||
this.AnchorAlignment == ContentAlignment.MiddleRight ||
this.AnchorAlignment == ContentAlignment.TopRight)
{
relativeX = relativeAnchorX - this.AnchorOffsetX;
relativeX *= groupScaleX;
if (relativeWidth != 0f && !double.IsNaN(relativeWidth))
{
if (inRelativeWidth)
{
relativeX -= relativeWidth;
}
else if (horizAxis != null)
{
float xValue = (float)horizAxis.PositionToValue(relativeX);
relativeX -= horizAxis.ValueToPosition(xValue + relativeWidth) - relativeX;
}
}
}
else
{
relativeX = relativeAnchorX + this.AnchorOffsetX;
relativeX *= groupScaleX;
if (relativeWidth != 0f && !double.IsNaN(relativeWidth))
{
if (inRelativeWidth)
{
relativeX -= relativeWidth / 2f;
}
else if (horizAxis != null)
{
float xValue = (float)horizAxis.PositionToValue(relativeX);
relativeX -= (horizAxis.ValueToPosition(xValue + relativeWidth) - relativeX) / 2f;
}
}
}
}
else
{
relativeX *= groupScaleX;
}
// Translate
relativeX += groupLocation.X;
relativeY += groupLocation.Y;
//***********************************************************************
//** Get annotation automatic location.
//***********************************************************************
// Set annotation size if not set to custom value
if (double.IsNaN(relativeX))
{
relativeX = contentPosition.X * groupScaleX;
inRelativeX = true;
}
if (double.IsNaN(relativeY))
{
relativeY = contentPosition.Y * groupScaleY;
inRelativeY = true;
}
//***********************************************************************
//** Convert coordinates from axes values to relative coordinates.
//***********************************************************************
// Check if values are set in axis values
if (horizAxis != null)
{
if (!inRelativeX)
{
relativeX = horizAxis.ValueToPosition(relativeX);
}
if (!inRelativeAnchorX)
{
anchorX = horizAxis.ValueToPosition(anchorX);
}
if (!inRelativeWidth)
{
relativeWidth = horizAxis.ValueToPosition(
horizAxis.PositionToValue(relativeX, false) + relativeWidth) - relativeX;
}
}
if (vertAxis != null)
{
if (!inRelativeY)
{
relativeY = vertAxis.ValueToPosition(relativeY);
}
if (!inRelativeAnchorY)
{
anchorY = vertAxis.ValueToPosition(anchorY);
}
if (!inRelativeHeight)
{
relativeHeight = vertAxis.ValueToPosition(
vertAxis.PositionToValue(relativeY, false) + relativeHeight) - relativeY;
}
}
bool isTextAnnotation = this is TextAnnotation;
//***********************************************************************
//** Apply 3D transforamtion if required
//***********************************************************************
ChartArea chartArea = null;
if (horizAxis != null && horizAxis.ChartArea != null)
{
chartArea = horizAxis.ChartArea;
}
if (vertAxis != null && vertAxis.ChartArea != null)
{
chartArea = vertAxis.ChartArea;
}
if (chartArea != null &&
chartArea.Area3DStyle.Enable3D == true &&
!chartArea.chartAreaIsCurcular &&
chartArea.requireAxes &&
chartArea.matrix3D.IsInitialized())
{
// Get anotation Z coordinate (use scene depth or anchored point Z position)
float positionZ = chartArea.areaSceneDepth;
if (this.AnchorDataPoint != null && this.AnchorDataPoint.series != null)
{
float depth = 0f;
chartArea.GetSeriesZPositionAndDepth(
this.AnchorDataPoint.series,
out depth,
out positionZ);
positionZ += depth / 2f;
}
// Define 3D points of annotation object
Point3D[] annot3DPoints = new Point3D[3];
annot3DPoints[0] = new Point3D((float)relativeX, (float)relativeY, positionZ);
annot3DPoints[1] = new Point3D((float)(relativeX + relativeWidth), (float)(relativeY + relativeHeight), positionZ);
annot3DPoints[2] = new Point3D((float)anchorX, (float)anchorY, positionZ);
// Tranform cube coordinates
chartArea.matrix3D.TransformPoints(annot3DPoints);
// Get transformed coordinates
relativeX = annot3DPoints[0].X;
relativeY = annot3DPoints[0].Y;
anchorX = annot3DPoints[2].X;
anchorY = annot3DPoints[2].Y;
// Don't adjust size for text annotation
if (!(isTextAnnotation && this.IsSizeAlwaysRelative))
{
relativeWidth = annot3DPoints[1].X - relativeX;
relativeHeight = annot3DPoints[1].Y - relativeY;
}
}
//***********************************************************************
//** Provide "dummy" position at design time
//***********************************************************************
if (this.Chart != null && this.Chart.IsDesignMode())
{
if (double.IsNaN(relativeX))
{
relativeX = groupLocation.X;
saveCurrentPosition = false;
}
if (double.IsNaN(relativeY))
{
relativeY = groupLocation.Y;
saveCurrentPosition = false;
}
if (double.IsNaN(relativeWidth))
{
relativeWidth = 20.0 * groupScaleX;
saveCurrentPosition = false;
}
if (double.IsNaN(relativeHeight))
{
relativeHeight = 20.0 * groupScaleY;
saveCurrentPosition = false;
}
}
//***********************************************************************
//** Initialize returned values
//***********************************************************************
location = new PointF((float)relativeX, (float)relativeY);
size = new SizeF((float)relativeWidth, (float)relativeHeight);
anchorLocation = new PointF((float)anchorX, (float)anchorY);
//***********************************************************************
//** Adjust text based annotaion position using SmartLabelStyle.
//***********************************************************************
// Check if smart labels are enabled
if (this.SmartLabelStyle.Enabled && isTextAnnotation &&
group == null)
{
// Anchor point must be set
if (!double.IsNaN(anchorX) && !double.IsNaN(anchorY) &&
double.IsNaN(this.X) && double.IsNaN(this.Y))
{
if (this.Chart != null &&
this.Chart.chartPicture != null)
{
// Remember old movement distance restriction
double oldMinMovingDistance = this.SmartLabelStyle.MinMovingDistance;
double oldMaxMovingDistance = this.SmartLabelStyle.MaxMovingDistance;
// Increase annotation moving restrictions according to the anchor offset
PointF anchorOffsetAbs = this.GetGraphics().GetAbsolutePoint(
new PointF((float)this.AnchorOffsetX, (float)this.AnchorOffsetY));
float maxAnchorOffsetAbs = Math.Max(anchorOffsetAbs.X, anchorOffsetAbs.Y);
if (maxAnchorOffsetAbs > 0.0)
{
this.SmartLabelStyle.MinMovingDistance += maxAnchorOffsetAbs;
this.SmartLabelStyle.MaxMovingDistance += maxAnchorOffsetAbs;
}
// Adjust label position using SmartLabelStyle algorithm
LabelAlignmentStyles labelAlignment = LabelAlignmentStyles.Bottom;
using (StringFormat format = new StringFormat())
{
SizeF markerSizeRel = new SizeF((float)this.AnchorOffsetX, (float)this.AnchorOffsetY);
PointF newlocation = this.Chart.chartPicture.annotationSmartLabel.AdjustSmartLabelPosition(
this.Common,
this.Chart.chartPicture.ChartGraph,
chartArea,
this.SmartLabelStyle,
location,
size,
format,
anchorLocation,
markerSizeRel,
labelAlignment,
(this is CalloutAnnotation));
// Restore old movement distance restriction
this.SmartLabelStyle.MinMovingDistance = oldMinMovingDistance;
this.SmartLabelStyle.MaxMovingDistance = oldMaxMovingDistance;
// Check if annotation should be hidden
if (newlocation.IsEmpty)
{
location = new PointF(float.NaN, float.NaN);
}
else
{
// Get new position using alignment in format
RectangleF newPosition = this.Chart.chartPicture.annotationSmartLabel.GetLabelPosition(
this.Chart.chartPicture.ChartGraph,
newlocation,
size,
format,
false);
// Set new location
location = newPosition.Location;
}
}
}
}
else
{
// Add annotation position into the list (to prevent overlapping)
using (StringFormat format = new StringFormat())
{
this.Chart.chartPicture.annotationSmartLabel.AddSmartLabelPosition(
this.Chart.chartPicture.ChartGraph,
location,
size,
format);
}
}
}
//***********************************************************************
//** Save calculated position
//***********************************************************************
if (saveCurrentPosition)
{
currentPositionRel = new RectangleF(location, size);
currentAnchorLocationRel = new PointF(anchorLocation.X, anchorLocation.Y);
}
}
///
/// Set annotation object position using rectangle in relative coordinates.
/// Automatically converts relative coordinates to axes values if required.
///
/// Position in relative coordinates.
/// Anchor location in relative coordinates.
internal void SetPositionRelative(RectangleF position, PointF anchorPoint)
{
SetPositionRelative(position, anchorPoint, false);
}
///
/// Set annotation object position using rectangle in relative coordinates.
/// Automatically converts relative coordinates to axes values if required.
///
/// Position in relative coordinates.
/// Anchor location in relative coordinates.
/// Indicates if position changing was a result of the user input.
internal void SetPositionRelative(RectangleF position, PointF anchorPoint, bool userInput)
{
double newX = position.X;
double newY = position.Y;
double newRight = position.Right;
double newBottom = position.Bottom;
double newWidth = position.Width;
double newHeight = position.Height;
double newAnchorX = anchorPoint.X;
double newAnchorY = anchorPoint.Y;
//***********************************************************************
//** Set pre calculated position and anchor location
//***********************************************************************
this.currentPositionRel = new RectangleF(position.Location, position.Size);
this.currentAnchorLocationRel = new PointF(anchorPoint.X, anchorPoint.Y);
//***********************************************************************
//** Get vertical and horizontal axis
//***********************************************************************
Axis vertAxis = null;
Axis horizAxis = null;
GetAxes(ref vertAxis, ref horizAxis);
//***********************************************************************
//** Disable anchoring to point and axes in 3D
//** This is done due to the issues of moving elements in 3D space.
//***********************************************************************
ChartArea chartArea = null;
if (horizAxis != null && horizAxis.ChartArea != null)
{
chartArea = horizAxis.ChartArea;
}
if (vertAxis != null && vertAxis.ChartArea != null)
{
chartArea = vertAxis.ChartArea;
}
if (chartArea != null && chartArea.Area3DStyle.Enable3D == true)
{
// If anchor point was set - get its relative position and use it as an anchor point
if (this.AnchorDataPoint != null)
{
bool inRelativeCoordX = true;
bool inRelativeCoordY = true;
this.GetAnchorLocation(ref newAnchorX, ref newAnchorY, ref inRelativeCoordX, ref inRelativeCoordY);
this.currentAnchorLocationRel = new PointF((float)newAnchorX, (float)newAnchorY);
}
// In 3D always use relative annotation coordinates
// Disconnect annotation from axes and anchor point
this.AnchorDataPoint = null;
this.AxisX = null;
this.AxisY = null;
horizAxis = null;
vertAxis = null;
}
//***********************************************************************
//** Convert relative coordinates to axis values
//***********************************************************************
if (horizAxis != null)
{
newX = horizAxis.PositionToValue(newX, false);
if (!double.IsNaN(newAnchorX))
{
newAnchorX = horizAxis.PositionToValue(newAnchorX, false);
}
// Adjust for the IsLogarithmic axis
if (horizAxis.IsLogarithmic)
{
newX = Math.Pow(horizAxis.logarithmBase, newX);
if (!double.IsNaN(newAnchorX))
{
newAnchorX = Math.Pow(horizAxis.logarithmBase, newAnchorX);
}
}
if (!this.IsSizeAlwaysRelative)
{
if (float.IsNaN(position.Right) &&
!float.IsNaN(position.Width) &&
!float.IsNaN(anchorPoint.X))
{
newRight = horizAxis.PositionToValue(anchorPoint.X + position.Width, false);
if (horizAxis.IsLogarithmic)
{
newRight = Math.Pow(horizAxis.logarithmBase, newRight);
}
newWidth = newRight - newAnchorX;
}
else
{
newRight = horizAxis.PositionToValue(position.Right, false);
if (horizAxis.IsLogarithmic)
{
newRight = Math.Pow(horizAxis.logarithmBase, newRight);
}
newWidth = newRight - newX;
}
}
}
if (vertAxis != null)
{
newY = vertAxis.PositionToValue(newY, false);
if (!double.IsNaN(newAnchorY))
{
newAnchorY = vertAxis.PositionToValue(newAnchorY, false);
}
// NOTE: Fixes issue #4113
// Adjust for the IsLogarithmic axis
if (vertAxis.IsLogarithmic)
{
newY = Math.Pow(vertAxis.logarithmBase, newY);
if (!double.IsNaN(newAnchorY))
{
newAnchorY = Math.Pow(vertAxis.logarithmBase, newAnchorY);
}
}
if (!this.IsSizeAlwaysRelative)
{
if (float.IsNaN(position.Bottom) &&
!float.IsNaN(position.Height) &&
!float.IsNaN(anchorPoint.Y))
{
newBottom = vertAxis.PositionToValue(anchorPoint.Y + position.Height, false);
if (vertAxis.IsLogarithmic)
{
newBottom = Math.Pow(vertAxis.logarithmBase, newBottom);
}
newHeight = newBottom - newAnchorY;
}
else
{
newBottom = vertAxis.PositionToValue(position.Bottom, false);
if (vertAxis.IsLogarithmic)
{
newBottom = Math.Pow(vertAxis.logarithmBase, newBottom);
}
newHeight = newBottom - newY;
}
}
}
// Fire position changing event when position changed by user.
if (userInput)
{
// Set flag that annotation position was changed
this.positionChanged = true;
// Fire position changing event
if (this.Chart != null)
{
AnnotationPositionChangingEventArgs args = new AnnotationPositionChangingEventArgs();
args.NewLocationX = newX;
args.NewLocationY = newY;
args.NewSizeWidth = newWidth;
args.NewSizeHeight = newHeight;
args.NewAnchorLocationX = newAnchorX;
args.NewAnchorLocationY = newAnchorY;
args.Annotation = this;
if (this.Chart.OnAnnotationPositionChanging(ref args))
{
// Get user changed position/anchor
newX = args.NewLocationX;
newY = args.NewLocationY;
newWidth = args.NewSizeWidth;
newHeight = args.NewSizeHeight;
newAnchorX = args.NewAnchorLocationX;
newAnchorY = args.NewAnchorLocationY;
}
}
}
// Adjust location & size
this.X = newX;
this.Y = newY;
this.Width = newWidth;
this.Height = newHeight;
this.AnchorX = newAnchorX;
this.AnchorY = newAnchorY;
// Invalidate annotation
this.Invalidate();
return;
}
///
/// Adjust annotation location and\or size as a result of user action.
///
/// Distance to resize/move the annotation.
/// Resizing mode.
virtual internal void AdjustLocationSize(SizeF movingDistance, ResizingMode resizeMode)
{
AdjustLocationSize(movingDistance, resizeMode, true);
}
///
/// Adjust annotation location and\or size as a result of user action.
///
/// Distance to resize/move the annotation.
/// Resizing mode.
/// Distance is in pixels, otherwise relative.
virtual internal void AdjustLocationSize(SizeF movingDistance, ResizingMode resizeMode, bool pixelCoord)
{
AdjustLocationSize(movingDistance, resizeMode, pixelCoord, false);
}
///
/// Adjust annotation location and\or size as a result of user action.
///
/// Distance to resize/move the annotation.
/// Resizing mode.
/// Distance is in pixels, otherwise relative.
/// Indicates if position changing was a result of the user input.
virtual internal void AdjustLocationSize(SizeF movingDistance, ResizingMode resizeMode, bool pixelCoord, bool userInput)
{
if (!movingDistance.IsEmpty)
{
// Convert pixel coordinates into relative
if (pixelCoord)
{
movingDistance = Chart.chartPicture.ChartGraph.GetRelativeSize(movingDistance);
}
// Get annotation position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
if (userInput)
{
if (this.startMovePositionRel.X == 0f &&
this.startMovePositionRel.Y == 0f &&
this.startMovePositionRel.Width == 0f &&
this.startMovePositionRel.Height == 0f)
{
GetRelativePosition(out firstPoint, out size, out anchorPoint);
this.startMovePositionRel = new RectangleF(firstPoint, size);
this.startMoveAnchorLocationRel = new PointF(anchorPoint.X, anchorPoint.Y);
}
firstPoint = this.startMovePositionRel.Location;
size = this.startMovePositionRel.Size;
anchorPoint = this.startMoveAnchorLocationRel;
}
else
{
GetRelativePosition(out firstPoint, out size, out anchorPoint);
}
if (resizeMode == ResizingMode.TopLeftHandle)
{
firstPoint.X -= movingDistance.Width;
firstPoint.Y -= movingDistance.Height;
size.Width += movingDistance.Width;
size.Height += movingDistance.Height;
}
else if (resizeMode == ResizingMode.TopHandle)
{
firstPoint.Y -= movingDistance.Height;
size.Height += movingDistance.Height;
}
else if (resizeMode == ResizingMode.TopRightHandle)
{
firstPoint.Y -= movingDistance.Height;
size.Width -= movingDistance.Width;
size.Height += movingDistance.Height;
}
else if (resizeMode == ResizingMode.RightHandle)
{
size.Width -= movingDistance.Width;
}
else if (resizeMode == ResizingMode.BottomRightHandle)
{
size.Width -= movingDistance.Width;
size.Height -= movingDistance.Height;
}
else if (resizeMode == ResizingMode.BottomHandle)
{
size.Height -= movingDistance.Height;
}
else if (resizeMode == ResizingMode.BottomLeftHandle)
{
firstPoint.X -= movingDistance.Width;
size.Width += movingDistance.Width;
size.Height -= movingDistance.Height;
}
else if (resizeMode == ResizingMode.LeftHandle)
{
firstPoint.X -= movingDistance.Width;
size.Width += movingDistance.Width;
}
else if (resizeMode == ResizingMode.AnchorHandle)
{
anchorPoint.X -= movingDistance.Width;
anchorPoint.Y -= movingDistance.Height;
}
else if (resizeMode == ResizingMode.Moving)
{
firstPoint.X -= movingDistance.Width;
firstPoint.Y -= movingDistance.Height;
}
// Make sure we do not override automatic Width and Heigth
if (resizeMode == ResizingMode.Moving)
{
if (double.IsNaN(this.Width))
{
size.Width = float.NaN;
}
if (double.IsNaN(this.Height))
{
size.Height = float.NaN;
}
}
// Make sure we do not override automatic X and Y
if (resizeMode == ResizingMode.AnchorHandle)
{
if (double.IsNaN(this.X))
{
firstPoint.X = float.NaN;
}
if (double.IsNaN(this.Y))
{
firstPoint.Y = float.NaN;
}
}
else if (double.IsNaN(this.AnchorX) || double.IsNaN(this.AnchorY))
{
anchorPoint = new PointF(float.NaN, float.NaN);
}
// Set annotation position from rectangle in relative coordinates
SetPositionRelative(new RectangleF(firstPoint, size), anchorPoint, userInput);
}
return;
}
#endregion
#region Anchor Point and Axes Converters
///
/// Checks if annotation draw anything in the anchor position (except selection handle)
///
/// True if annotation "connects" itself and anchor point visually.
virtual internal bool IsAnchorDrawn()
{
return false;
}
///
/// Gets data point by name.
///
/// Data point name to find.
/// Data point.
internal DataPoint GetDataPointByName(string dataPointName)
{
DataPoint dataPoint = null;
if (Chart != null && dataPointName.Length > 0)
{
// Split series name and point index
int separatorIndex = dataPointName.IndexOf("\\r", StringComparison.Ordinal);
if (separatorIndex > 0)
{
string seriesName = dataPointName.Substring(0, separatorIndex);
string pointIndex = dataPointName.Substring(separatorIndex + 2);
int index = 0;
if (int.TryParse(pointIndex, NumberStyles.Any, CultureInfo.InvariantCulture, out index))
{
dataPoint = Chart.Series[seriesName].Points[index];
}
}
}
return dataPoint;
}
///
/// Gets axis by name.
///
/// Axis name to find.
/// Data point.
private Axis GetAxisByName(string axisName)
{
Debug.Assert(axisName != null, "GetAxisByName: handed a null axis name");
Axis axis = null;
try
{
if (Chart != null && axisName.Length > 0)
{
// Split series name and point index
int separatorIndex = axisName.IndexOf("\\r", StringComparison.Ordinal);
if (separatorIndex > 0)
{
string areaName = axisName.Substring(0, separatorIndex);
string axisType = axisName.Substring(separatorIndex + 2);
switch ((AxisName)Enum.Parse(typeof(AxisName), axisType))
{
case (AxisName.X):
axis = Chart.ChartAreas[areaName].AxisX;
break;
case (AxisName.Y):
axis = Chart.ChartAreas[areaName].AxisY;
break;
case (AxisName.X2):
axis = Chart.ChartAreas[areaName].AxisX2;
break;
case (AxisName.Y2):
axis = Chart.ChartAreas[areaName].AxisY2;
break;
}
}
}
}
catch (ArgumentNullException)
{
axis = null;
}
catch (ArgumentException)
{
axis = null;
}
return axis;
}
///
/// Gets data point unique name.
///
/// Data point to get the name for.
/// Data point name.
internal string GetDataPointName(DataPoint dataPoint)
{
string name = String.Empty;
if (dataPoint.series != null)
{
int pointIndex = dataPoint.series.Points.IndexOf(dataPoint);
if (pointIndex >= 0)
{
name = dataPoint.series.Name +
"\\r" +
pointIndex.ToString(CultureInfo.InvariantCulture);
}
}
return name;
}
///
/// Gets axis unique name.
///
/// Axis to get the name for.
/// Axis name.
private string GetAxisName(Axis axis)
{
string name = String.Empty;
if (axis.ChartArea != null)
{
name = axis.ChartArea.Name +
"\\r" +
axis.AxisName.ToString();
}
return name;
}
#endregion
#region Z Order Methods
///
/// Sends an annotation to the back of all annotations.
///
///
virtual public void SendToBack()
{
// Find collection of annotation objects this annotation belongs too
AnnotationCollection collection = null;
if (Chart != null)
{
collection = Chart.Annotations;
}
// Check if annotation belongs to the group
AnnotationGroup group = AnnotationGroup;
if (group != null)
{
collection = group.Annotations;
}
// Check if annotation is found
if (collection != null)
{
Annotation annot = collection.FindByName(this.Name);
if (annot != null)
{
// Reinsert annotation at the beginning of the collection
collection.Remove(annot);
collection.Insert(0, annot);
}
}
}
///
/// Brings an annotation to the front of all annotations.
///
///
virtual public void BringToFront()
{
// Find collection of annotation objects this annotation belongs too
AnnotationCollection collection = null;
if (Chart != null)
{
collection = Chart.Annotations;
}
// Check if annotation belongs to the group
AnnotationGroup group = AnnotationGroup;
if (group != null)
{
collection = group.Annotations;
}
// Check if annotation is found
if (collection != null)
{
Annotation annot = collection.FindByName(this.Name);
if (annot != null)
{
// Reinsert annotation at the end of the collection
collection.Remove(annot);
collection.Add(this);
}
}
}
#endregion // Z Order Methods
#region Group Related Methods
#endregion // Group Related Methods
#region SmartLabelStyle methods
///
/// Adds anchor position to the list. Used to check SmartLabelStyle overlapping.
///
/// List to add to.
internal void AddSmartLabelMarkerPositions(ArrayList list)
{
// Anchor position is added to the list of non-overlapped markers
if (this.Visible && this.IsAnchorDrawn())
{
// Get vertical and horizontal axis
Axis vertAxis = null;
Axis horizAxis = null;
GetAxes(ref vertAxis, ref horizAxis);
// Get anchor position
double anchorX = double.NaN;
double anchorY = double.NaN;
bool relativeX = false;
bool relativeY = false;
this.GetAnchorLocation(ref anchorX, ref anchorY, ref relativeX, ref relativeY);
// Convert anchor location to relative coordinates
if (!double.IsNaN(anchorX) && !double.IsNaN(anchorY))
{
if (!relativeX && horizAxis != null)
{
anchorX = horizAxis.ValueToPosition(anchorX);
}
if (!relativeY && vertAxis != null)
{
anchorY = vertAxis.ValueToPosition(anchorY);
}
// Apply 3D transforamtion if required
ChartArea chartArea = null;
if (horizAxis != null && horizAxis.ChartArea != null)
{
chartArea = horizAxis.ChartArea;
}
if (vertAxis != null && vertAxis.ChartArea != null)
{
chartArea = vertAxis.ChartArea;
}
if (chartArea != null &&
chartArea.Area3DStyle.Enable3D == true &&
!chartArea.chartAreaIsCurcular &&
chartArea.requireAxes &&
chartArea.matrix3D.IsInitialized())
{
// Get anotation Z coordinate (use scene depth or anchored point Z position)
float positionZ = chartArea.areaSceneDepth;
if (this.AnchorDataPoint != null && this.AnchorDataPoint.series != null)
{
float depth = 0f;
chartArea.GetSeriesZPositionAndDepth(
this.AnchorDataPoint.series,
out depth,
out positionZ);
positionZ += depth / 2f;
}
// Define 3D points of annotation object
Point3D[] annot3DPoints = new Point3D[1];
annot3DPoints[0] = new Point3D((float)anchorX, (float)anchorY, positionZ);
// Tranform cube coordinates
chartArea.matrix3D.TransformPoints(annot3DPoints);
// Get transformed coordinates
anchorX = annot3DPoints[0].X;
anchorY = annot3DPoints[0].Y;
}
// Save selection handles position in array elements 0 and 4
if (this.GetGraphics() != null)
{
SizeF markerSizeRel = this.GetGraphics().GetRelativeSize(
new SizeF(1f, 1f));
RectangleF anchorRect = new RectangleF(
(float)anchorX - markerSizeRel.Width / 2f,
(float)anchorY - markerSizeRel.Height / 2f,
markerSizeRel.Width,
markerSizeRel.Height);
list.Add(anchorRect);
}
}
}
}
#endregion
#region Public Anchoring Methods
///
/// Anchors an annotation to a data point.
///
///
///
///
///
/// to be anchored to.
///
///
/// Anchors an annotation to the specified data point.
///
public void SetAnchor(DataPoint dataPoint)
{
SetAnchor(dataPoint, null);
}
///
/// Anchors an annotation to two data points.
///
///
///
///
///
/// First anchor .
///
///
/// Second anchor .
///
///
/// Anchors an annotation's top/left and bottom/right corners to the
/// specified data points.
///
public void SetAnchor(DataPoint dataPoint1, DataPoint dataPoint2)
{
// Set annotation position to automatic
this.X = double.NaN;
this.Y = double.NaN;
// Reset anchor point if any
this.AnchorX = double.NaN;
this.AnchorY = double.NaN;
// Set anchor point
this.AnchorDataPoint = dataPoint1;
// Get vertical and horizontal axis
Axis vertAxis = null;
Axis horizAxis = null;
GetAxes(ref vertAxis, ref horizAxis);
// Set Width and Height in axis coordinates
if (dataPoint2 != null && dataPoint1 != null)
{
this._anchorDataPoint2 = dataPoint2;
}
// Invalidate annotation
this.Invalidate();
}
#endregion // Public Anchoring Methods
#region Placement Methods
///
/// Begins end user placement of an annotation using the mouse.
///
///
/// When this method is called, the end user is allowed to place an annotation using the
/// mouse.
///
/// Placement will finish when the end user specifies all required points, or
/// the method is called.
///
virtual public void BeginPlacement()
{
// Can't place annotations inside the group
if (this.AnnotationGroup != null)
{
throw (new InvalidOperationException(SR.ExceptionAnnotationGroupedUnableToStartPlacement));
}
if (this.Chart != null)
{
// Set the annotation object which is currently placed
this.Chart.Annotations.placingAnnotation = this;
}
else
{
throw (new InvalidOperationException(SR.ExceptionAnnotationNotInCollection));
}
}
///
/// Ends user placement of an annotation.
///
///
/// Ends an annotation placement operation previously started by a
/// method call.
///
/// Calling this method is not required, since placement will automatically
/// end when an end user enters all required points. However, it is useful when an annotation
/// placement operation needs to be aborted for some reason.
///
///
virtual public void EndPlacement()
{
if (this.Chart != null)
{
// Reset currently placed annotation object
this.Chart.Annotations.placingAnnotation = null;
// Restore default cursor
this.Chart.Cursor = this.Chart.defaultCursor;
// Clear last placement mouse position
this.lastPlacementPosition = PointF.Empty;
// Fire annotation placed event
this.Chart.OnAnnotationPlaced(this);
}
}
///
/// Handles mouse down event during annotation placement.
///
/// Mouse cursor position in pixels.
/// Mouse button down.
internal virtual void PlacementMouseDown(PointF point, MouseButtons buttons)
{
if (buttons == MouseButtons.Right)
{
// Stop any pacement
this.EndPlacement();
}
if (buttons == MouseButtons.Left &&
IsValidPlacementPosition(point.X, point.Y))
{
if (this.lastPlacementPosition.IsEmpty)
{
// Remeber position where mouse was clicked
this.lastPlacementPosition = this.GetGraphics().GetRelativePoint(point);
// Get annotation position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
this.GetRelativePosition(out firstPoint, out size, out anchorPoint);
// Set annotation X, Y coordinate
if (this.AllowMoving)
{
firstPoint = this.GetGraphics().GetRelativePoint(point);
// Do not change default position
if (double.IsNaN(this.AnchorX))
{
anchorPoint.X = float.NaN;
}
if (double.IsNaN(this.AnchorY))
{
anchorPoint.Y = float.NaN;
}
}
else if (this.AllowAnchorMoving)
{
anchorPoint = this.GetGraphics().GetRelativePoint(point);
// Do not change default position
if (double.IsNaN(this.X))
{
firstPoint.X = float.NaN;
}
if (double.IsNaN(this.Y))
{
firstPoint.Y = float.NaN;
}
}
// Do not change default size
if (double.IsNaN(this.Width))
{
size.Width = float.NaN;
}
if (double.IsNaN(this.Height))
{
size.Height = float.NaN;
}
// Set annotation position
this.positionChanged = true;
this.SetPositionRelative(
new RectangleF(firstPoint, size),
anchorPoint,
true);
// Invalidate and update the chart
if (Chart != null)
{
Invalidate();
Chart.UpdateAnnotations();
}
}
}
}
///
/// Handles mouse up event during annotation placement.
///
/// Mouse cursor position in pixels.
/// Mouse button Up.
/// Return true when placing finished.
internal virtual bool PlacementMouseUp(PointF point, MouseButtons buttons)
{
bool result = false;
if (buttons == MouseButtons.Left)
{
// Get annotation position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
this.GetRelativePosition(out firstPoint, out size, out anchorPoint);
if (this.AllowResizing)
{
PointF pointRel = this.GetGraphics().GetRelativePoint(point);
size = new SizeF(
pointRel.X - this.lastPlacementPosition.X,
pointRel.Y - this.lastPlacementPosition.Y);
}
else
{
// Do not change default size
if (double.IsNaN(this.Width))
{
size.Width = float.NaN;
}
if (double.IsNaN(this.Height))
{
size.Height = float.NaN;
}
}
// Do not change default position
if (double.IsNaN(this.X))
{
firstPoint.X = float.NaN;
}
if (double.IsNaN(this.Y))
{
firstPoint.Y = float.NaN;
}
if (double.IsNaN(this.AnchorX))
{
anchorPoint.X = float.NaN;
}
if (double.IsNaN(this.AnchorY))
{
anchorPoint.Y = float.NaN;
}
// Set annotation position
this.positionChanged = true;
this.SetPositionRelative(
new RectangleF(firstPoint, size),
anchorPoint,
true);
// End placement
if (!size.IsEmpty || !this.AllowResizing)
{
result = true;
this.EndPlacement();
}
// Invalidate and update the chart
if (Chart != null)
{
Invalidate();
Chart.UpdateAnnotations();
}
}
return result;
}
///
/// Handles mouse move event during annotation placement.
///
/// Mouse cursor position in pixels.
internal virtual void PlacementMouseMove(PointF point)
{
// Check if annotation was moved
if (this.GetGraphics() != null &&
!this.lastPlacementPosition.IsEmpty)
{
// Get annotation position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
this.GetRelativePosition(out firstPoint, out size, out anchorPoint);
if (this.AllowResizing)
{
PointF pointRel = this.GetGraphics().GetRelativePoint(point);
size = new SizeF(
pointRel.X - this.lastPlacementPosition.X,
pointRel.Y - this.lastPlacementPosition.Y);
}
// Do not change default position
if (double.IsNaN(this.X))
{
firstPoint.X = float.NaN;
}
if (double.IsNaN(this.Y))
{
firstPoint.Y = float.NaN;
}
if (double.IsNaN(this.AnchorX))
{
anchorPoint.X = float.NaN;
}
if (double.IsNaN(this.AnchorY))
{
anchorPoint.Y = float.NaN;
}
// Set annotation position
this.positionChanged = true;
this.SetPositionRelative(
new RectangleF(firstPoint, size),
anchorPoint,
true);
// Invalidate and update the chart
if (this.Chart != null)
{
Invalidate();
this.Chart.UpdateAnnotations();
}
}
}
///
/// Checks if specified position is valid for placement.
///
/// X coordinate.
/// Y coordinate.
/// True if annotation can be placed at specified coordinates.
virtual internal bool IsValidPlacementPosition(float x, float y)
{
if (this.Chart != null &&
this.GetGraphics() != null)
{
// Check if cursor is over the area where placement allowed
// If so - change cursor to cross
RectangleF placementRect = new RectangleF(0f, 0f, 100f, 100f);
if (this.ClipToChartArea.Length > 0 &&
this.ClipToChartArea != Constants.NotSetValue)
{
ChartArea area = Chart.ChartAreas[this.ClipToChartArea];
placementRect = area.PlotAreaPosition.ToRectangleF();
}
placementRect = this.GetGraphics().GetAbsoluteRectangle(placementRect);
if (placementRect.Contains(x, y))
{
return true;
}
}
return false;
}
#endregion // Placement Methods
#region Helper Methods
///
/// Helper method that checks if annotation is visible.
///
/// True if annotation is visible.
internal bool IsVisible()
{
if (this.Visible)
{
if (this.Chart != null)
{
// Check if annotation is anchored to the data point
ChartArea area = null;
if (this.AnchorDataPoint != null &&
this.AnchorDataPoint.series != null)
{
if (this.Chart.ChartAreas.IndexOf(this.AnchorDataPoint.series.ChartArea) >= 0)
{
area = this.Chart.ChartAreas[this.AnchorDataPoint.series.ChartArea];
}
}
if (area == null &&
this._anchorDataPoint2 != null &&
this._anchorDataPoint2.series != null)
{
if (this.Chart.ChartAreas.IndexOf(this._anchorDataPoint2.series.ChartArea) >= 0)
{
area = this.Chart.ChartAreas[this._anchorDataPoint2.series.ChartArea];
}
}
// Check if annotation uses chart area axis values
if (area == null && this.AxisX != null)
{
area = this.AxisX.ChartArea;
}
if (area == null && this.AxisY != null)
{
area = this.AxisY.ChartArea;
}
// Check if associated area is visible
if (area != null &&
!area.Visible)
{
return false;
}
}
return true;
}
return false;
}
///
/// Resets pre-calculated annotation position.
///
internal void ResetCurrentRelativePosition()
{
this.currentPositionRel = new RectangleF(float.NaN, float.NaN, float.NaN, float.NaN);
this.currentAnchorLocationRel = new PointF(float.NaN, float.NaN);
}
///
/// Replaces predefined keyword inside the string with their values if
/// annotation is anchored to the data point.
///
/// Original string with keywords.
/// Modified string.
internal string ReplaceKeywords(string strOriginal)
{
if (this.AnchorDataPoint != null)
{
return this.AnchorDataPoint.ReplaceKeywords(strOriginal);
}
return strOriginal;
}
///
/// Checks if anchor point of the annotation is visible.
///
/// True if anchor point is visible.
internal bool IsAnchorVisible()
{
// Get axes objects
Axis vertAxis = null;
Axis horizAxis = null;
GetAxes(ref vertAxis, ref horizAxis);
// Get anchor position
bool inRelativeAnchorX = false;
bool inRelativeAnchorY = false;
double anchorX = this.AnchorX;
double anchorY = this.AnchorY;
GetAnchorLocation(ref anchorX, ref anchorY, ref inRelativeAnchorX, ref inRelativeAnchorY);
// Check if anchor is set
if (!double.IsNaN(anchorX) && !double.IsNaN(anchorY))
{
// Check if anchor is in axes coordinates
if (this.AnchorDataPoint != null ||
this.AxisX != null ||
this.AxisY != null)
{
// Convert anchor point to relative coordinates
if (!inRelativeAnchorX && horizAxis != null)
{
anchorX = horizAxis.ValueToPosition(anchorX);
}
if (!inRelativeAnchorY && vertAxis != null)
{
anchorY = vertAxis.ValueToPosition(anchorY);
}
// Get chart area
ChartArea chartArea = null;
if (horizAxis != null)
{
chartArea = horizAxis.ChartArea;
}
if (chartArea == null && vertAxis != null)
{
chartArea = vertAxis.ChartArea;
}
// Apply 3D transforamtion if required
if (chartArea != null && chartArea.Area3DStyle.Enable3D == true)
{
if (!chartArea.chartAreaIsCurcular &&
chartArea.requireAxes &&
chartArea.matrix3D.IsInitialized())
{
// Get anotation Z coordinate (use scene depth or anchored point Z position)
float positionZ = chartArea.areaSceneDepth;
if (this.AnchorDataPoint != null && this.AnchorDataPoint.series != null)
{
float depth = 0f;
chartArea.GetSeriesZPositionAndDepth(
this.AnchorDataPoint.series,
out depth,
out positionZ);
positionZ += depth / 2f;
}
// Define 3D points of annotation object
Point3D[] annot3DPoints = new Point3D[1];
annot3DPoints[0] = new Point3D((float)anchorX, (float)anchorY, positionZ);
// Tranform cube coordinates
chartArea.matrix3D.TransformPoints(annot3DPoints);
// Get transformed coordinates
anchorX = annot3DPoints[0].X;
anchorY = annot3DPoints[0].Y;
}
}
// Get plot rectangle position and inflate it slightly
// to solve any float rounding issues.
RectangleF rect = chartArea.PlotAreaPosition.ToRectangleF();
rect.Inflate(0.00001f, 0.00001f);
// Check if anchor point is in the plotting area
if (!rect.Contains((float)anchorX, (float)anchorY))
{
return false;
}
}
}
return true;
}
///
/// Returns chart graphics objects.
///
/// Chart graphics object.
internal ChartGraphics GetGraphics()
{
if (this.Common != null)
{
return this.Common.graph;
}
return null;
}
///
/// Checks if provided pixel coordinate is contained in one of the
/// selection handles rectangle.
///
/// Coordinate in pixels.
/// Resizing mode.
internal ResizingMode GetSelectionHandle(PointF point)
{
ResizingMode resizingMode = ResizingMode.None;
if (this.Common != null &&
this.Common.graph != null)
{
// Convert point to relative coordinates
point = this.Common.graph.GetRelativePoint(point);
// Check if point is in one of the selection handles
if (this.selectionRects != null)
{
for (int index = 0; index < this.selectionRects.Length; index++)
{
if (!this.selectionRects[index].IsEmpty &&
this.selectionRects[index].Contains(point))
{
if (index > (int)ResizingMode.AnchorHandle)
{
resizingMode = ResizingMode.MovingPathPoints;
this.currentPathPointIndex = index - 9;
}
else
{
resizingMode = (ResizingMode)index;
}
}
}
}
}
return resizingMode;
}
///
/// Gets data point X or Y axis.
///
/// Data point to get the axis for.
/// X or Y axis to get.
/// Data point axis.
private Axis GetDataPointAxis(DataPoint dataPoint, AxisName axisName)
{
if (dataPoint != null && dataPoint.series != null && Chart != null)
{
// Get data point chart area
ChartArea chartArea = Chart.ChartAreas[dataPoint.series.ChartArea];
// Get point X axis
if ((axisName == AxisName.X || axisName == AxisName.X2) &&
!chartArea.switchValueAxes)
{
return chartArea.GetAxis(axisName, dataPoint.series.XAxisType, dataPoint.series.XSubAxisName);
}
else
{
return chartArea.GetAxis(axisName, dataPoint.series.YAxisType, dataPoint.series.YSubAxisName);
}
}
return null;
}
///
/// Gets annotation vertical and horizontal axes.
///
/// Returns annotation vertical axis or null.
/// Returns annotation horizontal axis or null.
internal void GetAxes(ref Axis vertAxis, ref Axis horizAxis)
{
vertAxis = null;
horizAxis = null;
if (this.AxisX != null && this.AxisX.ChartArea != null)
{
if (this.AxisX.ChartArea.switchValueAxes)
{
vertAxis = this.AxisX;
}
else
{
horizAxis = this.AxisX;
}
}
if (this.AxisY != null && this.AxisY.ChartArea != null)
{
if (this.AxisY.ChartArea.switchValueAxes)
{
horizAxis = this.AxisY;
}
else
{
vertAxis = this.AxisY;
}
}
// Get axes from attached data point
if (this.AnchorDataPoint != null)
{
if (horizAxis == null)
{
horizAxis = GetDataPointAxis(this.AnchorDataPoint, AxisName.X);
// For chart types like Bar, RangeBar and others, position of X and Y axes are flipped
if (horizAxis != null && horizAxis.ChartArea != null && horizAxis.ChartArea.switchValueAxes)
{
horizAxis = GetDataPointAxis(this.AnchorDataPoint, AxisName.Y);
}
}
if (vertAxis == null)
{
vertAxis = GetDataPointAxis(this.AnchorDataPoint, AxisName.Y);
// For chart types like Bar, RangeBar and others, position of X and Y axes are flipped
if (vertAxis != null && vertAxis.ChartArea != null && vertAxis.ChartArea.switchValueAxes)
{
vertAxis = GetDataPointAxis(this.AnchorDataPoint, AxisName.X);
}
}
}
// No axes coordinate system for grouped annotations
if (vertAxis != null || horizAxis != null)
{
if (this.AnnotationGroup != null)
{
throw (new InvalidOperationException(SR.ExceptionAnnotationGroupedAxisMustBeEmpty));
}
}
}
#endregion
#endregion
#region IDisposable Members
///
/// Releases unmanaged and - optionally - managed resources
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected override void Dispose(bool disposing)
{
if (disposing)
{
//Free managed resources
if (_fontCache != null)
{
_fontCache.Dispose();
_fontCache = null;
}
}
base.Dispose(disposing);
}
#endregion
}
///
/// This class is used to stores position changing event data for an annotation.
///
///
/// Provides additional data like the new annotation and anchor position when an end user
/// is moving the annotation with the mouse.
///
/// Can be used to restrict annotation movement, or snap the annotation position to
/// specific points.
///
///
[
SRDescription("DescriptionAttributeAnnotationPositionChangingEventArgs_AnnotationPositionChangingEventArgs"),
]
public class AnnotationPositionChangingEventArgs : EventArgs
{
#region Fields
private Annotation _Annotation = null;
///
/// Gets or sets the annotation the event is fired for.
///
public Annotation Annotation
{
get { return _Annotation; }
set { _Annotation = value; }
}
private double _NewLocationX = 0.0;
///
/// Gets or sets the new X location of the annotation.
///
public double NewLocationX
{
get { return _NewLocationX; }
set { _NewLocationX = value; }
}
private double _NewLocationY = 0.0;
///
/// Gets or sets the new Y location of the annotation.
///
public double NewLocationY
{
get { return _NewLocationY; }
set { _NewLocationY = value; }
}
private double _NewSizeWidth = 0.0;
///
/// Gets or sets the new width of the annotation.
///
public double NewSizeWidth
{
get { return _NewSizeWidth; }
set { _NewSizeWidth = value; }
}
private double _NewSizeHeight = 0.0;
///
/// Gets or sets the new height of the annotation.
///
public double NewSizeHeight
{
get { return _NewSizeHeight; }
set { _NewSizeHeight = value; }
}
private double _NewAnchorLocationX = 0.0;
///
/// Gets or sets the new annotation anchor point X location.
///
public double NewAnchorLocationX
{
get { return _NewAnchorLocationX; }
set { _NewAnchorLocationX = value; }
}
private double _NewAnchorLocationY = 0.0;
///
/// Gets or sets the new annotation anchor point Y location.
///
public double NewAnchorLocationY
{
get { return _NewAnchorLocationY; }
set { _NewAnchorLocationY = value; }
}
#endregion // Fields
#region Properties
///
/// Gets or sets the new location and size of the annotation.
///
[
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
]
public RectangleF NewPosition
{
get
{
return new RectangleF(
(float)this.NewLocationX,
(float)this.NewLocationY,
(float)this.NewSizeWidth,
(float)this.NewSizeHeight);
}
set
{
this.NewLocationX = value.X;
this.NewLocationY = value.Y;
this.NewSizeWidth = value.Width;
this.NewSizeHeight = value.Height;
}
}
///
/// Gets or sets the new anchor location of the annotation.
///
[
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
]
public PointF NewAnchorLocation
{
get
{
return new PointF(
(float)this.NewAnchorLocationX,
(float)this.NewAnchorLocationY);
}
set
{
this.NewAnchorLocationX = value.X;
this.NewAnchorLocationY = value.Y;
}
}
#endregion // Properties
}
}