536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
472 lines
15 KiB
C#
472 lines
15 KiB
C#
//-------------------------------------------------------------
|
||
// <copyright company=’Microsoft Corporation’>
|
||
// Copyright © Microsoft Corporation. All Rights Reserved.
|
||
// </copyright>
|
||
//-------------------------------------------------------------
|
||
// @owner=alexgor, deliant
|
||
//=================================================================
|
||
// File: ArrowAnnotation.cs
|
||
//
|
||
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
|
||
//
|
||
// Classes: ArrowAnnotation
|
||
//
|
||
// Purpose: Arrow 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;
|
||
#if Microsoft_CONTROL
|
||
using System.Windows.Forms.DataVisualization.Charting;
|
||
using System.Windows.Forms.DataVisualization.Charting.Data;
|
||
using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
|
||
using System.Windows.Forms.DataVisualization.Charting.Utilities;
|
||
using System.Windows.Forms.DataVisualization.Charting.Borders3D;
|
||
|
||
#else
|
||
using System.Web;
|
||
using System.Web.UI;
|
||
using System.Web.UI.DataVisualization.Charting;
|
||
using System.Web.UI.DataVisualization.Charting.Data;
|
||
using System.Web.UI.DataVisualization.Charting.Utilities;
|
||
using System.Web.UI.DataVisualization.Charting.Borders3D;
|
||
#endif
|
||
|
||
|
||
#endregion
|
||
|
||
#if Microsoft_CONTROL
|
||
namespace System.Windows.Forms.DataVisualization.Charting
|
||
|
||
#else
|
||
namespace System.Web.UI.DataVisualization.Charting
|
||
|
||
#endif
|
||
{
|
||
#region Enumeration
|
||
|
||
/// <summary>
|
||
/// Arrow annotation styles.
|
||
/// <seealso cref="ArrowAnnotation.ArrowStyle"/>
|
||
/// </summary>
|
||
[
|
||
SRDescription("DescriptionAttributeArrowStyle_ArrowStyle")
|
||
]
|
||
public enum ArrowStyle
|
||
{
|
||
/// <summary>
|
||
/// Simple arrow.
|
||
/// </summary>
|
||
Simple,
|
||
|
||
/// <summary>
|
||
/// Arrow pointing in two directions.
|
||
/// </summary>
|
||
DoubleArrow,
|
||
|
||
/// <summary>
|
||
/// Arrow with a tail.
|
||
/// </summary>
|
||
Tailed,
|
||
}
|
||
|
||
#endregion // Enumeration
|
||
|
||
/// <summary>
|
||
/// <b>ArrowAnnotation</b> is a class class that represents an arrow annotation.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// Arrow annotations can be used to connect to points on the chart or highlight a
|
||
/// single chart area. Different arrow styles and sizes may be applied.
|
||
/// </remarks>
|
||
[
|
||
SRDescription("DescriptionAttributeArrowAnnotation_ArrowAnnotation"),
|
||
]
|
||
#if ASPPERM_35
|
||
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
||
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
||
#endif
|
||
public class ArrowAnnotation : Annotation
|
||
{
|
||
#region Fields
|
||
|
||
// Annotation arrow style
|
||
private ArrowStyle _arrowStyle = ArrowStyle.Simple;
|
||
|
||
// Annotation arrow size
|
||
private int _arrowSize = 5;
|
||
|
||
#endregion
|
||
|
||
#region Construction and Initialization
|
||
|
||
/// <summary>
|
||
/// Default public constructor.
|
||
/// </summary>
|
||
public ArrowAnnotation()
|
||
: base()
|
||
{
|
||
base.AnchorAlignment = ContentAlignment.TopLeft;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Properties
|
||
|
||
#region Arrow properties
|
||
|
||
/// <summary>
|
||
/// Gets or sets the arrow style of an arrow annotation.
|
||
/// <seealso cref="ArrowSize"/>
|
||
/// </summary>
|
||
/// <value>
|
||
/// <see cref="ArrowStyle"/> of an annotation.
|
||
/// </value>
|
||
[
|
||
SRCategory("CategoryAttributeAppearance"),
|
||
Bindable(true),
|
||
DefaultValue(ArrowStyle.Simple),
|
||
SRDescription("DescriptionAttributeArrowAnnotation_ArrowStyle"),
|
||
ParenthesizePropertyNameAttribute(true),
|
||
]
|
||
virtual public ArrowStyle ArrowStyle
|
||
{
|
||
get
|
||
{
|
||
return _arrowStyle;
|
||
}
|
||
set
|
||
{
|
||
_arrowStyle = value;
|
||
Invalidate();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets or sets the arrow size in pixels of an arrow annotation.
|
||
/// <seealso cref="ArrowStyle"/>
|
||
/// </summary>
|
||
/// <value>
|
||
/// Integer value that represents arrow size (thickness) in pixels.
|
||
/// </value>
|
||
[
|
||
SRCategory("CategoryAttributeAppearance"),
|
||
Bindable(true),
|
||
DefaultValue(5),
|
||
SRDescription("DescriptionAttributeArrowAnnotation_ArrowSize"),
|
||
ParenthesizePropertyNameAttribute(true),
|
||
]
|
||
virtual public int ArrowSize
|
||
{
|
||
get
|
||
{
|
||
return _arrowSize;
|
||
}
|
||
set
|
||
{
|
||
if(value <= 0)
|
||
{
|
||
throw(new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationArrowSizeIsZero));
|
||
}
|
||
if(value > 100)
|
||
{
|
||
throw (new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationArrowSizeMustBeLessThen100));
|
||
}
|
||
_arrowSize = value;
|
||
Invalidate();
|
||
}
|
||
}
|
||
|
||
|
||
#endregion // Arrow properties
|
||
|
||
#region Anchor
|
||
|
||
/// <summary>
|
||
/// Gets or sets an annotation position's alignment to the anchor point.
|
||
/// <seealso cref="Annotation.AnchorX"/>
|
||
/// <seealso cref="Annotation.AnchorY"/>
|
||
/// <seealso cref="Annotation.AnchorDataPoint"/>
|
||
/// <seealso cref="Annotation.AnchorOffsetX"/>
|
||
/// <seealso cref="Annotation.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="Annotation.AnchorDataPoint"/>, or the <see cref="Annotation.AnchorX"/>
|
||
/// and <see cref="Annotation.AnchorY"/> properties. Its <see cref="Annotation.X"/> and <see cref="Annotation.Y"/>
|
||
/// properties must be set to <b>Double.NaN</b>.
|
||
/// </remarks>
|
||
[
|
||
SRCategory("CategoryAttributeAnchor"),
|
||
Browsable(false),
|
||
EditorBrowsableAttribute(EditorBrowsableState.Never),
|
||
DefaultValue(typeof(ContentAlignment), "TopLeft"),
|
||
SRDescription("DescriptionAttributeAnchorAlignment"),
|
||
]
|
||
override public ContentAlignment AnchorAlignment
|
||
{
|
||
get
|
||
{
|
||
return base.AnchorAlignment;
|
||
}
|
||
set
|
||
{
|
||
base.AnchorAlignment = value;
|
||
}
|
||
}
|
||
|
||
#endregion // Anchoring
|
||
|
||
#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 "Arrow";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets or sets 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"),
|
||
]
|
||
override internal SelectionPointsStyle SelectionPointsStyle
|
||
{
|
||
get
|
||
{
|
||
return SelectionPointsStyle.TwoPoints;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#endregion
|
||
|
||
#region Methods
|
||
|
||
/// <summary>
|
||
/// Paints annotation object on specified graphics.
|
||
/// </summary>
|
||
/// <param name="graphics">
|
||
/// A <see cref="ChartGraphics"/> used to paint annotation object.
|
||
/// </param>
|
||
/// <param name="chart">
|
||
/// Reference to the <see cref="Chart"/> control.
|
||
/// </param>
|
||
override internal void Paint(Chart chart, ChartGraphics graphics)
|
||
{
|
||
// 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));
|
||
|
||
// Check if text position is valid
|
||
if( float.IsNaN(firstPoint.X) ||
|
||
float.IsNaN(firstPoint.Y) ||
|
||
float.IsNaN(secondPoint.X) ||
|
||
float.IsNaN(secondPoint.Y) )
|
||
{
|
||
return;
|
||
}
|
||
|
||
// Get arrow shape path
|
||
using (GraphicsPath arrowPathAbs = GetArrowPath(graphics, selectionRect))
|
||
{
|
||
|
||
// Draw arrow shape
|
||
if (this.Common.ProcessModePaint)
|
||
{
|
||
graphics.DrawPathAbs(
|
||
arrowPathAbs,
|
||
(this.BackColor.IsEmpty) ? Color.White : 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);
|
||
}
|
||
|
||
// Process hot region
|
||
if (this.Common.ProcessModeRegions)
|
||
{
|
||
// Use callout defined hot region
|
||
this.Common.HotRegionsList.AddHotRegion(
|
||
graphics,
|
||
arrowPathAbs,
|
||
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);
|
||
}
|
||
|
||
// Paint selection handles
|
||
PaintSelectionHandles(graphics, selectionRect, null);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get arrow path for the specified annotation position
|
||
/// </summary>
|
||
/// <param name="graphics"></param>
|
||
/// <param name="position"></param>
|
||
/// <returns></returns>
|
||
private GraphicsPath GetArrowPath(
|
||
ChartGraphics graphics,
|
||
RectangleF position)
|
||
{
|
||
// Get absolute position
|
||
RectangleF positionAbs = graphics.GetAbsoluteRectangle(position);
|
||
PointF firstPoint = positionAbs.Location;
|
||
PointF secondPoint = new PointF(positionAbs.Right, positionAbs.Bottom);
|
||
|
||
// Calculate arrow length
|
||
float deltaX = secondPoint.X - firstPoint.X;
|
||
float deltaY = secondPoint.Y - firstPoint.Y;
|
||
float arrowLength = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
|
||
|
||
// Create unrotated graphics path for the arrow started at the annotation location
|
||
// and going to the right for the length of the rotated arrow.
|
||
GraphicsPath path = new GraphicsPath();
|
||
|
||
PointF[] points = null;
|
||
float pointerRatio = 2.1f;
|
||
if(this.ArrowStyle == ArrowStyle.Simple)
|
||
{
|
||
points = new PointF[] {
|
||
firstPoint,
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize*pointerRatio),
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize),
|
||
new PointF(firstPoint.X + arrowLength, firstPoint.Y - this.ArrowSize),
|
||
new PointF(firstPoint.X + arrowLength, firstPoint.Y + this.ArrowSize),
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize),
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize*pointerRatio) };
|
||
}
|
||
else if(this.ArrowStyle == ArrowStyle.DoubleArrow)
|
||
{
|
||
points = new PointF[] {
|
||
firstPoint,
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize*pointerRatio),
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize),
|
||
new PointF(firstPoint.X + arrowLength - this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize),
|
||
new PointF(firstPoint.X + arrowLength - this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize*pointerRatio),
|
||
new PointF(firstPoint.X + arrowLength, firstPoint.Y),
|
||
new PointF(firstPoint.X + arrowLength - this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize*pointerRatio),
|
||
new PointF(firstPoint.X + arrowLength - this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize),
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize),
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize*pointerRatio) };
|
||
}
|
||
else if(this.ArrowStyle == ArrowStyle.Tailed)
|
||
{
|
||
float tailRatio = 2.1f;
|
||
points = new PointF[] {
|
||
firstPoint,
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize*pointerRatio),
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize),
|
||
new PointF(firstPoint.X + arrowLength, firstPoint.Y - this.ArrowSize*tailRatio),
|
||
new PointF(firstPoint.X + arrowLength - this.ArrowSize*tailRatio, firstPoint.Y),
|
||
new PointF(firstPoint.X + arrowLength, firstPoint.Y + this.ArrowSize*tailRatio),
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize),
|
||
new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize*pointerRatio) };
|
||
}
|
||
else
|
||
{
|
||
throw (new InvalidOperationException(SR.ExceptionAnnotationArrowStyleUnknown));
|
||
}
|
||
|
||
path.AddLines(points);
|
||
path.CloseAllFigures();
|
||
|
||
// Calculate arrow angle
|
||
float angle = (float)(Math.Atan(deltaY / deltaX) * 180f / Math.PI);
|
||
if(deltaX < 0)
|
||
{
|
||
angle += 180f;
|
||
}
|
||
|
||
// Rotate arrow path around the first point
|
||
using( Matrix matrix = new Matrix() )
|
||
{
|
||
matrix.RotateAt(angle, firstPoint);
|
||
path.Transform(matrix);
|
||
}
|
||
|
||
return path;
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|