Files
Pat Tullmann 0cb742dafb binfmt-detector-cli: rewrite to support PE32+ binaries (#38)
Rewrite with hard-coded offsets into the PE file format to discern
if a binary is PE32 or PE32+, and then to determine if it contains
a "CLR Data Directory" entry that looks valid.

Tested with PE32 and PE32+ compiled Mono binaries, PE32 and PE32+ native
binaries, and a random assortment of garbage files.

Former-commit-id: 9e7ac86ec84f653a2f79b87183efd5b0ebda001b
2023-10-16 20:16:47 +02:00

4438 lines
131 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//-------------------------------------------------------------
// <copyright company=Microsoft Corporation>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: Annotation.cs
//
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
//
// Classes: Annotation, AnnotationPositionChangingEventArgs
//
// Purpose: Base class for all anotation objects. Provides
// basic set of properties and methods.
//
// Reviewed:
//
//===================================================================
#region Used namespace
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Globalization;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
#if Microsoft_CONTROL
using System.ComponentModel.Design.Serialization;
using System.Reflection;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Windows.Forms.DataVisualization.Charting.Data;
using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
using System.Windows.Forms.DataVisualization.Charting.Utilities;
using System.Windows.Forms.DataVisualization.Charting.Borders3D;
#else
using System.Web;
using System.Web.UI;
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.DataVisualization.Charting.Data;
using System.Web.UI.DataVisualization.Charting.Utilities;
#endif
#endregion
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
#endif
{
#region Enumerations
/// <summary>
/// Annotation object selection points style.
/// </summary>
/// <remarks>
/// Enumeration is for internal use only and should not be part of the documentation.
/// </remarks>
internal enum SelectionPointsStyle
{
/// <summary>
/// Selection points are displayed top left and bottom right corners
/// </summary>
TwoPoints,
/// <summary>
/// Selection points are displayed on all sides and corners of the rectangle.
/// </summary>
Rectangle,
}
/// <summary>
/// Annotation object resizing\moving mode.
/// </summary>
/// <remarks>
/// Enumeration is for internal use only and should not be part of the documentation.
/// </remarks>
internal enum ResizingMode
{
/// <summary>
/// Top Left selection handle is used.
/// </summary>
TopLeftHandle = 0,
/// <summary>
/// Top selection handle is used.
/// </summary>
TopHandle = 1,
/// <summary>
/// Top Right selection handle is used.
/// </summary>
TopRightHandle = 2,
/// <summary>
/// Right selection handle is used.
/// </summary>
RightHandle = 3,
/// <summary>
/// Bottom Right selection handle is used.
/// </summary>
BottomRightHandle = 4,
/// <summary>
/// Bottom selection handle is used.
/// </summary>
BottomHandle = 5,
/// <summary>
/// Bottom Left selection handle is used.
/// </summary>
BottomLeftHandle = 6,
/// <summary>
/// Left selection handle is used.
/// </summary>
LeftHandle = 7,
/// <summary>
/// Anchor selection handle is used.
/// </summary>
AnchorHandle = 8,
/// <summary>
/// No selection handles used - moving mode.
/// </summary>
Moving = 16,
/// <summary>
/// Moving points of the annotation path.
/// </summary>
MovingPathPoints = 32,
/// <summary>
/// No moving or resizing.
/// </summary>
None = 64,
}
#endregion
/// <summary>
/// <b>Annotation</b> is an abstract class that defines properties and methods
/// common to all annotations.
/// </summary>
/// <remarks>
/// All annotations are derived from the <b>Annotation</b> class, which can be
/// used to set properties common to all annotation objects (e.g. color, position,
/// anchoring and others).
/// </remarks>
[
SRDescription("DescriptionAttributeAnnotation_Annotation"),
DefaultProperty("Name"),
]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
#if !Microsoft_CONTROL
public abstract class Annotation : ChartNamedElement, IChartMapArea
#else
public abstract class Annotation : ChartNamedElement
#endif
{
#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;
#if Microsoft_CONTROL
// 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;
#endif //Microsoft_CONTROL
#if Microsoft_CONTROL
// 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;
#endif // Microsoft_CONTROL
// 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;
#if !Microsoft_CONTROL
// Annotation map area attributes
private string _url = String.Empty;
private string _mapAreaAttributes = String.Empty;
private string _postbackValue = String.Empty;
#endif // !Microsoft_CONTROL
/// <summary>
/// Limit of annotation width and height.
/// </summary>
internal static double WidthHightLimit = 290000000;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Annotation"/> class.
/// </summary>
protected Annotation()
{
_textFont = _fontCache.DefaultFont;
}
#endregion
#region Properties
#region Miscellaneous
/// <summary>
/// Gets or sets an annotation's unique name.
/// </summary>
/// <value>
/// A <b>string</b> that represents an annotation's unique name.
/// </value>
[
SRCategory("CategoryAttributeMisc"),
Bindable(true),
SRDescription("DescriptionAttributeName4"),
ParenthesizePropertyNameAttribute(true),
]
public override string Name
{
get
{
return base.Name;
}
set
{
base.Name = value;
}
}
/// <summary>
/// Gets or sets an annotation's type name.
/// </summary>
/// <remarks>
/// This property is used to get the name of each annotation Style
/// (e.g. Line, Rectangle, Ellipse).
/// <para>
/// This property is for internal use and is hidden at design and run time.
/// </para>
/// </remarks>
[
SRCategory("CategoryAttributeMisc"),
Bindable(true),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeAnnotation_AnnotationType"),
]
public abstract string AnnotationType
{
get;
}
/// <summary>
/// Gets or sets the name of the chart area which an annotation is clipped to.
/// </summary>
/// <value>
/// A string which represents the name of an existing chart area.
/// </value>
/// <remarks>
/// 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.
/// <para>
/// To disable chart area clipping, set the property to "NotSet" or an empty string.
/// </para>
/// </remarks>
[
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();
}
}
}
/// <summary>
/// Gets or sets the smart labels style of an annotation.
/// </summary>
/// <value>
/// An <see cref="AnnotationSmartLabelStyle"/> object that represents an annotation's
/// smart labels style properties.
/// </value>
/// <remarks>
/// Smart labels are used to prevent an annotation from overlapping data point labels
/// and other annotations.
/// <para>
/// Note that data point labels must also have smart labels enabled.
/// </para>
/// </remarks>
[
Browsable(true),
SRCategory("CategoryAttributeMisc"),
Bindable(true),
SRDescription("DescriptionAttributeSmartLabels"),
#if Microsoft_CONTROL
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
#else
PersistenceMode(PersistenceMode.InnerProperty),
#endif
]
public AnnotationSmartLabelStyle SmartLabelStyle
{
get
{
if (this._smartLabelStyle == null)
{
this._smartLabelStyle = new AnnotationSmartLabelStyle(this);
}
return _smartLabelStyle;
}
set
{
value.chartElement = this;
_smartLabelStyle = value;
this.Invalidate();
}
}
/// <summary>
/// Gets the group, if any, the annotation belongs to.
/// </summary>
[
Browsable(false),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
]
public AnnotationGroup AnnotationGroup
{
get { return this.annotationGroup; }
}
#endregion
#region Position
/// <summary>
/// Gets or sets a flag that specifies whether the size of an annotation is always
/// defined in relative chart coordinates.
/// <seealso cref="Width"/>
/// <seealso cref="Height"/>
/// </summary>
/// <value>
/// <b>True</b> if an annotation's <see cref="Width"/> and <see cref="Height"/> are always
/// in chart relative coordinates, <b>false</b> otherwise.
/// </value>
/// <remarks>
/// An annotation's width and height may be set in relative chart or axes coordinates.
/// By default, relative chart coordinates are used.
/// <para>
/// To use axes coordinates for size set the <b>IsSizeAlwaysRelative</b> property to
/// <b>false</b> and either anchor the annotation to a data point or set the
/// <see cref="AxisX"/> or <see cref="AxisY"/> properties.
/// </para>
/// </remarks>
[
SRCategory("CategoryAttributePosition"),
DefaultValue(true),
SRDescription("DescriptionAttributeSizeAlwaysRelative"),
]
virtual public bool IsSizeAlwaysRelative
{
get
{
return _isSizeAlwaysRelative;
}
set
{
_isSizeAlwaysRelative = value;
this.ResetCurrentRelativePosition();
Invalidate();
}
}
/// <summary>
/// Gets or sets the X coordinate of an annotation.
/// <seealso cref="AnchorDataPoint"/>
/// <seealso cref="AnchorX"/>
/// </summary>
/// <value>
/// A Double value that represents the X coordinate of an annotation.
/// </value>
/// <remarks>
/// The X coordinate of an annotation is in relative chart coordinates or axes coordinates. Chart
/// relative coordinates are used by default.
/// <para>
/// To use axes coordinates, anchor
/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or
/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties.
/// </para>
/// <para>
/// Set the X position to Double.NaN ("NotSet") to achieve automatic position calculation
/// when the annotation is anchored using the <see cref="AnchorDataPoint"/> property or
/// the <see cref="AnchorX"/> and <see cref="AnchorY"/> properties.
/// </para>
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets the Y coordinate of an annotation.
/// <seealso cref="AnchorDataPoint"/>
/// <seealso cref="AnchorY"/>
/// </summary>
/// <value>
/// A Double value that represents the Y coordinate of an annotation.
/// </value>
/// <remarks>
/// The Y coordinate of an annotation is in relative chart coordinates or axes coordinates. Chart
/// relative coordinates are used by default.
/// <para>
/// To use axes coordinates, anchor
/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or
/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties.
/// </para>
/// <para>
/// Set the Y position to Double.NaN ("NotSet") to achieve automatic position calculation
/// when the annotation is anchored using the <see cref="AnchorDataPoint"/> property or
/// the <see cref="AnchorX"/> and <see cref="AnchorY"/> properties.
/// </para>
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets an annotation's width.
/// <seealso cref="IsSizeAlwaysRelative"/>
/// <seealso cref="AxisX"/>
/// </summary>
/// <value>
/// A Double value that represents an annotation's width.
/// </value>
/// <remarks>
/// An annotation's width can be a negative value, in which case the annotation orientation
/// is switched.
/// <para>
/// Annotation width can be in relative chart or axes coordinates. Chart
/// relative coordinates are used by default.
/// </para>
/// <para>
/// To use axes coordinates, anchor
/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or
/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties
/// and set the <see cref="IsSizeAlwaysRelative"/> property to <b>false</b>.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets an annotation's height.
/// <seealso cref="IsSizeAlwaysRelative"/>
/// <seealso cref="AxisY"/>
/// </summary>
/// <value>
/// A Double value that represents an annotation's height.
/// </value>
/// <remarks>
/// An annotation's height can be a negative value, in which case the annotation orientation
/// is switched.
/// <para>
/// Annotation height can be in relative chart or axes coordinates. Chart
/// relative coordinates are used by default.
/// </para>
/// <para>
/// To use axes coordinates, anchor
/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or
/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties
/// and set the <see cref="IsSizeAlwaysRelative"/> property to <b>false</b>.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets an annotation position's right boundary.
/// <seealso cref="IsSizeAlwaysRelative"/>
/// <seealso cref="AxisX"/>
/// </summary>
/// <value>
/// A Double value that represents the position of an annotation's right boundary.
/// </value>
/// <remarks>
/// To use axes coordinates, anchor
/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or
/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties
/// and set the <see cref="IsSizeAlwaysRelative"/> property to <b>false</b>.
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets an annotation position's bottom boundary.
/// <seealso cref="IsSizeAlwaysRelative"/>
/// <seealso cref="AxisX"/>
/// </summary>
/// <value>
/// A Double value that represents the position of an annotation's bottom boundary.
/// </value>
/// <remarks>
/// To use axes coordinates, anchor
/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or
/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties
/// and set the <see cref="IsSizeAlwaysRelative"/> property to <b>false</b>.
/// </remarks>
[
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
#if Microsoft_CONTROL
/// <summary>
/// Gets or sets a flag that determines if an annotation is selected.
/// <seealso cref="AllowSelecting"/>
/// </summary>
/// <value>
/// <b>True</b> if the annotation is selected, <b>false</b> otherwise.
/// </value>
#else
/// <summary>
/// Gets or sets a flag that determines if an annotation is selected.
/// </summary>
/// <value>
/// <b>True</b> if the annotation is selected, <b>false</b> otherwise.
/// </value>
#endif // Microsoft_CONTROL
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(false),
Browsable(false),
SRDescription("DescriptionAttributeSelected"),
]
virtual public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets an annotation selection points style.
/// </summary>
/// <value>
/// A <see cref="SelectionPointsStyle"/> value that represents annotation
/// selection style.
/// </value>
/// <remarks>
/// This property is for internal use and is hidden at design and run time.
/// </remarks>
[
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;
}
}
/// <summary>
/// Gets or sets a flag that specifies whether an annotation is visible.
/// </summary>
/// <value>
/// <b>True</b> if the annotation is visible, <b>false</b> otherwise.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(true),
SRDescription("DescriptionAttributeVisible"),
ParenthesizePropertyNameAttribute(true),
]
virtual public bool Visible
{
get
{
return _visible;
}
set
{
_visible = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets an annotation's content alignment.
/// </summary>
/// <value>
/// A <see cref="ContentAlignment"/> value that represents the content alignment.
/// </value>
/// <remarks>
/// This property is used to align text for <see cref="TextAnnotation"/>, <see cref="RectangleAnnotation"/>,
/// <see cref="EllipseAnnotation"/> and <see cref="CalloutAnnotation"/> objects, and to align
/// a non-scaled image inside an <see cref="ImageAnnotation"/> object.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(ContentAlignment), "MiddleCenter"),
SRDescription("DescriptionAttributeAlignment"),
]
virtual public ContentAlignment Alignment
{
get
{
return _alignment;
}
set
{
_alignment = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the text color of an annotation.
/// <seealso cref="Font"/>
/// </summary>
/// <value>
/// A <see cref="Color"/> value used for the text color of an annotation.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), "Black"),
SRDescription("DescriptionAttributeForeColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
virtual public Color ForeColor
{
get
{
return _foreColor;
}
set
{
_foreColor = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the font of an annotation's text.
/// <seealso cref="ForeColor"/>
/// </summary>
/// <value>
/// A <see cref="Font"/> object used for an annotation's text.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
SRDescription("DescriptionAttributeTextFont"),
]
virtual public Font Font
{
get
{
return _textFont;
}
set
{
_textFont = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets an annotation's text style.
/// <seealso cref="Font"/>
/// <seealso cref="ForeColor"/>
/// </summary>
/// <value>
/// A <see cref="TextStyle"/> value used to draw an annotation's text.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(TextStyle), "Default"),
SRDescription("DescriptionAttributeTextStyle"),
]
virtual public TextStyle TextStyle
{
get
{
return _textStyle;
}
set
{
_textStyle = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the color of an annotation line.
/// <seealso cref="LineWidth"/>
/// <seealso cref="LineDashStyle"/>
/// </summary>
/// <value>
/// A <see cref="Color"/> value used to draw an annotation line.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), "Black"),
SRDescription("DescriptionAttributeLineColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
virtual public Color LineColor
{
get
{
return lineColor;
}
set
{
lineColor = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the width of an annotation line.
/// <seealso cref="LineColor"/>
/// <seealso cref="LineDashStyle"/>
/// </summary>
/// <value>
/// An integer value defining the width of an annotation line in pixels.
/// </value>
[
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();
}
}
/// <summary>
/// Gets or sets the style of an annotation line.
/// <seealso cref="LineWidth"/>
/// <seealso cref="LineColor"/>
/// </summary>
/// <value>
/// A <see cref="ChartDashStyle"/> value used to draw an annotation line.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(ChartDashStyle.Solid),
SRDescription("DescriptionAttributeLineDashStyle"),
]
virtual public ChartDashStyle LineDashStyle
{
get
{
return _lineDashStyle;
}
set
{
_lineDashStyle = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the background color of an annotation.
/// <seealso cref="BackSecondaryColor"/>
/// <seealso cref="BackHatchStyle"/>
/// <seealso cref="BackGradientStyle"/>
/// </summary>
/// <value>
/// A <see cref="Color"/> value used for the background of an annotation.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), ""),
SRDescription("DescriptionAttributeBackColor"),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
virtual public Color BackColor
{
get
{
return _backColor;
}
set
{
_backColor = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the background hatch style of an annotation.
/// <seealso cref="BackSecondaryColor"/>
/// <seealso cref="BackColor"/>
/// <seealso cref="BackGradientStyle"/>
/// </summary>
/// <value>
/// A <see cref="ChartHatchStyle"/> value used for the background of an annotation.
/// </value>
/// <remarks>
/// Two colors are used to draw the hatching, <see cref="BackColor"/> and <see cref="BackSecondaryColor"/>.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(ChartHatchStyle.None),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackHatchStyle"),
Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
]
virtual public ChartHatchStyle BackHatchStyle
{
get
{
return _backHatchStyle;
}
set
{
_backHatchStyle = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the background gradient style of an annotation.
/// <seealso cref="BackSecondaryColor"/>
/// <seealso cref="BackColor"/>
/// <seealso cref="BackHatchStyle"/>
/// </summary>
/// <value>
/// A <see cref="GradientStyle"/> value used for the background of an annotation.
/// </value>
/// <remarks>
/// Two colors are used to draw the gradient, <see cref="BackColor"/> and <see cref="BackSecondaryColor"/>.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(GradientStyle.None),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackGradientStyle"),
Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
]
virtual public GradientStyle BackGradientStyle
{
get
{
return _backGradientStyle;
}
set
{
_backGradientStyle = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the secondary background color of an annotation.
/// <seealso cref="BackColor"/>
/// <seealso cref="BackHatchStyle"/>
/// <seealso cref="BackGradientStyle"/>
/// </summary>
/// <value>
/// A <see cref="Color"/> value used for the secondary color of an annotation background with
/// hatching or gradient fill.
/// </value>
/// <remarks>
/// This color is used with <see cref="BackColor"/> when <see cref="BackHatchStyle"/> or
/// <see cref="BackGradientStyle"/> are used.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), ""),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackSecondaryColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
virtual public Color BackSecondaryColor
{
get
{
return _backSecondaryColor;
}
set
{
_backSecondaryColor = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the color of an annotation's shadow.
/// <seealso cref="ShadowOffset"/>
/// </summary>
/// <value>
/// A <see cref="Color"/> value used to draw an annotation's shadow.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Color), "128,0,0,0"),
SRDescription("DescriptionAttributeShadowColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
virtual public Color ShadowColor
{
get
{
return _shadowColor;
}
set
{
_shadowColor = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the offset between an annotation and its shadow.
/// <seealso cref="ShadowColor"/>
/// </summary>
/// <value>
/// An integer value that represents the offset between an annotation and its shadow.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(0),
SRDescription("DescriptionAttributeShadowOffset"),
]
virtual public int ShadowOffset
{
get
{
return _shadowOffset;
}
set
{
_shadowOffset = value;
Invalidate();
}
}
#endregion
#region Axes Attaching
/// <summary>
/// Gets or sets the name of the X axis which an annotation is attached to.
/// </summary>
/// <value>
/// A string value that represents the name of the X axis which an annotation
/// is attached to.
/// </value>
/// <remarks>
/// This property is for internal use and is hidden at design and run time.
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets the name of the Y axis which an annotation is attached to.
/// </summary>
/// <value>
/// A string value that represents the name of the Y axis which an annotation
/// is attached to.
/// </value>
/// <remarks>
/// This property is for internal use and is hidden at design and run time.
/// </remarks>
[
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;
}
}
/// <summary>
/// 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.
/// </summary>
/// <value>
/// A string value that represents the name of the Y axis which an annotation
/// is attached to.
/// </value>
/// <remarks>
/// This property is for internal use and is hidden at design and run time.
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets the X axis which an annotation is attached to.
/// <seealso cref="AxisY"/>
/// <seealso cref="IsSizeAlwaysRelative"/>
/// </summary>
/// <value>
/// <see cref="Axis"/> object which an annotation is attached to.
/// </value>
/// <remarks>
/// 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 <see cref="IsSizeAlwaysRelative"/> property is set to <b>false</b>.
/// <para>
/// Set this value to <b>null</b> or <b>nothing</b> to disable attachment to the axis.
/// </para>
/// </remarks>
[
SRCategory("CategoryAttributeAnchorAxes"),
DefaultValue(null),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeAxisX"),
Editor(Editors.AnnotationAxisUITypeEditor.Editor, Editors.AnnotationAxisUITypeEditor.Base),
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();
}
}
/// <summary>
/// Gets or sets the Y axis which an annotation is attached to.
/// <seealso cref="AxisX"/>
/// <seealso cref="IsSizeAlwaysRelative"/>
/// </summary>
/// <value>
/// <see cref="Axis"/> object which an annotation is attached to.
/// </value>
/// <remarks>
/// 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 <see cref="IsSizeAlwaysRelative"/> property is set to <b>false</b>.
/// <para>
/// Set this value to <b>null</b> or <b>nothing</b> to disable annotation attachment to an axis.
/// </para>
/// </remarks>
[
SRCategory("CategoryAttributeAnchorAxes"),
DefaultValue(null),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeAxisY"),
Editor(Editors.AnnotationAxisUITypeEditor.Editor, Editors.AnnotationAxisUITypeEditor.Base),
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();
}
}
#endregion
#region Anchor
/// <summary>
/// Gets or sets the name of a data point which an annotation is anchored to.
/// </summary>
/// <value>
/// A string value that represents the name of the data point which an
/// annotation is anchored to.
/// </value>
/// <remarks>
/// This property is for internal use and is hidden at design and run time.
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets the data point an annotation is anchored to.
/// <seealso cref="AnchorAlignment"/>
/// <seealso cref="AnchorOffsetX"/>
/// <seealso cref="AnchorOffsetY"/>
/// <seealso cref="AnchorX"/>
/// <seealso cref="AnchorY"/>
/// <seealso cref="SetAnchor(Charting.DataPoint)"/>
/// <seealso cref="SetAnchor(Charting.DataPoint, Charting.DataPoint)"/>
/// </summary>
/// <value>
/// A <see cref="DataPoint"/> object an annotation is anchored to.
/// </value>
/// <remarks>
/// 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.
/// <para>
/// To automatically position an annotation relative to an anchor point, make sure
/// its <see cref="X"/> and <see cref="Y"/> properties are set to <b>Double.NaN</b>.
/// The <see cref="AnchorAlignment"/> property may be used to change an annotation's
/// automatic position alignment to an anchor point. The <see cref="AnchorOffsetX"/> and
/// <see cref="AnchorOffsetY"/> properties may be used to add extra spacing.
/// </para>
/// <para>
/// When using this property, make sure the <see cref="AnchorX"/> and <see cref="AnchorY"/>
/// properties are set to <b>Double.NaN</b> (they have precedence).
/// </para>
/// <para>
/// Set this value to <b>null</b> or <b>nothing</b> to disable annotation anchoring to a data point.
/// </para>
/// </remarks>
[
SRCategory("CategoryAttributeAnchor"),
DefaultValue(null),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeAnchorDataPoint"),
Editor(Editors.AnchorPointUITypeEditor.Editor, Editors.AnchorPointUITypeEditor.Base),
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();
}
}
/// <summary>
/// Gets or sets the X coordinate the annotation is anchored to.
/// <seealso cref="AnchorY"/>
/// <seealso cref="AnchorOffsetX"/>
/// <seealso cref="AnchorOffsetY"/>
/// <seealso cref="AnchorAlignment"/>
/// <seealso cref="AnchorDataPoint"/>
/// </summary>
/// <value>
/// A double value that represents the X coordinate which an annotation is anchored to.
/// </value>
/// <remarks>
/// The annotation is anchored to the X coordinate specified in relative or axis coordinates,
/// depending on the <see cref="AxisX"/> property value.
/// <para>
/// To automatically position an annotation relative to an anchor point, make sure
/// its <see cref="X"/> property is set to <b>Double.NaN</b>.
/// The <see cref="AnchorAlignment"/> property may be used to change the annotation's
/// automatic position alignment to the anchor point. The <see cref="AnchorOffsetX"/> and
/// <see cref="AnchorOffsetY"/> properties may be used to add extra spacing.
/// </para>
/// <para>
/// This property has a higher priority than the <see cref="AnchorDataPoint"/> property.
/// </para>
/// <para>
/// Set this value to <b>Double.NaN</b> to disable annotation anchoring to the value.
/// </para>
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets the Y coordinate which an annotation is anchored to.
/// <seealso cref="AnchorY"/>
/// <seealso cref="AnchorOffsetX"/>
/// <seealso cref="AnchorOffsetY"/>
/// <seealso cref="AnchorAlignment"/>
/// <seealso cref="AnchorDataPoint"/>
/// </summary>
/// <value>
/// A double value that represents the Y coordinate which an annotation is anchored to.
/// </value>
/// <remarks>
/// The annotation is anchored to the Y coordinate specified in relative or axis coordinates,
/// depending on the <see cref="AxisX"/> property value.
/// <para>
/// To automatically position an annotation relative to an anchor point, make sure
/// its <see cref="Y"/> property is set to <b>Double.NaN</b>.
/// The <see cref="AnchorAlignment"/> property may be used to change the annotation's
/// automatic position alignment to the anchor point. The <see cref="AnchorOffsetX"/> and
/// <see cref="AnchorOffsetY"/> properties may be used to add extra spacing.
/// </para>
/// <para>
/// This property has a higher priority than the <see cref="AnchorDataPoint"/> property.
/// </para>
/// <para>
/// Set this value to <b>Double.NaN</b> to disable annotation anchoring to the value.
/// </para>
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets the x-coordinate offset between the positions of an annotation and its anchor point.
/// <seealso cref="AnchorOffsetY"/>
/// <seealso cref="AnchorDataPoint"/>
/// <seealso cref="AnchorX"/>
/// <seealso cref="AnchorAlignment"/>
/// </summary>
/// <value>
/// A double value that represents the x-coordinate offset between the positions of an annotation and its anchor point.
/// </value>
/// <remarks>
/// The annotation must be anchored using the <see cref="AnchorDataPoint"/> or
/// <see cref="AnchorX"/> properties, and its <see cref="X"/> property must be set
/// to <b>Double.NaN</b>.
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets the y-coordinate offset between the positions of an annotation and its anchor point.
/// <seealso cref="Annotation.AnchorOffsetX"/>
/// <seealso cref="Annotation.AnchorDataPoint"/>
/// <seealso cref="Annotation.AnchorY"/>
/// <seealso cref="Annotation.AnchorAlignment"/>
/// </summary>
/// <value>
/// A double value that represents the y-coordinate offset between the positions of an annotation and its anchor point.
/// </value>
/// <remarks>
/// Annotation must be anchored using <see cref="Annotation.AnchorDataPoint"/> or
/// <see cref="Annotation.AnchorY"/> properties and it's <see cref="Annotation.Y"/> property must be set
/// to <b>Double.NaN</b>.
/// </remarks>
[
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();
}
}
/// <summary>
/// Gets or sets an annotation position's alignment to the anchor point.
/// <seealso cref="AnchorX"/>
/// <seealso cref="AnchorY"/>
/// <seealso cref="AnchorDataPoint"/>
/// <seealso cref="AnchorOffsetX"/>
/// <seealso cref="AnchorOffsetY"/>
/// </summary>
/// <value>
/// A <see cref="ContentAlignment"/> value that represents the annotation's alignment to
/// the anchor point.
/// </value>
/// <remarks>
/// The annotation must be anchored using either <see cref="AnchorDataPoint"/>, or the <see cref="AnchorX"/>
/// and <see cref="AnchorY"/> properties. Its <see cref="X"/> and <see cref="Y"/>
/// properties must be set to <b>Double.NaN</b>.
/// </remarks>
[
SRCategory("CategoryAttributeAnchor"),
DefaultValue(typeof(ContentAlignment), "BottomCenter"),
SRDescription("DescriptionAttributeAnchorAlignment"),
]
virtual public ContentAlignment AnchorAlignment
{
get
{
return anchorAlignment;
}
set
{
anchorAlignment = value;
this.ResetCurrentRelativePosition();
Invalidate();
}
}
#endregion // Anchoring
#region Editing Permissions
#if Microsoft_CONTROL
/// <summary>
/// Gets or sets a flag that specifies whether an annotation may be selected
/// with a mouse by the end user.
/// </summary>
/// <value>
/// <b>True</b> if the annotation may be selected, <b>false</b> otherwise.
/// </value>
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowSelecting"),
]
virtual public bool AllowSelecting
{
get
{
return _allowSelecting;
}
set
{
_allowSelecting = value;
}
}
/// <summary>
/// Gets or sets a flag that specifies whether an annotation may be moved
/// with a mouse by the end user.
/// </summary>
/// <value>
/// <b>True</b> if the annotation may be moved, <b>false</b> otherwise.
/// </value>
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowMoving"),
]
virtual public bool AllowMoving
{
get
{
return _allowMoving;
}
set
{
_allowMoving = value;
}
}
/// <summary>
/// Gets or sets a flag that specifies whether an annotation anchor may be moved
/// with a mouse by the end user.
/// </summary>
/// <value>
/// <b>True</b> if the annotation anchor may be moved, <b>false</b> otherwise.
/// </value>
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowAnchorMoving3"),
]
virtual public bool AllowAnchorMoving
{
get
{
return _allowAnchorMoving;
}
set
{
_allowAnchorMoving = value;
}
}
/// <summary>
/// Gets or sets a flag that specifies whether an annotation may be resized
/// with a mouse by the end user.
/// </summary>
/// <value>
/// <b>True</b> if the annotation may be resized, <b>false</b> otherwise.
/// </value>
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowResizing"),
]
virtual public bool AllowResizing
{
get
{
return _allowResizing;
}
set
{
_allowResizing = value;
}
}
/// <summary>
/// Gets or sets a flag that specifies whether an annotation's text may be edited
/// when the end user double clicks on the text.
/// </summary>
/// <value>
/// <b>True</b> if the annotation text may be edited, <b>false</b> otherwise.
/// </value>
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowTextEditing"),
]
virtual public bool AllowTextEditing
{
get
{
return _allowTextEditing;
}
set
{
_allowTextEditing = value;
}
}
/// <summary>
/// Gets or sets a flag that specifies whether a polygon annotation's points
/// may be moved with a mouse by the end user.
/// </summary>
/// <value>
/// <b>True</b> if the polygon annotation's points may be moved, <b>false</b> otherwise.
/// </value>
[
SRCategory("CategoryAttributeEditing"),
DefaultValue(false),
SRDescription("DescriptionAttributeAllowPathEditing3"),
]
virtual public bool AllowPathEditing
{
get
{
return _allowPathEditing;
}
set
{
_allowPathEditing = value;
}
}
#endif // Microsoft_CONTROL
#endregion
#region Interactivity
/// <summary>
/// Gets or sets an annotation's tooltip text.
/// </summary>
/// <value>
/// A string value.
/// </value>
/// <remarks>
/// Special keywords can be used in the text when an annotation is anchored to
/// a data point using the <see cref="AnchorDataPoint"/> property. For a listing of
/// these keywords, refer to the "Annotations" help topic.
/// </remarks>
[
SRCategory("CategoryAttributeMisc"),
DefaultValue(""),
SRDescription("DescriptionAttributeToolTip"),
]
virtual public string ToolTip
{
get
{
return _tooltip;
}
set
{
_tooltip = value;
}
}
#if !Microsoft_CONTROL
/// <summary>
/// Gets or sets an annotation's Url.
/// </summary>
/// <value>
/// A string value.
/// </value>
/// <remarks>
/// Special keywords can be used when an annotation is anchored to
/// a data point using the <see cref="AnchorDataPoint"/> property. For a listing of
/// these keywords, refer to the "Annotations" help topic.
/// </remarks>
[
SRCategory("CategoryAttributeMisc"),
DefaultValue(""),
SRDescription("DescriptionAttributeUrl"),
]
virtual public string Url
{
get
{
return _url;
}
set
{
_url = value;
}
}
/// <summary>
/// Gets or sets an annotation's map area attributes.
/// </summary>
/// <value>
/// A string value.
/// </value>
/// <remarks>
/// This string will be added to the attributes of the image map generated
/// for the annotation.
/// <para>
/// Special keywords can be used when an annotation is anchored to
/// a data point using the <see cref="AnchorDataPoint"/> property. For a listing of
/// these keywords, refer to the "Annotations" help topic.
/// </para>
/// </remarks>
[
SRCategory("CategoryAttributeMisc"),
DefaultValue(""),
SRDescription("DescriptionAttributeMapAreaAttributes"),
]
virtual public string MapAreaAttributes
{
get
{
return _mapAreaAttributes;
}
set
{
_mapAreaAttributes = value;
}
}
/// <summary>
/// Gets or sets the postback value which can be processed on click event.
/// </summary>
/// <value>The value which is passed to click event as argument.</value>
[DefaultValue("")]
[SRCategory(SR.Keys.CategoryAttributeMapArea)]
[SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
public string PostBackValue
{
get
{
return this._postbackValue;
}
set
{
this._postbackValue = value;
}
}
#endif // !Microsoft_CONTROL
#endregion // Interactivity
#endregion
#region Methods
#region Painting
/// <summary>
/// Paints the annotation object using the specified graphics.
/// </summary>
/// <param name="graphics">
/// A <see cref="ChartGraphics"/> object used to paint the annotation object.
/// </param>
/// <param name="chart">
/// Reference to the annotation's <see cref="Chart"/> control owner.
/// </param>
abstract internal void Paint(Chart chart, ChartGraphics graphics);
/// <summary>
/// Paints annotation selection markers.
/// </summary>
/// <param name="chartGraphics">Chart graphics used for painting.</param>
/// <param name="rect">Selection rectangle.</param>
/// <param name="path">Selection path.</param>
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);
}
#if Microsoft_CONTROL
//********************************************************************
//** 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);
}
}
#endif // Microsoft_CONTROL
}
}
}
#endregion
#region Position and Size
/// <summary>
/// Resizes an annotation according to its content size.
/// </summary>
/// <remarks>
/// Sets the annotation width and height to fit the specified text. This method applies to
/// <see cref="TextAnnotation"/>, <see cref="RectangleAnnotation"/>, <see cref="EllipseAnnotation"/>
/// and <see cref="CalloutAnnotation"/> objects only.
/// </remarks>
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;
}
}
/// <summary>
/// Gets an annotation's content position.
/// </summary>
/// <returns>Annotation's content size.</returns>
virtual internal RectangleF GetContentPosition()
{
return new RectangleF(float.NaN, float.NaN, float.NaN, float.NaN);
}
/// <summary>
/// Gets an annotation's anchor point location.
/// </summary>
/// <param name="anchorX">Returns the anchor X coordinate.</param>
/// <param name="anchorY">Returns the anchor Y coordinate.</param>
/// <param name="inRelativeAnchorX">Indicates if X coordinate is in relative chart coordinates.</param>
/// <param name="inRelativeAnchorY">Indicates if Y coordinate is in relative chart coordinates.</param>
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;
}
}
}
}
/// <summary>
/// Gets annotation object position in relative coordinates.
/// </summary>
/// <param name="location">Returns annotation location.</param>
/// <param name="size">Returns annotation size.</param>
/// <param name="anchorLocation">Returns annotation anchor point location.</param>
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);
}
}
#if Microsoft_CONTROL
/// <summary>
/// Set annotation object position using rectangle in relative coordinates.
/// Automatically converts relative coordinates to axes values if required.
/// </summary>
/// <param name="position">Position in relative coordinates.</param>
/// <param name="anchorPoint">Anchor location in relative coordinates.</param>
internal void SetPositionRelative(RectangleF position, PointF anchorPoint)
{
SetPositionRelative(position, anchorPoint, false);
}
#endif // Microsoft_CONTROL
/// <summary>
/// Set annotation object position using rectangle in relative coordinates.
/// Automatically converts relative coordinates to axes values if required.
/// </summary>
/// <param name="position">Position in relative coordinates.</param>
/// <param name="anchorPoint">Anchor location in relative coordinates.</param>
/// <param name="userInput">Indicates if position changing was a result of the user input.</param>
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)
{
#if Microsoft_CONTROL
// 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;
}
}
#endif // Microsoft_CONTROL
}
// 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;
}
/// <summary>
/// Adjust annotation location and\or size as a result of user action.
/// </summary>
/// <param name="movingDistance">Distance to resize/move the annotation.</param>
/// <param name="resizeMode">Resizing mode.</param>
virtual internal void AdjustLocationSize(SizeF movingDistance, ResizingMode resizeMode)
{
AdjustLocationSize(movingDistance, resizeMode, true);
}
/// <summary>
/// Adjust annotation location and\or size as a result of user action.
/// </summary>
/// <param name="movingDistance">Distance to resize/move the annotation.</param>
/// <param name="resizeMode">Resizing mode.</param>
/// <param name="pixelCoord">Distance is in pixels, otherwise relative.</param>
virtual internal void AdjustLocationSize(SizeF movingDistance, ResizingMode resizeMode, bool pixelCoord)
{
AdjustLocationSize(movingDistance, resizeMode, pixelCoord, false);
}
/// <summary>
/// Adjust annotation location and\or size as a result of user action.
/// </summary>
/// <param name="movingDistance">Distance to resize/move the annotation.</param>
/// <param name="resizeMode">Resizing mode.</param>
/// <param name="pixelCoord">Distance is in pixels, otherwise relative.</param>
/// <param name="userInput">Indicates if position changing was a result of the user input.</param>
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 Microsoft_CONTROL
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 // Microsoft_CONTROL
GetRelativePosition(out firstPoint, out size, out anchorPoint);
#endif // Microsoft_CONTROL
}
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
/// <summary>
/// Checks if annotation draw anything in the anchor position (except selection handle)
/// </summary>
/// <returns>True if annotation "connects" itself and anchor point visually.</returns>
virtual internal bool IsAnchorDrawn()
{
return false;
}
/// <summary>
/// Gets data point by name.
/// </summary>
/// <param name="dataPointName">Data point name to find.</param>
/// <returns>Data point.</returns>
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;
if (int.TryParse(pointIndex, NumberStyles.Any, CultureInfo.InvariantCulture, out index))
{
dataPoint = Chart.Series[seriesName].Points[index];
}
}
}
return dataPoint;
}
/// <summary>
/// Gets axis by name.
/// </summary>
/// <param name="axisName">Axis name to find.</param>
/// <returns>Data point.</returns>
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;
}
/// <summary>
/// Gets data point unique name.
/// </summary>
/// <param name="dataPoint">Data point to get the name for.</param>
/// <returns>Data point name.</returns>
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;
}
/// <summary>
/// Gets axis unique name.
/// </summary>
/// <param name="axis">Axis to get the name for.</param>
/// <returns>Axis name.</returns>
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
/// <summary>
/// Sends an annotation to the back of all annotations.
/// <seealso cref="BringToFront"/>
/// </summary>
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);
}
}
}
/// <summary>
/// Brings an annotation to the front of all annotations.
/// <seealso cref="SendToBack"/>
/// </summary>
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
/// <summary>
/// Adds anchor position to the list. Used to check SmartLabelStyle overlapping.
/// </summary>
/// <param name="list">List to add to.</param>
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
/// <summary>
/// Anchors an annotation to a data point.
/// <seealso cref="AnchorDataPoint"/>
/// <seealso cref="AnchorX"/>
/// <seealso cref="AnchorY"/>
/// </summary>
/// <param name="dataPoint">
/// <see cref="DataPoint"/> to be anchored to.
/// </param>
/// <remarks>
/// Anchors an annotation to the specified data point.
/// </remarks>
public void SetAnchor(DataPoint dataPoint)
{
SetAnchor(dataPoint, null);
}
/// <summary>
/// Anchors an annotation to two data points.
/// <seealso cref="AnchorDataPoint"/>
/// <seealso cref="AnchorX"/>
/// <seealso cref="AnchorY"/>
/// </summary>
/// <param name="dataPoint1">
/// First anchor <see cref="DataPoint"/>.
/// </param>
/// <param name="dataPoint2">
/// Second anchor <see cref="DataPoint"/>.
/// </param>
/// <remarks>
/// Anchors an annotation's top/left and bottom/right corners to the
/// specified data points.
/// </remarks>
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
#if Microsoft_CONTROL
/// <summary>
/// Begins end user placement of an annotation using the mouse.
/// </summary>
/// <remarks>
/// When this method is called, the end user is allowed to place an annotation using the
/// mouse.
/// <para>
/// Placement will finish when the end user specifies all required points, or
/// the <see cref="EndPlacement"/> method is called.</para>
/// </remarks>
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));
}
}
/// <summary>
/// Ends user placement of an annotation.
/// </summary>
/// <remarks>
/// Ends an annotation placement operation previously started by a
/// <see cref="BeginPlacement"/> method call.
/// <para>
/// 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.
/// </para>
/// </remarks>
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);
}
}
/// <summary>
/// Handles mouse down event during annotation placement.
/// </summary>
/// <param name="point">Mouse cursor position in pixels.</param>
/// <param name="buttons">Mouse button down.</param>
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();
}
}
}
}
/// <summary>
/// Handles mouse up event during annotation placement.
/// </summary>
/// <param name="point">Mouse cursor position in pixels.</param>
/// <param name="buttons">Mouse button Up.</param>
/// <returns>Return true when placing finished.</returns>
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;
}
/// <summary>
/// Handles mouse move event during annotation placement.
/// </summary>
/// <param name="point">Mouse cursor position in pixels.</param>
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();
}
}
}
/// <summary>
/// Checks if specified position is valid for placement.
/// </summary>
/// <param name="x">X coordinate.</param>
/// <param name="y">Y coordinate.</param>
/// <returns>True if annotation can be placed at specified coordinates.</returns>
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;
}
#endif // Microsoft_CONTROL
#endregion // Placement Methods
#region Helper Methods
/// <summary>
/// Helper method that checks if annotation is visible.
/// </summary>
/// <returns>True if annotation is visible.</returns>
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;
}
/// <summary>
/// Resets pre-calculated annotation position.
/// </summary>
internal void ResetCurrentRelativePosition()
{
this.currentPositionRel = new RectangleF(float.NaN, float.NaN, float.NaN, float.NaN);
this.currentAnchorLocationRel = new PointF(float.NaN, float.NaN);
}
/// <summary>
/// Replaces predefined keyword inside the string with their values if
/// annotation is anchored to the data point.
/// </summary>
/// <param name="strOriginal">Original string with keywords.</param>
/// <returns>Modified string.</returns>
internal string ReplaceKeywords(string strOriginal)
{
if(this.AnchorDataPoint != null)
{
return this.AnchorDataPoint.ReplaceKeywords(strOriginal);
}
return strOriginal;
}
/// <summary>
/// Checks if anchor point of the annotation is visible.
/// </summary>
/// <returns>True if anchor point is visible.</returns>
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;
}
/// <summary>
/// Returns chart graphics objects.
/// </summary>
/// <returns>Chart graphics object.</returns>
internal ChartGraphics GetGraphics()
{
if (this.Common != null)
{
return this.Common.graph;
}
return null;
}
#if Microsoft_CONTROL
/// <summary>
/// Checks if provided pixel coordinate is contained in one of the
/// selection handles rectangle.
/// </summary>
/// <param name="point">Coordinate in pixels.</param>
/// <returns>Resizing mode.</returns>
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;
}
#endif //Microsoft_CONTROL
/// <summary>
/// Gets data point X or Y axis.
/// </summary>
/// <param name="dataPoint">Data point to get the axis for.</param>
/// <param name="axisName">X or Y axis to get.</param>
/// <returns>Data point axis.</returns>
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;
}
/// <summary>
/// Gets annotation vertical and horizontal axes.
/// </summary>
/// <param name="vertAxis">Returns annotation vertical axis or null.</param>
/// <param name="horizAxis">Returns annotation horizontal axis or null.</param>
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
/// <summary>
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
//Free managed resources
if (_fontCache != null)
{
_fontCache.Dispose();
_fontCache = null;
}
}
base.Dispose(disposing);
}
#endregion
}
#if Microsoft_CONTROL
/// <summary>
/// This class is used to stores position changing event data for an annotation.
/// </summary>
/// <remarks>
/// Provides additional data like the new annotation and anchor position when an end user
/// is moving the annotation with the mouse.
/// <para>
/// Can be used to restrict annotation movement, or snap the annotation position to
/// specific points.
/// </para>
/// </remarks>
[
SRDescription("DescriptionAttributeAnnotationPositionChangingEventArgs_AnnotationPositionChangingEventArgs"),
]
public class AnnotationPositionChangingEventArgs : EventArgs
{
#region Fields
private Annotation _Annotation = null;
/// <summary>
/// Gets or sets the annotation the event is fired for.
/// </summary>
public Annotation Annotation
{
get { return _Annotation; }
set { _Annotation = value; }
}
private double _NewLocationX = 0.0;
/// <summary>
/// Gets or sets the new X location of the annotation.
/// </summary>
public double NewLocationX
{
get { return _NewLocationX; }
set { _NewLocationX = value; }
}
private double _NewLocationY = 0.0;
/// <summary>
/// Gets or sets the new Y location of the annotation.
/// </summary>
public double NewLocationY
{
get { return _NewLocationY; }
set { _NewLocationY = value; }
}
private double _NewSizeWidth = 0.0;
/// <summary>
/// Gets or sets the new width of the annotation.
/// </summary>
public double NewSizeWidth
{
get { return _NewSizeWidth; }
set { _NewSizeWidth = value; }
}
private double _NewSizeHeight = 0.0;
/// <summary>
/// Gets or sets the new height of the annotation.
/// </summary>
public double NewSizeHeight
{
get { return _NewSizeHeight; }
set { _NewSizeHeight = value; }
}
private double _NewAnchorLocationX = 0.0;
/// <summary>
/// Gets or sets the new annotation anchor point X location.
/// </summary>
public double NewAnchorLocationX
{
get { return _NewAnchorLocationX; }
set { _NewAnchorLocationX = value; }
}
private double _NewAnchorLocationY = 0.0;
/// <summary>
/// Gets or sets the new annotation anchor point Y location.
/// </summary>
public double NewAnchorLocationY
{
get { return _NewAnchorLocationY; }
set { _NewAnchorLocationY = value; }
}
#endregion // Fields
#region Properties
/// <summary>
/// Gets or sets the new location and size of the annotation.
/// </summary>
[
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;
}
}
/// <summary>
/// Gets or sets the new anchor location of the annotation.
/// </summary>
[
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
}
#endif //Microsoft_CONTROL
}