123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- //
- // Purpose: Arrow annotation classes.
- //
- 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 FastReport.DataVisualization.Charting;
- using FastReport.DataVisualization.Charting.Data;
- using FastReport.DataVisualization.Charting.ChartTypes;
- using FastReport.DataVisualization.Charting.Utilities;
- using FastReport.DataVisualization.Charting.Borders3D;
- namespace FastReport.DataVisualization.Charting
- {
- #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"),
- ]
- 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),
- String.Empty,
- String.Empty,
- String.Empty,
- 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
- }
- }
|