//------------------------------------------------------------- // // Copyright © Microsoft Corporation. All Rights Reserved. // //------------------------------------------------------------- // @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 { /// /// PolylineAnnotation is a class that represents a polyline annotation. /// [ 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 /// /// Default public constructor. /// public PolylineAnnotation() : base() { _pathPoints = new AnnotationPathPointCollection(this); _graphicsPath = _defaultGraphicsPath; } #endregion #region Properties #region Polyline Visual Attributes /// /// Gets or sets a cap style used at the start of an annotation line. /// /// /// /// A value used for a cap style used at the start of an annotation line. /// [ SRCategory("CategoryAttributeAppearance"), DefaultValue(LineAnchorCapStyle.None), SRDescription("DescriptionAttributeStartCap3"), ] virtual public LineAnchorCapStyle StartCap { get { return _startCap; } set { _startCap = value; Invalidate(); } } /// /// Gets or sets a cap style used at the end of an annotation line. /// /// /// /// A value used for a cap style used at the end of an annotation line. /// [ 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) /// /// Not applicable to this annotation type. /// /// /// A value. /// [ SRCategory("CategoryAttributeAppearance"), Browsable(false), DefaultValue(typeof(ContentAlignment), "MiddleCenter"), ] override public ContentAlignment Alignment { get { return base.Alignment; } set { base.Alignment = value; } } /// /// Gets or sets an annotation's text style. /// /// /// /// /// A value used to draw an annotation's text. /// [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] public override TextStyle TextStyle { get { return base.TextStyle; } set { base.TextStyle = value; } } /// /// Not applicable to this annotation type. /// /// /// /// A 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; } } /// /// Not applicable to this annotation type. /// /// /// /// A object. /// [ SRCategory("CategoryAttributeAppearance"), Browsable(false), DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"), ] override public Font Font { get { return base.Font; } set { base.Font = value; } } /// /// Not applicable to this annotation type. /// [ 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; } } /// /// Not applicable to this annotation type. /// [ 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; } } /// /// Not applicable to this annotation type. /// [ 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; } } /// /// Not applicable to this annotation type. /// [ 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 /// /// Gets or sets an annotation's type name. /// /// /// This property is used to get the name of each annotation type /// (e.g. Line, Rectangle, Ellipse). /// /// This property is for internal use and is hidden at design and run time. /// /// [ SRCategory("CategoryAttributeMisc"), Bindable(true), Browsable(false), EditorBrowsableAttribute(EditorBrowsableState.Never), DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden), SerializationVisibilityAttribute(SerializationVisibility.Hidden), SRDescription("DescriptionAttributeAnnotationType"), ] public override string AnnotationType { get { return "Polyline"; } } /// /// Gets or sets an annotation selection points style. /// /// /// A value that represents the annotation /// selection style. /// /// /// This property is for internal use and is hidden at design and run time. /// [ SRCategory("CategoryAttributeAppearance"), DefaultValue(SelectionPointsStyle.Rectangle), ParenthesizePropertyNameAttribute(true), Browsable(false), EditorBrowsableAttribute(EditorBrowsableState.Never), DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden), SerializationVisibilityAttribute(SerializationVisibility.Hidden), SRDescription("DescriptionAttributeSelectionPointsStyle"), ] override internal SelectionPointsStyle SelectionPointsStyle { get { return SelectionPointsStyle.Rectangle; } } /// /// Gets or sets a flag that determines whether an annotation should be placed using the free-draw mode. /// /// /// True if an annotation should be placed using free-draw mode, /// false otherwise. Defaults to false. /// /// /// Two different placement modes are supported when the Annotation.BeginPlacement /// method is called. Set this property to true to switch from the default /// mode to free-draw mode, which allows the caller to free-draw while moving the mouse cursor. /// [ 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; } } /// /// Gets or sets the path points of a polyline at run-time. /// /// /// A object with the polyline shape. /// /// /// 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. /// /// This property is not accessible at design time (at design-time, use the /// property instead). /// /// [ 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; } } /// /// Gets or sets the path points of the polyline at design-time. /// /// /// An object with the polyline shape. /// /// /// 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. /// /// This property is not accessible at runtime (at runtime, use the /// property instead). /// /// [ 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 /// /// Paints an annotation object on the specified graphics. /// /// /// A object, used to paint an annotation object. /// /// /// Reference to the owner control. /// 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 /// /// Changes annotation position, so it exactly matches the bounary of the /// polyline path. /// 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 /// /// Adjust annotation location and\or size as a result of user action. /// /// Distance to resize/move the annotation. /// Resizing mode. /// Distance is in pixels, otherwise relative. /// Indicates if position changing was a result of the user input. 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 /// /// Ends user placement of an annotation. /// /// /// Ends an annotation placement operation previously started by a /// method call. /// /// Calling this method is not required, since placement will automatically /// end when an end user enters all required points. However, it is useful when an annotation /// placement operation needs to be aborted for some reason. /// /// 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; } /// /// Handles mouse down event during annotation placement. /// /// Mouse cursor position in pixels. /// Mouse button down. 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(); } } } /// /// Handles mouse up event during annotation placement. /// /// Mouse cursor position in pixels. /// Mouse button Up. /// Return true when placing finished. 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; } /// /// Handles mouse move event during annotation placement. /// /// Mouse cursor position in pixels. 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 /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) { if (disposing) { if (_defaultGraphicsPath != null) { _defaultGraphicsPath.Dispose(); _defaultGraphicsPath = null; } if (_pathPoints != null) { _pathPoints.Dispose(); _pathPoints = null; } } base.Dispose(disposing); } #endregion } /// /// PolygonAnnotation is a class that represents a polygon annotation. /// [ 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 /// /// Default public constructor. /// public PolygonAnnotation() : base() { this.isPolygon = true; } #endregion #region Properties #region Non Applicable Annotation Appearance Attributes (set as Non-Browsable) /// /// Not applicable to this annotation type. /// /// /// /// A value. /// [ SRCategory("CategoryAttributeAppearance"), Browsable(false), DefaultValue(LineAnchorCapStyle.None), ] override public LineAnchorCapStyle StartCap { get { return base.StartCap; } set { base.StartCap = value; } } /// /// Not applicable to this annotation type. /// /// /// /// A 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) /// /// Gets or sets the background color of an annotation. /// /// /// /// /// /// A value used for the background of an annotation. /// [ 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; } } /// /// Gets or sets the background hatch style of an annotation. /// /// /// /// /// /// A value used for the background of an annotation. /// /// /// Two colors are used to draw the hatching, and . /// [ SRCategory("CategoryAttributeAppearance"), 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; } } /// /// Gets or sets the background gradient style of an annotation. /// /// /// /// /// /// A value used for the background of an annotation. /// /// /// Two colors are used to draw the gradient, and . /// [ SRCategory("CategoryAttributeAppearance"), 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; } } /// /// Gets or sets the secondary background color of an annotation. /// /// /// /// /// /// A value used for the secondary color of an annotation background with /// hatching or gradient fill. /// /// /// This color is used with when or /// are used. /// [ SRCategory("CategoryAttributeAppearance"), 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 /// /// Gets or sets an annotation's type name. /// /// /// This property is used to get the name of each annotation type /// (e.g. Line, Rectangle, Ellipse). /// /// This property is for internal use and is hidden at design and run time. /// /// [ SRCategory("CategoryAttributeMisc"), Bindable(true), Browsable(false), EditorBrowsableAttribute(EditorBrowsableState.Never), DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden), SerializationVisibilityAttribute(SerializationVisibility.Hidden), SRDescription("DescriptionAttributeAnnotationType"), ] public override string AnnotationType { get { return "Polygon"; } } /// /// Gets or sets an annotation's selection points style. /// /// /// A value that represents an annotation's /// selection style. /// /// /// This property is for internal use and is hidden at design and run time. /// [ SRCategory("CategoryAttributeAppearance"), DefaultValue(SelectionPointsStyle.Rectangle), ParenthesizePropertyNameAttribute(true), Browsable(false), EditorBrowsableAttribute(EditorBrowsableState.Never), DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden), SerializationVisibilityAttribute(SerializationVisibility.Hidden), SRDescription("DescriptionAttributeSelectionPointsStyle"), ] override internal SelectionPointsStyle SelectionPointsStyle { get { return SelectionPointsStyle.Rectangle; } } #endregion #endregion } /// AnnotationPathPointCollection is a collection of polyline /// annotation path points, and is only available via the GraphicsPathPoints /// property at design-time. /// /// /// 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 /// [ 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 { #region Fields internal PolylineAnnotation annotation = null; private GraphicsPath _graphicsPath = null; #endregion // Fields #region Constructors /// /// Default public constructor. /// public AnnotationPathPointCollection(PolylineAnnotation annotation) : base(annotation) { this.annotation = annotation; } #endregion // Constructors #region Methods /// /// Forces the invalidation of the chart element /// 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 /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) { if (disposing) { // Free up managed resources if (this._graphicsPath != null) { this._graphicsPath.Dispose(); this._graphicsPath = null; } } base.Dispose(disposing); } #endregion } /// /// The AnnotationPathPoint class represents a path point of a polyline or polygon, /// and is stored in their GraphicsPathPoints property, which is only available at design-time. /// /// /// At run-time, use Path property to set the path of a polyline or polygon. /// [ 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 /// /// Default public constructor. /// public AnnotationPathPoint() { } /// /// Constructor that takes X and Y parameters. /// /// Point's X value. /// Point's Y value. [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; } /// /// Constructor that takes X, Y and point type parameters. /// /// Point's X value. /// Point's Y value. /// Point type. [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 /// /// Gets or sets an annotation path point's X coordinate. /// /// /// A float value for the point's X coordinate. /// [ 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; } } /// /// Gets or sets an annotation path point's Y coordinate. /// /// /// A float value for the point's Y coordinate. /// [ 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; } } /// /// Gets or sets an annotation path point's type. /// /// /// A byte value. /// /// /// See the enumeration for more details. /// [ 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; } } /// /// Gets or sets an annotation path point's name. /// /// /// This property is for internal use and is hidden at design and run time. /// [ 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 } }