|
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: RectangleAnnotation.cs
//
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
//
// Classes: PolylineAnnotation, PolygonAnnotation
//
// Purpose: Polyline and polygon annotation classes.
//
// Reviewed:
//
//===================================================================
#region Used namespace
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.Diagnostics.CodeAnalysis;
#if Microsoft_CONTROL
using System.Windows.Forms;
using System.Globalization;
using System.Reflection;
using System.ComponentModel.Design.Serialization;
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;
using System.Collections.ObjectModel;
#else
using System.Web;
using System.Web.UI;
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.DataVisualization.Charting.Data;
using System.Web.UI.DataVisualization.Charting.Utilities;
using System.Web.UI.DataVisualization.Charting.Borders3D;
using System.Collections.ObjectModel;
#endif
#endregion
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
#endif
{
/// <summary>
/// <b>PolylineAnnotation</b> is a class that represents a polyline annotation.
/// </summary>
[
SRDescription("DescriptionAttributePolylineAnnotation_PolylineAnnotation"),
]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Polyline")]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class PolylineAnnotation : Annotation
{
#region Fields
// Path with polygon points.
private GraphicsPath _defaultGraphicsPath = new GraphicsPath();
private GraphicsPath _graphicsPath;
// Indicates that path was changed
internal bool pathChanged = false;
// Collection of path points exposed at design-time
private AnnotationPathPointCollection _pathPoints;
// Indicate that filled polygon must be drawn
internal bool isPolygon = false;
// Indicates that annotation will be placed using free-draw style
internal bool isFreeDrawPlacement = false;
// Line start/end caps
private LineAnchorCapStyle _startCap = LineAnchorCapStyle.None;
private LineAnchorCapStyle _endCap = LineAnchorCapStyle.None;
#endregion
#region Construction and Initialization
/// <summary>
/// Default public constructor.
/// </summary>
public PolylineAnnotation()
: base()
{
_pathPoints = new AnnotationPathPointCollection(this);
_graphicsPath = _defaultGraphicsPath;
}
#endregion
#region Properties
#region Polyline Visual Attributes
/// <summary>
/// Gets or sets a cap style used at the start of an annotation line.
/// <seealso cref="EndCap"/>
/// </summary>
/// <value>
/// A <see cref="LineAnchorCapStyle"/> value used for a cap style used at the start of an annotation line.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(LineAnchorCapStyle.None),
SRDescription("DescriptionAttributeStartCap3"),
]
virtual public LineAnchorCapStyle StartCap
{
get
{
return _startCap;
}
set
{
_startCap = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets a cap style used at the end of an annotation line.
/// <seealso cref="StartCap"/>
/// </summary>
/// <value>
/// A <see cref="LineAnchorCapStyle"/> value used for a cap style used at the end of an annotation line.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(LineAnchorCapStyle.None),
SRDescription("DescriptionAttributeStartCap3"),
]
virtual public LineAnchorCapStyle EndCap
{
get
{
return _endCap;
}
set
{
_endCap = value;
Invalidate();
}
}
#endregion
#region Non Applicable Annotation Appearance Attributes (set as Non-Browsable)
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
/// <value>
/// A <see cref="ContentAlignment"/> value.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(typeof(ContentAlignment), "MiddleCenter"),
]
override public ContentAlignment Alignment
{
get
{
return base.Alignment;
}
set
{
base.Alignment = value;
}
}
/// <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>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public override TextStyle TextStyle
{
get
{
return base.TextStyle;
}
set
{
base.TextStyle = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// <seealso cref="Font"/>
/// </summary>
/// <value>
/// A <see cref="Color"/> value.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(typeof(Color), "Black"),
SRDescription("DescriptionAttributeForeColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
base.ForeColor = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// <seealso cref="ForeColor"/>
/// </summary>
/// <value>
/// A <see cref="Font"/> object.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
]
override public Font Font
{
get
{
return base.Font;
}
set
{
base.Font = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(typeof(Color), ""),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(ChartHatchStyle.None),
NotifyParentPropertyAttribute(true),
Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
]
override public ChartHatchStyle BackHatchStyle
{
get
{
return base.BackHatchStyle;
}
set
{
base.BackHatchStyle = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(GradientStyle.None),
NotifyParentPropertyAttribute(true),
Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
]
override public GradientStyle BackGradientStyle
{
get
{
return base.BackGradientStyle;
}
set
{
base.BackGradientStyle = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(typeof(Color), ""),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color BackSecondaryColor
{
get
{
return base.BackSecondaryColor;
}
set
{
base.BackSecondaryColor = value;
}
}
#endregion
#region Other
/// <summary>
/// Gets or sets an annotation's type name.
/// </summary>
/// <remarks>
/// This property is used to get the name of each annotation type
/// (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("DescriptionAttributeAnnotationType"),
]
public override string AnnotationType
{
get
{
return "Polyline";
}
}
/// <summary>
/// Gets or sets an annotation selection points style.
/// </summary>
/// <value>
/// A <see cref="SelectionPointsStyle"/> value that represents the 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"),
]
override internal SelectionPointsStyle SelectionPointsStyle
{
get
{
return SelectionPointsStyle.Rectangle;
}
}
/// <summary>
/// Gets or sets a flag that determines whether an annotation should be placed using the free-draw mode.
/// </summary>
/// <value>
/// <b>True</b> if an annotation should be placed using free-draw mode,
/// <b>false</b> otherwise. Defaults to <b>false</b>.
/// </value>
/// <remarks>
/// Two different placement modes are supported when the Annotation.BeginPlacement
/// method is called. Set this property to <b>true</b> to switch from the default
/// mode to free-draw mode, which allows the caller to free-draw while moving the mouse cursor.
/// </remarks>
[
SRCategory("CategoryAttributeMisc"),
DefaultValue(false),
SRDescription("DescriptionAttributeFreeDrawPlacement"),
#if !Microsoft_CONTROL
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never),
#endif // !Microsoft_CONTROL
]
virtual public bool IsFreeDrawPlacement
{
get
{
return isFreeDrawPlacement;
}
set
{
isFreeDrawPlacement = value;
}
}
/// <summary>
/// Gets or sets the path points of a polyline at run-time.
/// </summary>
/// <value>
/// A <see cref="GraphicsPath"/> object with the polyline shape.
/// </value>
/// <remarks>
/// A polyline must use coordinates relative to an annotation object, where (0,0) is
/// the top-left coordinates and (100,100) is the bottom-right coordinates of the annotation.
/// <para>
/// This property is not accessible at design time (at design-time, use the
/// <see cref="GraphicsPathPoints"/> property instead).
/// </para>
/// </remarks>
[
SRCategory("CategoryAttributePosition"),
DefaultValue(null),
SRDescription("DescriptionAttributePath"),
Browsable(false),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
]
virtual public GraphicsPath GraphicsPath
{
get
{
return _graphicsPath;
}
set
{
_graphicsPath = value;
this.pathChanged = true;
}
}
/// <summary>
/// Gets or sets the path points of the polyline at design-time.
/// </summary>
/// <value>
/// An <see cref="AnnotationPathPointCollection"/> object with the polyline shape.
/// </value>
/// <remarks>
/// A polyline must use coordinates relative to an annotation object, where (0,0) is
/// the top-left coordinates and (100,100) is the bottom-right coordinates of the annotation.
/// <para>
/// This property is not accessible at runtime (at runtime, use the <see cref="GraphicsPath"/>
/// property instead).
/// </para>
/// </remarks>
[
SRCategory("CategoryAttributePosition"),
SRDescription("DescriptionAttributePathPoints"),
EditorBrowsableAttribute(EditorBrowsableState.Never),
Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.InnerProperty)
#endif
]
public AnnotationPathPointCollection GraphicsPathPoints
{
get
{
if(this.pathChanged ||
_graphicsPath.PointCount != _pathPoints.Count)
{
// Recreate collection from graphics path
_pathPoints.annotation = null;
_pathPoints.Clear();
if (_graphicsPath.PointCount > 0 )
{
PointF[] points = _graphicsPath.PathPoints;
byte[] types = _graphicsPath.PathTypes;
for (int index = 0; index < points.Length; index++)
{
_pathPoints.Add(new AnnotationPathPoint(points[index].X, points[index].Y, types[index]));
}
}
_pathPoints.annotation = this;
}
return _pathPoints;
}
}
#endregion
#endregion
#region Methods
#region Painting
/// <summary>
/// Paints an annotation object on the specified graphics.
/// </summary>
/// <param name="graphics">
/// A <see cref="ChartGraphics"/> object, used to paint an annotation object.
/// </param>
/// <param name="chart">
/// Reference to the <see cref="Chart"/> owner control.
/// </param>
override internal void Paint(Chart chart, ChartGraphics graphics)
{
// Check for empty path
if(_graphicsPath.PointCount == 0)
{
return;
}
// Get annotation position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
GetRelativePosition(out firstPoint, out size, out anchorPoint);
PointF secondPoint = new PointF(firstPoint.X + size.Width, firstPoint.Y + size.Height);
// Create selection rectangle
RectangleF selectionRect = new RectangleF(firstPoint, new SizeF(secondPoint.X - firstPoint.X, secondPoint.Y - firstPoint.Y));
// Get position
RectangleF rectanglePosition = new RectangleF(selectionRect.Location, selectionRect.Size);
if(rectanglePosition.Width < 0)
{
rectanglePosition.X = rectanglePosition.Right;
rectanglePosition.Width = -rectanglePosition.Width;
}
if(rectanglePosition.Height < 0)
{
rectanglePosition.Y = rectanglePosition.Bottom;
rectanglePosition.Height = -rectanglePosition.Height;
}
// Check if position is valid
if( float.IsNaN(rectanglePosition.X) ||
float.IsNaN(rectanglePosition.Y) ||
float.IsNaN(rectanglePosition.Right) ||
float.IsNaN(rectanglePosition.Bottom) )
{
return;
}
// Get annotation absolute position
RectangleF rectanglePositionAbs = graphics.GetAbsoluteRectangle(rectanglePosition);
// Calculate scaling
float groupScaleX = rectanglePositionAbs.Width / 100.0f;
float groupScaleY = rectanglePositionAbs.Height / 100.0f;
// Convert path to pixel coordinates
PointF[] pathPoints = _graphicsPath.PathPoints;
byte[] pathTypes = _graphicsPath.PathTypes;
for(int pointIndex = 0; pointIndex < pathPoints.Length; pointIndex++)
{
pathPoints[pointIndex].X = rectanglePositionAbs.X + pathPoints[pointIndex].X * groupScaleX;
pathPoints[pointIndex].Y = rectanglePositionAbs.Y + pathPoints[pointIndex].Y * groupScaleY;
}
using (GraphicsPath pathAbs = new GraphicsPath(pathPoints, pathTypes))
{
// Set line caps
bool capChanged = false;
LineCap oldStartCap = LineCap.Flat;
LineCap oldEndCap = LineCap.Flat;
if (!this.isPolygon)
{
if (this._startCap != LineAnchorCapStyle.None ||
this._endCap != LineAnchorCapStyle.None)
{
capChanged = true;
oldStartCap = graphics.Pen.StartCap;
oldEndCap = graphics.Pen.EndCap;
// Apply anchor cap settings
if (this._startCap == LineAnchorCapStyle.Arrow)
{
// Adjust arrow size for small line width
if (this.LineWidth < 4)
{
int adjustment = 3 - this.LineWidth;
graphics.Pen.StartCap = LineCap.Custom;
graphics.Pen.CustomStartCap = new AdjustableArrowCap(
this.LineWidth + adjustment,
this.LineWidth + adjustment,
true);
}
else
{
graphics.Pen.StartCap = LineCap.ArrowAnchor;
}
}
else if (this._startCap == LineAnchorCapStyle.Diamond)
{
graphics.Pen.StartCap = LineCap.DiamondAnchor;
}
else if (this._startCap == LineAnchorCapStyle.Round)
{
graphics.Pen.StartCap = LineCap.RoundAnchor;
}
else if (this._startCap == LineAnchorCapStyle.Square)
{
graphics.Pen.StartCap = LineCap.SquareAnchor;
}
if (this._endCap == LineAnchorCapStyle.Arrow)
{
// Adjust arrow size for small line width
if (this.LineWidth < 4)
{
int adjustment = 3 - this.LineWidth;
graphics.Pen.EndCap = LineCap.Custom;
graphics.Pen.CustomEndCap = new AdjustableArrowCap(
this.LineWidth + adjustment,
this.LineWidth + adjustment,
true);
}
else
{
graphics.Pen.EndCap = LineCap.ArrowAnchor;
}
}
else if (this._endCap == LineAnchorCapStyle.Diamond)
{
graphics.Pen.EndCap = LineCap.DiamondAnchor;
}
else if (this._endCap == LineAnchorCapStyle.Round)
{
graphics.Pen.EndCap = LineCap.RoundAnchor;
}
else if (this._endCap == LineAnchorCapStyle.Square)
{
graphics.Pen.EndCap = LineCap.SquareAnchor;
}
}
}
// Painting mode
if (this.Common.ProcessModePaint)
{
if (this.isPolygon)
{
// Draw polygon
pathAbs.CloseAllFigures();
graphics.DrawPathAbs(
pathAbs,
this.BackColor,
this.BackHatchStyle,
String.Empty,
ChartImageWrapMode.Scaled,
Color.Empty,
ChartImageAlignmentStyle.Center,
this.BackGradientStyle,
this.BackSecondaryColor,
this.LineColor,
this.LineWidth,
this.LineDashStyle,
PenAlignment.Center,
this.ShadowOffset,
this.ShadowColor);
}
else
{
// Draw polyline
graphics.DrawPathAbs(
pathAbs,
Color.Transparent,
ChartHatchStyle.None,
String.Empty,
ChartImageWrapMode.Scaled,
Color.Empty,
ChartImageAlignmentStyle.Center,
GradientStyle.None,
Color.Empty,
this.LineColor,
this.LineWidth,
this.LineDashStyle,
PenAlignment.Center,
this.ShadowOffset,
this.ShadowColor);
}
}
if (this.Common.ProcessModeRegions)
{
// Create line graphics path
GraphicsPath selectionPath = null;
GraphicsPath newPath = null;
if (this.isPolygon)
{
selectionPath = pathAbs;
}
else
{
newPath = new GraphicsPath();
selectionPath = newPath;
selectionPath.AddPath(pathAbs, false);
using (Pen pen = (Pen)graphics.Pen.Clone())
{
// Increase pen size by 2 pixels
pen.DashStyle = DashStyle.Solid;
pen.Width += 2;
try
{
selectionPath.Widen(pen);
}
catch (OutOfMemoryException)
{
// GraphicsPath.Widen incorrectly throws OutOfMemoryException
// catching here and reacting by not widening
}
catch (ArgumentException)
{
}
}
}
// Add hot region
this.Common.HotRegionsList.AddHotRegion(
graphics,
selectionPath,
false,
ReplaceKeywords(this.ToolTip),
#if Microsoft_CONTROL
String.Empty,
String.Empty,
String.Empty,
#else // Microsoft_CONTROL
ReplaceKeywords(this.Url),
ReplaceKeywords(this.MapAreaAttributes),
ReplaceKeywords(this.PostBackValue),
#endif // Microsoft_CONTROL
this,
ChartElementType.Annotation);
//Clean up
if (newPath != null)
newPath.Dispose();
}
// Restore line caps
if (capChanged)
{
graphics.Pen.StartCap = oldStartCap;
graphics.Pen.EndCap = oldEndCap;
}
// Paint selection handles
PaintSelectionHandles(graphics, rectanglePosition, pathAbs);
}
}
#endregion // Painting
#region Position Changing
#if Microsoft_CONTROL
/// <summary>
/// Changes annotation position, so it exactly matches the bounary of the
/// polyline path.
/// </summary>
private void ResizeToPathBoundary()
{
if(_graphicsPath.PointCount > 0)
{
// Get current annotation position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
GetRelativePosition(out firstPoint, out size, out anchorPoint);
// Get path boundary and convert it to relative coordinates
RectangleF pathBoundary = _graphicsPath.GetBounds();
pathBoundary.X *= size.Width / 100f;
pathBoundary.Y *= size.Height / 100f;
pathBoundary.X += firstPoint.X;
pathBoundary.Y += firstPoint.Y;
pathBoundary.Width *= size.Width / 100f;
pathBoundary.Height *= size.Height / 100f;
// Scale all current points
using( Matrix matrix = new Matrix() )
{
matrix.Scale(size.Width/pathBoundary.Width, size.Height/pathBoundary.Height);
matrix.Translate(-pathBoundary.X, -pathBoundary.Y);
_graphicsPath.Transform(matrix);
}
// Set new position for annotation
this.SetPositionRelative(pathBoundary, anchorPoint);
}
}
#endif //Microsoft_CONTROL
/// <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>
override internal void AdjustLocationSize(SizeF movingDistance, ResizingMode resizeMode, bool pixelCoord, bool userInput)
{
// Call base class when not resizing the path points
if(resizeMode != ResizingMode.MovingPathPoints)
{
base.AdjustLocationSize(movingDistance, resizeMode, pixelCoord, userInput);
return;
}
// Get annotation position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
GetRelativePosition(out firstPoint, out size, out anchorPoint);
// Remember path before moving operation
if(userInput == true && startMovePathRel == null)
{
#if Microsoft_CONTROL
this.startMovePathRel = (GraphicsPath)_graphicsPath.Clone();
this.startMovePositionRel = new RectangleF(firstPoint, size);
this.startMoveAnchorLocationRel = new PointF(anchorPoint.X, anchorPoint.Y);
#endif // Microsoft_CONTROL
}
// Convert moving distance to coordinates relative to the anotation
if(pixelCoord)
{
movingDistance = this.GetGraphics().GetRelativeSize(movingDistance);
}
movingDistance.Width /= startMovePositionRel.Width / 100.0f;
movingDistance.Height /= startMovePositionRel.Height / 100.0f;
// Get path points and adjust position of one of them
if(_graphicsPath.PointCount > 0)
{
GraphicsPath pathToMove = (userInput) ? startMovePathRel : _graphicsPath;
PointF[] pathPoints = pathToMove.PathPoints;
byte[] pathTypes = pathToMove.PathTypes;
for(int pointIndex = 0; pointIndex < pathPoints.Length; pointIndex++)
{
// Adjust position
if( currentPathPointIndex == pointIndex ||
currentPathPointIndex < 0 ||
currentPathPointIndex >= pathPoints.Length )
{
pathPoints[pointIndex].X -= movingDistance.Width;
pathPoints[pointIndex].Y -= movingDistance.Height;
}
}
#if Microsoft_CONTROL
// Adjust annotation position to the boundary of the path
if(userInput && this.AllowResizing)
{
// Get path bounds in relative coordinates
_defaultGraphicsPath.Dispose();
_defaultGraphicsPath = new GraphicsPath(pathPoints, pathTypes);
_graphicsPath = _defaultGraphicsPath;
RectangleF pathBounds = _graphicsPath.GetBounds();
pathBounds.X *= startMovePositionRel.Width / 100f;
pathBounds.Y *= startMovePositionRel.Height / 100f;
pathBounds.X += startMovePositionRel.X;
pathBounds.Y += startMovePositionRel.Y;
pathBounds.Width *= startMovePositionRel.Width / 100f;
pathBounds.Height *= startMovePositionRel.Height / 100f;
// Set new annotation position
this.SetPositionRelative(pathBounds, anchorPoint);
// Adjust path point position
for(int pointIndex = 0; pointIndex < pathPoints.Length; pointIndex++)
{
pathPoints[pointIndex].X = startMovePositionRel.X + pathPoints[pointIndex].X * (startMovePositionRel.Width / 100f);
pathPoints[pointIndex].Y = startMovePositionRel.Y + pathPoints[pointIndex].Y * (startMovePositionRel.Height / 100f);
pathPoints[pointIndex].X = (pathPoints[pointIndex].X - pathBounds.X) / (pathBounds.Width / 100f);
pathPoints[pointIndex].Y = (pathPoints[pointIndex].Y - pathBounds.Y) / (pathBounds.Height / 100f);
}
}
#endif // Microsoft_CONTROL
#if Microsoft_CONTROL
// Position changed
this.positionChanged = true;
#endif // Microsoft_CONTROL
// Recreate path with new points
_defaultGraphicsPath.Dispose();
_defaultGraphicsPath = new GraphicsPath(pathPoints, pathTypes);
_graphicsPath = _defaultGraphicsPath;
this.pathChanged = true;
// Invalidate annotation
this.Invalidate();
}
}
#endregion // Position Changing
#region Placement Methods
#if Microsoft_CONTROL
/// <summary>
/// Ends user placement of an annotation.
/// </summary>
/// <remarks>
/// Ends an annotation placement operation previously started by a
/// <see cref="Annotation.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>
override public void EndPlacement()
{
// Call base method
base.EndPlacement();
// Position was changed
if(this.Chart != null)
{
this.Chart.OnAnnotationPositionChanged(this);
}
// Reset last placement position
this.lastPlacementPosition = PointF.Empty;
// Resize annotation to the boundary of the polygon
ResizeToPathBoundary();
// Position changed
this.positionChanged = true;
}
/// <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 override void PlacementMouseDown(PointF point, MouseButtons buttons)
{
// Call base class method if path editing is not allowed
if(!this.AllowPathEditing)
{
base.PlacementMouseDown(point, buttons);
return;
}
if(buttons == MouseButtons.Right)
{
// Stop pacement
this.EndPlacement();
}
if(buttons == MouseButtons.Left &&
IsValidPlacementPosition(point.X, point.Y))
{
// Convert coordinate to relative
PointF newPoint = this.GetGraphics().GetRelativePoint(point);
if(this.lastPlacementPosition.IsEmpty)
{
// Set annotation coordinates to full chart
this.X = 0f;
this.Y = 0f;
this.Width = 100f;
this.Height = 100f;
// Remeber position where mouse was clicked
this.lastPlacementPosition = newPoint;
}
else
{
if(this.lastPlacementPosition.X == newPoint.X &&
this.lastPlacementPosition.Y == newPoint.Y)
{
// Stop pacement
this.EndPlacement();
}
}
// Add a line from prev. position to current into the path
using( GraphicsPath tmpPath = new GraphicsPath() )
{
PointF firstPoint = this.lastPlacementPosition;
if(_graphicsPath.PointCount > 1)
{
firstPoint = _graphicsPath.GetLastPoint();
}
tmpPath.AddLine(firstPoint, newPoint);
_graphicsPath.AddPath(tmpPath, true);
}
// Remember last position
this.lastPlacementPosition = newPoint;
// 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 override bool PlacementMouseUp(PointF point, MouseButtons buttons)
{
// Call base class method if path editing is not allowed
if(!this.AllowPathEditing)
{
return base.PlacementMouseUp(point, buttons);
}
if(buttons == MouseButtons.Left &&
isFreeDrawPlacement)
{
// Stop pacement
this.EndPlacement();
}
return false;
}
/// <summary>
/// Handles mouse move event during annotation placement.
/// </summary>
/// <param name="point">Mouse cursor position in pixels.</param>
internal override void PlacementMouseMove(PointF point)
{
// Call base class method if path editing is not allowed
if(!this.AllowPathEditing)
{
base.PlacementMouseMove(point);
return;
}
// Check if annotation was moved
if( this.GetGraphics() != null &&
_graphicsPath.PointCount > 0 &&
!this.lastPlacementPosition.IsEmpty)
{
// Convert coordinate to relative
PointF newPoint = this.GetGraphics().GetRelativePoint(point);
if(this.isFreeDrawPlacement)
{
// Add new point
using( GraphicsPath tmpPath = new GraphicsPath() )
{
PointF firstPoint = this.lastPlacementPosition;
if(_graphicsPath.PointCount > 1)
{
firstPoint = _graphicsPath.GetLastPoint();
}
tmpPath.AddLine(firstPoint, newPoint);
_graphicsPath.AddPath(tmpPath, true);
}
}
else
{
// Adjust last point position
PointF[] pathPoints = _graphicsPath.PathPoints;
byte[] pathTypes = _graphicsPath.PathTypes;
pathPoints[pathPoints.Length - 1] = newPoint;
_defaultGraphicsPath.Dispose();
_defaultGraphicsPath = new GraphicsPath(pathPoints, pathTypes);
_graphicsPath = _defaultGraphicsPath;
}
// Position changed
this.positionChanged = true;
// Invalidate and update the chart
if(this.Chart != null)
{
Invalidate();
this.Chart.UpdateAnnotations();
}
}
}
#endif // Microsoft_CONTROL
#endregion // Placement Methods
#endregion
#region IDisposable override
/// <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)
{
if (_defaultGraphicsPath != null)
{
_defaultGraphicsPath.Dispose();
_defaultGraphicsPath = null;
}
if (_pathPoints != null)
{
_pathPoints.Dispose();
_pathPoints = null;
}
}
base.Dispose(disposing);
}
#endregion
}
/// <summary>
/// <b>PolygonAnnotation</b> is a class that represents a polygon annotation.
/// </summary>
[
SRDescription("DescriptionAttributePolygonAnnotation_PolygonAnnotation"),
]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class PolygonAnnotation : PolylineAnnotation
{
#region Construction and Initialization
/// <summary>
/// Default public constructor.
/// </summary>
public PolygonAnnotation()
: base()
{
this.isPolygon = true;
}
#endregion
#region Properties
#region Non Applicable Annotation Appearance Attributes (set as Non-Browsable)
/// <summary>
/// Not applicable to this annotation type.
/// <seealso cref="EndCap"/>
/// </summary>
/// <value>
/// A <see cref="LineAnchorCapStyle"/> value.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(LineAnchorCapStyle.None),
]
override public LineAnchorCapStyle StartCap
{
get
{
return base.StartCap;
}
set
{
base.StartCap = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// <seealso cref="StartCap"/>
/// </summary>
/// <value>
/// A <see cref="LineAnchorCapStyle"/> value.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(LineAnchorCapStyle.None),
]
override public LineAnchorCapStyle EndCap
{
get
{
return base.EndCap;
}
set
{
base.EndCap = value;
}
}
#endregion
#region Applicable Annotation Appearance Attributes (set as Browsable)
/// <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"),
Browsable(true),
DefaultValue(typeof(Color), ""),
SRDescription("DescriptionAttributeBackColor"),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
/// <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"),
Browsable(true),
DefaultValue(ChartHatchStyle.None),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackHatchStyle"),
Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
]
override public ChartHatchStyle BackHatchStyle
{
get
{
return base.BackHatchStyle;
}
set
{
base.BackHatchStyle = value;
}
}
/// <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"),
Browsable(true),
DefaultValue(GradientStyle.None),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackGradientStyle"),
Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
]
override public GradientStyle BackGradientStyle
{
get
{
return base.BackGradientStyle;
}
set
{
base.BackGradientStyle = value;
}
}
/// <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"),
Browsable(true),
DefaultValue(typeof(Color), ""),
NotifyParentPropertyAttribute(true),
SRDescription("DescriptionAttributeBackSecondaryColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color BackSecondaryColor
{
get
{
return base.BackSecondaryColor;
}
set
{
base.BackSecondaryColor = value;
}
}
#endregion
#region Other
/// <summary>
/// Gets or sets an annotation's type name.
/// </summary>
/// <remarks>
/// This property is used to get the name of each annotation type
/// (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("DescriptionAttributeAnnotationType"),
]
public override string AnnotationType
{
get
{
return "Polygon";
}
}
/// <summary>
/// Gets or sets an annotation's selection points style.
/// </summary>
/// <value>
/// A <see cref="SelectionPointsStyle"/> value that represents an annotation's
/// 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"),
]
override internal SelectionPointsStyle SelectionPointsStyle
{
get
{
return SelectionPointsStyle.Rectangle;
}
}
#endregion
#endregion
}
/// <summary><b>AnnotationPathPointCollection</b> is a collection of polyline
/// annotation path points, and is only available via the <b>GraphicsPathPoints</b>
/// property at design-time.
/// <seealso cref="PolylineAnnotation.GraphicsPathPoints"/></summary>
/// <remarks>
/// This collection is used at design-time only, and uses serialization to expose the
/// shape of the polyline and polygon via their GraphicsPathPoints collection property.
/// At run-time, use Path property to set the path of a polyline or polygon
/// </remarks>
[
SRDescription("DescriptionAttributeAnnotationPathPointCollection_AnnotationPathPointCollection"),
]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class AnnotationPathPointCollection : ChartElementCollection<AnnotationPathPoint>
{
#region Fields
internal PolylineAnnotation annotation = null;
private GraphicsPath _graphicsPath = null;
#endregion // Fields
#region Constructors
/// <summary>
/// Default public constructor.
/// </summary>
public AnnotationPathPointCollection(PolylineAnnotation annotation)
: base(annotation)
{
this.annotation = annotation;
}
#endregion // Constructors
#region Methods
/// <summary>
/// Forces the invalidation of the chart element
/// </summary>
public override void Invalidate()
{
if (this.annotation != null)
{
//Dispose previously instantiated graphics path
if (this._graphicsPath != null)
{
this._graphicsPath.Dispose();
this._graphicsPath = null;
}
// Recreate polyline annotation path
if (this.Count > 0)
{
PointF[] points = new PointF[this.Count];
byte[] types = new byte[this.Count];
for (int index = 0; index < this.Count; index++)
{
points[index] = new PointF(this[index].X, this[index].Y);
types[index] = this[index].PointType;
}
this._graphicsPath = new GraphicsPath(points, types);
}
else
{
this._graphicsPath = new GraphicsPath();
}
// Invalidate annotation
this.annotation.GraphicsPath = this._graphicsPath;
this.annotation.Invalidate();
}
base.Invalidate();
}
#endregion // Methods
#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 up managed resources
if (this._graphicsPath != null)
{
this._graphicsPath.Dispose();
this._graphicsPath = null;
}
}
base.Dispose(disposing);
}
#endregion
}
/// <summary>
/// The <b>AnnotationPathPoint</b> class represents a path point of a polyline or polygon,
/// and is stored in their <b>GraphicsPathPoints</b> property, which is only available at design-time.
/// </summary>
/// <remarks>
/// At run-time, use <b>Path</b> property to set the path of a polyline or polygon.
/// </remarks>
[
SRDescription("DescriptionAttributeAnnotationPathPoint_AnnotationPathPoint"),
]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class AnnotationPathPoint: ChartElement
{
#region Fields
// Point X value
private float _x = 0f;
// Point Y value
private float _y = 0f;
// Point type
private byte _pointType = 1;
#endregion // Fields
#region Constructors
/// <summary>
/// Default public constructor.
/// </summary>
public AnnotationPathPoint()
{
}
/// <summary>
/// Constructor that takes X and Y parameters.
/// </summary>
/// <param name="x">Point's X value.</param>
/// <param name="y">Point's Y value.</param>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
Justification="X and Y are cartesian coordinates and well understood")]
public AnnotationPathPoint(float x, float y)
{
this._x = x;
this._y = y;
}
/// <summary>
/// Constructor that takes X, Y and point type parameters.
/// </summary>
/// <param name="x">Point's X value.</param>
/// <param name="y">Point's Y value.</param>
/// <param name="type">Point type.</param>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
Justification = "X and Y are cartesian coordinates and well understood")]
public AnnotationPathPoint(float x, float y, byte type)
{
this._x = x;
this._y = y;
this._pointType = type;
}
#endregion // Constructors
#region Properties
/// <summary>
/// Gets or sets an annotation path point's X coordinate.
/// </summary>
/// <value>
/// A float value for the point's X coordinate.
/// </value>
[
SRCategory("CategoryAttributePosition"),
DefaultValue(0f),
Browsable(true),
SRDescription("DescriptionAttributeAnnotationPathPoint_X"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "X")]
public float X
{
get
{
return _x;
}
set
{
_x = value;
}
}
/// <summary>
/// Gets or sets an annotation path point's Y coordinate.
/// </summary>
/// <value>
/// A float value for the point's Y coordinate.
/// </value>
[
SRCategory("CategoryAttributePosition"),
DefaultValue(0f),
Browsable(true),
SRDescription("DescriptionAttributeAnnotationPathPoint_Y"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Y")]
public float Y
{
get
{
return _y;
}
set
{
_y = value;
}
}
/// <summary>
/// Gets or sets an annotation path point's type.
/// </summary>
/// <value>
/// A byte value.
/// </value>
/// <remarks>
/// See the <see cref="PathPointType"/> enumeration for more details.
/// </remarks>
[
SRCategory("CategoryAttributePosition"),
DefaultValue(typeof(byte), "1"),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
SRDescription("DescriptionAttributeAnnotationPathPoint_Name"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
]
public byte PointType
{
get
{
return _pointType;
}
set
{
_pointType = value;
}
}
/// <summary>
/// Gets or sets an annotation path point's name.
/// </summary>
/// <para>
/// This property is for internal use and is hidden at design and run time.
/// </para>
[
SRCategory("CategoryAttributeMisc"),
DefaultValue("PathPoint"),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
SRDescription("DescriptionAttributeAnnotationPathPoint_Name"),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
]
public string Name
{
get
{
return "PathPoint";
}
}
#endregion // Properties
}
}
|