private void PaintElement (ChartGraphics g, object element, ElementPosition position) { ChartPaintEventArgs e = new ChartPaintEventArgs (this, element, g, position); OnPrePaint (e); OnPostPaint (e); }
internal ChartPaintEventArgs (Chart chart, object chartElement, ChartGraphics chartGraphics, ElementPosition position) { Chart = chart; ChartElement = chartElement; ChartGraphics = chartGraphics; Position = position; }
/// <summary> /// Get the absolute location of dp /// </summary> /// <param name="cg">for finding the absolute location</param> /// <param name="dp"></param> /// <returns></returns> public static PointF GetAbsolutePoint(ChartGraphics cg, DataPoint dp) { PointF p1 = new PointF( (float)cg.GetPositionFromAxis("Default", AxisName.X, dp.XValue), (float)cg.GetPositionFromAxis("Default", AxisName.Y, dp.YValues[0])); p1 = cg.GetAbsolutePoint(p1); return p1; }
protected override void OnPaint (PaintEventArgs e) { base.OnPaint (e); ChartGraphics g = new ChartGraphics (e.Graphics); PaintElement (g, this, new ElementPosition (0, 0, 100, 100)); foreach (var area in ChartAreas) PaintElement (g, area, new ElementPosition (9.299009f, 6.15f, 86.12599f, 81.1875f)); foreach (var series in Series) PaintElement (g, series, new ElementPosition (9.299009f, 6.15f, 86.12599f, 81.1875f)); }
/// <summary> /// Gets position of the axis break line. Break line may be shown as a single /// line or two lines separated with a spacing. /// </summary> /// <param name="graph">Chart graphics.</param> /// <param name="nextSegment">Next segment reference.</param> /// <returns>Position of the axis break line in pixel coordinates.</returns> internal RectangleF GetBreakLinePosition(ChartGraphics graph, AxisScaleSegment nextSegment) { // Start with the plotting rectangle position RectangleF breakPosition = this.axis.PlotAreaPosition.ToRectangleF(); // Find maximum scale value of the current segment and minimuj of the next double from = this.axis.GetLinearPosition(nextSegment.ScaleMinimum); double to = this.axis.GetLinearPosition(this.ScaleMaximum); if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left) { breakPosition.Y = (float)Math.Min(from, to); breakPosition.Height = (float)Math.Max(from, to); } else { breakPosition.X = (float)Math.Min(from, to); breakPosition.Width = (float)Math.Max(from, to);; } // Convert to pixels breakPosition = Rectangle.Round(graph.GetAbsoluteRectangle(breakPosition)); // Add border width if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left) { breakPosition.Height = (float)Math.Abs(breakPosition.Y - breakPosition.Height); breakPosition.X -= this.axis.ChartArea.BorderWidth; breakPosition.Width += 2 * this.axis.ChartArea.BorderWidth; } else { breakPosition.Width = (float)Math.Abs(breakPosition.X - breakPosition.Width); breakPosition.Y -= this.axis.ChartArea.BorderWidth; breakPosition.Height += 2 * this.axis.ChartArea.BorderWidth; } return(breakPosition); }
/// <summary> /// Gets text annotation content size based on the text and font. /// </summary> /// <returns>Annotation content position.</returns> override internal RectangleF GetContentPosition() { // Check image size if (this.Image.Length > 0) { // Try loading image and getting its size try { if (this.Chart != null) { ImageLoader imageLoader = this.Common.ImageLoader; if (imageLoader != null) { ChartGraphics chartGraphics = this.GetGraphics(); if (chartGraphics != null) { SizeF absSize = new SizeF(); if (imageLoader.GetAdjustedImageSize(this.Image, chartGraphics.Graphics, ref absSize)) { SizeF imageSize = chartGraphics.GetRelativeSize(absSize); return(new RectangleF(float.NaN, float.NaN, imageSize.Width, imageSize.Height)); } } } } } catch (ArgumentException) { // ArgumentException is thrown by LoadImage in certain situations when it can't load the image } } return(new RectangleF(float.NaN, float.NaN, float.NaN, float.NaN)); }
/// <summary> /// Gets text annotation content size based on the text and font. /// </summary> /// <returns>Annotation content position.</returns> override internal RectangleF GetContentPosition() { // Return pre calculated value if (!contentSize.IsEmpty) { return(new RectangleF(float.NaN, float.NaN, contentSize.Width, contentSize.Height)); } // Create temporary bitmap based chart graphics if chart was not // rendered yet and the graphics was not created. // NOTE: Fix for issue #3978. Graphics graphics = null; System.Drawing.Image graphicsImage = null; ChartGraphics tempChartGraph = null; if (GetGraphics() == null && this.Common != null) { graphicsImage = new System.Drawing.Bitmap(Common.ChartPicture.Width, Common.ChartPicture.Height); graphics = Graphics.FromImage(graphicsImage); tempChartGraph = new ChartGraphics(Common); tempChartGraph.Graphics = graphics; tempChartGraph.SetPictureSize(Common.ChartPicture.Width, Common.ChartPicture.Height); this.Common.graph = tempChartGraph; } // Calculate content size RectangleF result = RectangleF.Empty; if (GetGraphics() != null && this.Text.Trim().Length > 0) { // Measure text using current font and slightly increase it contentSize = GetGraphics().MeasureString( "W" + this.ReplaceKeywords(this.Text.Replace("\\n", "\n")), this.Font, new SizeF(2000, 2000), StringFormat.GenericTypographic); contentSize.Height *= 1.04f; // Convert to relative coordinates contentSize = GetGraphics().GetRelativeSize(contentSize); // Add spacing bool annotationRelative = false; RectangleF textSpacing = GetTextSpacing(out annotationRelative); float spacingScaleX = 1f; float spacingScaleY = 1f; if (annotationRelative) { if (contentSize.Width > 25f) { spacingScaleX = contentSize.Width / 25f; spacingScaleX = Math.Max(1f, spacingScaleX); } if (contentSize.Height > 25f) { spacingScaleY = contentSize.Height / 25f; spacingScaleY = Math.Max(1f, spacingScaleY); } } contentSize.Width += (textSpacing.X + textSpacing.Width) * spacingScaleX; contentSize.Height += (textSpacing.Y + textSpacing.Height) * spacingScaleY; result = new RectangleF(float.NaN, float.NaN, contentSize.Width, contentSize.Height); } // Dispose temporary chart graphics if (tempChartGraph != null) { tempChartGraph.Dispose(); graphics.Dispose(); graphicsImage.Dispose(); this.Common.graph = null; } return(result); }
/// <summary> /// Draws a cardinal spline through a specified array of PointF structures /// using a specified tension. The drawing begins offset from /// the beginning of the array. /// </summary> /// <param name="pen">Pen object that determines the color, width, and height of the curve.</param> /// <param name="points">Array of PointF structures that define the spline.</param> /// <param name="offset">Offset from the first element in the array of the points parameter to the starting point in the curve.</param> /// <param name="numberOfSegments">Number of segments after the starting point to include in the curve.</param> /// <param name="tension">Value greater than or equal to 0.0F that specifies the tension of the curve.</param> internal void DrawCurve( Pen pen, PointF[] points, int offset, int numberOfSegments, float tension ) { ChartGraphics chartGraphics = this as ChartGraphics; if (chartGraphics == null || !chartGraphics.IsMetafile) { RenderingObject.DrawCurve(pen, points, offset, numberOfSegments, tension); } else { // Special handling required for the metafiles. We cannot pass large array of // points because they will be persisted inside EMF file and cause exponential // increase in emf file size. Draw curve method uses additional 2, 3 or 4 points // depending on which segement is drawn. PointF[] pointsExact = null; if (offset == 0 && numberOfSegments == points.Length - 1) { // In case the array contains the minimum required number of points // to draw segments - just call the curve drawing method RenderingObject.DrawCurve(pen, points, offset, numberOfSegments, tension); } else { if (offset == 0 && numberOfSegments < points.Length - 1) { // Segment is at the beginning of the array with more points following pointsExact = new PointF[numberOfSegments + 2]; for (int index = 0; index < numberOfSegments + 2; index++) { pointsExact[index] = points[index]; } } else if (offset > 0 && (offset + numberOfSegments) == points.Length - 1) { // Segment is at the end of the array with more points prior to it pointsExact = new PointF[numberOfSegments + 2]; for (int index = 0; index < numberOfSegments + 2; index++) { pointsExact[index] = points[offset + index - 1]; } offset = 1; } else if (offset > 0 && (offset + numberOfSegments) < points.Length - 1) { // Segment in the middle of the array with points prior and following it pointsExact = new PointF[numberOfSegments + 3]; for (int index = 0; index < numberOfSegments + 3; index++) { pointsExact[index] = points[offset + index - 1]; } offset = 1; } // Render the curve using minimum number of required points in the array RenderingObject.DrawCurve(pen, pointsExact, offset, numberOfSegments, tension); } } }
/// <summary> /// Draws text in specified rectangle. /// </summary> /// <param name="graphics">Chart graphics.</param> /// <param name="textPosition">Text position.</param> /// <param name="noSpacingForCenteredText">True if text allowed to be outside of position when centered.</param> /// <param name="getTextPosition">True if position text must be returned by the method.</param> /// <returns>Text actual position if required.</returns> internal RectangleF DrawText(ChartGraphics graphics, RectangleF textPosition, bool noSpacingForCenteredText, bool getTextPosition) { RectangleF textActualPosition = RectangleF.Empty; //*************************************************************** //** Adjust text position uing text spacing //*************************************************************** bool annotationRelative = false; RectangleF textSpacing = GetTextSpacing(out annotationRelative); float spacingScaleX = 1f; float spacingScaleY = 1f; if (annotationRelative) { if (textPosition.Width > 25f) { spacingScaleX = textPosition.Width / 50f; spacingScaleX = Math.Max(1f, spacingScaleX); } if (textPosition.Height > 25f) { spacingScaleY = textPosition.Height / 50f; spacingScaleY = Math.Max(1f, spacingScaleY); } } RectangleF textPositionWithSpacing = new RectangleF(textPosition.Location, textPosition.Size); textPositionWithSpacing.Width -= (textSpacing.Width + textSpacing.X) * spacingScaleX; textPositionWithSpacing.X += textSpacing.X * spacingScaleX; textPositionWithSpacing.Height -= (textSpacing.Height + textSpacing.Y) * spacingScaleY; textPositionWithSpacing.Y += textSpacing.Y * spacingScaleY; //*************************************************************** //** Replace new line characters //*************************************************************** string titleText = this.ReplaceKeywords(this.Text.Replace("\\n", "\n")); //*************************************************************** //** Check if centered text require spacing. //** Use only half of the spacing required. //** Apply only for 1 line of text. //*************************************************************** if (noSpacingForCenteredText && titleText.IndexOf('\n') == -1) { if (this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.MiddleLeft || this.Alignment == ContentAlignment.MiddleRight) { textPositionWithSpacing.Y = textPosition.Y; textPositionWithSpacing.Height = textPosition.Height; textPositionWithSpacing.Height -= textSpacing.Height / 2f + textSpacing.Y / 2f; textPositionWithSpacing.Y += textSpacing.Y / 2f; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.TopCenter) { textPositionWithSpacing.X = textPosition.X; textPositionWithSpacing.Width = textPosition.Width; textPositionWithSpacing.Width -= textSpacing.Width / 2f + textSpacing.X / 2f; textPositionWithSpacing.X += textSpacing.X / 2f; } } // Draw text using (Brush textBrush = new SolidBrush(this.ForeColor)) { using (StringFormat format = new StringFormat(StringFormat.GenericTypographic)) { //*************************************************************** //** Set text format //*************************************************************** format.FormatFlags = format.FormatFlags ^ StringFormatFlags.LineLimit; format.Trimming = StringTrimming.EllipsisCharacter; if (this.Alignment == ContentAlignment.BottomRight || this.Alignment == ContentAlignment.MiddleRight || this.Alignment == ContentAlignment.TopRight) { format.Alignment = StringAlignment.Far; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.TopCenter) { format.Alignment = StringAlignment.Center; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.BottomLeft || this.Alignment == ContentAlignment.BottomRight) { format.LineAlignment = StringAlignment.Far; } if (this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.MiddleLeft || this.Alignment == ContentAlignment.MiddleRight) { format.LineAlignment = StringAlignment.Center; } //*************************************************************** //** Set shadow color and offset //*************************************************************** Color textShadowColor = ChartGraphics.GetGradientColor(this.ForeColor, Color.Black, 0.8); int textShadowOffset = 1; TextStyle textStyle = this.TextStyle; if (textStyle == TextStyle.Shadow && ShadowOffset != 0) { // Draw shadowed text textShadowColor = ShadowColor; textShadowOffset = ShadowOffset; } if (textStyle == TextStyle.Shadow) { textShadowColor = (textShadowColor.A != 255) ? textShadowColor : Color.FromArgb(textShadowColor.A / 2, textShadowColor); } //*************************************************************** //** Get text actual position //*************************************************************** if (getTextPosition) { // Measure text size SizeF textSize = graphics.MeasureStringRel( this.ReplaceKeywords(_text.Replace("\\n", "\n")), this.Font, textPositionWithSpacing.Size, format); // Get text position textActualPosition = new RectangleF(textPositionWithSpacing.Location, textSize); if (this.Alignment == ContentAlignment.BottomRight || this.Alignment == ContentAlignment.MiddleRight || this.Alignment == ContentAlignment.TopRight) { textActualPosition.X += textPositionWithSpacing.Width - textSize.Width; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.TopCenter) { textActualPosition.X += (textPositionWithSpacing.Width - textSize.Width) / 2f; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.BottomLeft || this.Alignment == ContentAlignment.BottomRight) { textActualPosition.Y += textPositionWithSpacing.Height - textSize.Height; } if (this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.MiddleLeft || this.Alignment == ContentAlignment.MiddleRight) { textActualPosition.Y += (textPositionWithSpacing.Height - textSize.Height) / 2f; } // Do not allow text to go outside annotation position textActualPosition.Intersect(textPositionWithSpacing); } RectangleF absPosition = graphics.GetAbsoluteRectangle(textPositionWithSpacing); Title.DrawStringWithStyle( graphics, titleText, this.TextStyle, this.Font, absPosition, this.ForeColor, textShadowColor, textShadowOffset, format, TextOrientation.Auto ); } } return(textActualPosition); }
/// <summary> /// Paints the axis break line. /// </summary> /// <param name="graph">Chart graphics to use.</param> /// <param name="nextSegment">Axis scale segment next to current.</param> internal void PaintBreakLine(ChartGraphics graph, AxisScaleSegment nextSegment) { // Get break line position RectangleF breakPosition = this.GetBreakLinePosition(graph, nextSegment); // Get top line graphics path GraphicsPath breakLinePathTop = this.GetBreakLinePath(breakPosition, true); GraphicsPath breakLinePathBottom = null; // Clear break line space using chart color behind the area if (breakPosition.Width > 0f && breakPosition.Height > 0f) { // Get bottom line graphics path breakLinePathBottom = this.GetBreakLinePath(breakPosition, false); // Clear plotting area background using (GraphicsPath fillPath = new GraphicsPath()) { // Create fill path out of top and bottom break lines fillPath.AddPath(breakLinePathTop, true); fillPath.Reverse(); fillPath.AddPath(breakLinePathBottom, true); fillPath.CloseAllFigures(); // Use chart back color to fill the area using (Brush fillBrush = this.GetChartFillBrush(graph)) { graph.FillPath(fillBrush, fillPath); // Check if shadow exsits in chart area if (this.axis.ChartArea.ShadowOffset != 0 && !this.axis.ChartArea.ShadowColor.IsEmpty) { // Clear shadow RectangleF shadowPartRect = breakPosition; if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left) { shadowPartRect.Y += this.axis.ChartArea.ShadowOffset; shadowPartRect.Height -= this.axis.ChartArea.ShadowOffset; shadowPartRect.X = shadowPartRect.Right - 1; shadowPartRect.Width = this.axis.ChartArea.ShadowOffset + 2; } else { shadowPartRect.X += this.axis.ChartArea.ShadowOffset; shadowPartRect.Width -= this.axis.ChartArea.ShadowOffset; shadowPartRect.Y = shadowPartRect.Bottom - 1; shadowPartRect.Height = this.axis.ChartArea.ShadowOffset + 2; } graph.FillRectangle(fillBrush, shadowPartRect); // Draw new shadow using (GraphicsPath shadowPath = new GraphicsPath()) { shadowPath.AddPath(breakLinePathTop, false); // Define maximum size float size = this.axis.ChartArea.ShadowOffset; if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left) { size = Math.Min(size, breakPosition.Height); } else { size = Math.Min(size, breakPosition.Width); } // Define step to increase transperancy int transparencyStep = (int)(this.axis.ChartArea.ShadowColor.A / size); // Set clip region to achieve spacing of the shadow // Start with the plotting rectangle position RectangleF clipRegion = graph.GetAbsoluteRectangle(this.axis.PlotAreaPosition.ToRectangleF()); if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left) { clipRegion.X += this.axis.ChartArea.ShadowOffset; clipRegion.Width += this.axis.ChartArea.ShadowOffset; } else { clipRegion.Y += this.axis.ChartArea.ShadowOffset; clipRegion.Height += this.axis.ChartArea.ShadowOffset; } graph.SetClip(graph.GetRelativeRectangle(clipRegion)); // Draw several lines to form shadow for (int index = 0; index < size; index++) { using (Matrix newMatrix = new Matrix()) { // Shift top break line by 1 pixel if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left) { newMatrix.Translate(0f, 1f); } else { newMatrix.Translate(1f, 0f); } shadowPath.Transform(newMatrix); } // Get line color Color color = Color.FromArgb( this.axis.ChartArea.ShadowColor.A - transparencyStep * index, this.axis.ChartArea.ShadowColor); using (Pen shadowPen = new Pen(color, 1)) { // Draw shadow graph.DrawPath(shadowPen, shadowPath); } } graph.ResetClip(); } } } } } // Draw Separator Line(s) if (this.axis.ScaleBreakStyle.BreakLineStyle != BreakLineStyle.None) { using (Pen pen = new Pen(this.axis.ScaleBreakStyle.LineColor, this.axis.ScaleBreakStyle.LineWidth)) { // Set line style pen.DashStyle = graph.GetPenStyle(this.axis.ScaleBreakStyle.LineDashStyle); // Draw break lines graph.DrawPath(pen, breakLinePathTop); if (breakPosition.Width > 0f && breakPosition.Height > 0f) { graph.DrawPath(pen, breakLinePathBottom); } } } // Dispose break line paths breakLinePathTop.Dispose(); breakLinePathTop = null; if (breakLinePathBottom != null) { breakLinePathBottom.Dispose(); breakLinePathBottom = null; } }
/// <summary> /// Gets all the RangePolygons between line1 and line2. /// </summary> /// <param name="cg">used for getting absolute values</param> /// <param name="line1">the line that has the 'good' values</param> /// <param name="line2">the line that has the 'bad' values </param> private void FillRangePolygons(ChartGraphics cg, Series line1, Series line2) { this.ClearRangePolygons(); //System.Console.WriteLine("GetRangePolygons Start: " + DateTime.Now.Millisecond); DataPoint[] dpIntersections = LineUtils.GetAllIntersections(line1, line2); //ArrayList rPolygons = new ArrayList(); if (dpIntersections != null) { switch (dpIntersections.Length) { case 0: //this is where tehre is no intersection break; case 1: //this is the special case that there is only one intersection RangePolygon sPolygon = GetStartPolygon(cg, line1, line2, dpIntersections[0], this.rPolygons.Count); if (sPolygon != null) rPolygons.Add(sPolygon); RangePolygon ePolygon = GetEndPolygon(cg, line1, line2, dpIntersections[dpIntersections.Length - 1], this.rPolygons.Count); if (ePolygon != null) rPolygons.Add(ePolygon); break; default: if (dpIntersections.Length >= 0) { RangePolygon startPolygon = GetStartPolygon(cg, line1, line2, dpIntersections[0], this.rPolygons.Count); if (startPolygon != null) rPolygons.Add(startPolygon); for (int dpInterIndex = 0; dpInterIndex < dpIntersections.Length - 1; dpInterIndex++) { RangePolygon rp = GetPolygonOfIntersection(cg, line1, line2, dpIntersections[dpInterIndex], dpIntersections[dpInterIndex + 1], this.rPolygons.Count); if (rp != null) rPolygons.Add(rp); } RangePolygon endPolygon = GetEndPolygon(cg, line1, line2, dpIntersections[dpIntersections.Length - 1], this.rPolygons.Count); if (endPolygon != null) rPolygons.Add(endPolygon); } else { break; } //System.Console.WriteLine("GetRangePolygons END: " + DateTime.Now.Millisecond); break; } } }
/// <summary> /// Gets a RangePolygon between two intersecting points /// </summary> /// <param name="cg">for finding the absolute coordinates</param> /// <param name="line1">line 1</param> /// <param name="line2">line 2</param> /// <param name="startPoint">the first intersection point</param> /// <param name="endPoint">the second intersection point</param> /// <param name="polygonID">id for the new polygon</param> /// <returns>a RangePolygon, null otherwise</returns> private RangePolygon GetPolygonOfIntersection(ChartGraphics cg, Series line1, Series line2, DataPoint startPoint, DataPoint endPoint, int polygonID) { //System.Console.WriteLine("GetPolygonIntersection Start: " + DateTime.Now.Millisecond); Series tempLine1 = LineUtils.PointsInRange(startPoint, endPoint, line1); Series tempLine2 = LineUtils.PointsInRange(startPoint, endPoint, line2); if (tempLine1 == null || tempLine2 == null) return null; RangePolygon.RANGETYPE rType; Series topLine; Series bottomLine; if (tempLine1.Points.Count == 0) { tempLine1.Points.Add(startPoint); tempLine1.Points.Add(endPoint); } if (tempLine2.Points.Count == 0) { tempLine2.Points.Add(startPoint); tempLine2.Points.Add(endPoint); } if (LineUtils.IsAbove(tempLine1, tempLine2)) { topLine = tempLine1; bottomLine = tempLine2; rType = RangePolygon.RANGETYPE.TOP; } else { rType = RangePolygon.RANGETYPE.BOTTOM; topLine = tempLine2; bottomLine = tempLine1; } List<PointF> points = new List<PointF>(); points.Add(LineUtils.GetAbsolutePoint(cg, startPoint)); foreach (DataPoint dp in topLine.Points) { points.Add(LineUtils.GetAbsolutePoint(cg, dp)); } points.Add(LineUtils.GetAbsolutePoint(cg, endPoint)); bottomLine.Sort(PointSortOrder.Descending, "X"); foreach (DataPoint dp in bottomLine.Points) { points.Add(LineUtils.GetAbsolutePoint(cg, dp)); } points.Add(LineUtils.GetAbsolutePoint(cg, startPoint)); //System.Console.WriteLine("GetPolygonIntersection END: " + DateTime.Now.Millisecond); return new RangePolygon(points.ToArray(), rType, polygonID); }
/// <summary> /// Paints the annotation object on the specified graphics. /// </summary> /// <param name="graphics"> /// A <see cref="ChartGraphics"/> object, used to paint the annotation object. /// </param> /// <param name="chart"> /// Reference to the <see cref="Chart"/> owner 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)); // 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; } if (this.Common.ProcessModePaint) { // Draw "empty" image at design time if (this._imageName.Length == 0 && this.Chart.IsDesignMode()) { graphics.FillRectangleRel( rectanglePosition, this.BackColor, this.BackHatchStyle, this._imageName, this._imageWrapMode, this._imageTransparentColor, GetImageAlignment(this.Alignment), this.BackGradientStyle, this.BackSecondaryColor, this.LineColor, this.LineWidth, this.LineDashStyle, this.ShadowColor, this.ShadowOffset, PenAlignment.Center); // Draw text using (Brush textBrush = new SolidBrush(this.ForeColor)) { using (StringFormat format = new StringFormat(StringFormat.GenericTypographic)) { format.Alignment = StringAlignment.Center; format.LineAlignment = StringAlignment.Center; format.FormatFlags = StringFormatFlags.LineLimit; format.Trimming = StringTrimming.EllipsisCharacter; graphics.DrawStringRel( "(no image)", this.Font, textBrush, rectanglePosition, format); } } } else { // Draw image graphics.FillRectangleRel( rectanglePosition, Color.Transparent, this.BackHatchStyle, this._imageName, this._imageWrapMode, this._imageTransparentColor, GetImageAlignment(this.Alignment), this.BackGradientStyle, Color.Transparent, Color.Transparent, 0, this.LineDashStyle, this.ShadowColor, this.ShadowOffset, PenAlignment.Center); } } if (this.Common.ProcessModeRegions) { // Add hot region this.Common.HotRegionsList.AddHotRegion( rectanglePosition, ReplaceKeywords(this.ToolTip), String.Empty, String.Empty, String.Empty, this, ChartElementType.Annotation, String.Empty); } // Paint selection handles PaintSelectionHandles(graphics, selectionRect, null); }
internal void Paint(ChartGraphics chartGraph, bool drawAnnotationOnly) { ChartPicture chartPicture = this.Chart.chartPicture; // Restore previous background using double buffered bitmap if (!chartPicture.isSelectionMode && this.Count > 0 /*&& * !this.Chart.chartPicture.isPrinting*/) { chartPicture.backgroundRestored = true; Rectangle chartPosition = new Rectangle(0, 0, chartPicture.Width, chartPicture.Height); if (chartPicture.nonTopLevelChartBuffer == null || !drawAnnotationOnly) { // Dispose previous bitmap if (chartPicture.nonTopLevelChartBuffer != null) { chartPicture.nonTopLevelChartBuffer.Dispose(); chartPicture.nonTopLevelChartBuffer = null; } // Copy chart area plotting rectangle from the chart's dubble buffer image into area dubble buffer image if (this.Chart.paintBufferBitmap != null && this.Chart.paintBufferBitmap.Size.Width >= chartPosition.Size.Width && this.Chart.paintBufferBitmap.Size.Height >= chartPosition.Size.Height) { chartPicture.nonTopLevelChartBuffer = this.Chart.paintBufferBitmap.Clone( chartPosition, this.Chart.paintBufferBitmap.PixelFormat); } } else if (drawAnnotationOnly && chartPicture.nonTopLevelChartBuffer != null) { // Restore previous background this.Chart.paintBufferBitmapGraphics.DrawImageUnscaled( chartPicture.nonTopLevelChartBuffer, chartPosition); } } // Draw all annotation objects foreach (Annotation annotation in this) { // Reset calculated relative position annotation.ResetCurrentRelativePosition(); if (annotation.IsVisible()) { bool resetClip = false; // Check if anchor point assosiated with plot area is inside the scaleView if (annotation.IsAnchorVisible()) { // Set annotation object clipping if (annotation.ClipToChartArea.Length > 0 && annotation.ClipToChartArea != Constants.NotSetValue && Chart != null) { int areaIndex = Chart.ChartAreas.IndexOf(annotation.ClipToChartArea); if (areaIndex >= 0) { // Get chart area object ChartArea chartArea = Chart.ChartAreas[areaIndex]; chartGraph.SetClip(chartArea.PlotAreaPosition.ToRectangleF()); resetClip = true; } } // Start Svg Selection mode string url = String.Empty; chartGraph.StartHotRegion( annotation.ReplaceKeywords(url), annotation.ReplaceKeywords(annotation.ToolTip)); // Draw annotation object annotation.Paint(Chart, chartGraph); // End Svg Selection mode chartGraph.EndHotRegion( ); // Reset clipping region if (resetClip) { chartGraph.ResetClip(); } } } } }
/// <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"/> 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)); // Get text 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; } if (this.isRectVisible && this.Common.ProcessModePaint) { // Draw rectangle graphics.FillRectangleRel( rectanglePosition, this.BackColor, this.BackHatchStyle, String.Empty, ChartImageWrapMode.Scaled, Color.Empty, ChartImageAlignmentStyle.Center, this.BackGradientStyle, this.BackSecondaryColor, this.LineColor, this.LineWidth, this.LineDashStyle, this.ShadowColor, this.ShadowOffset, PenAlignment.Center, this.isEllipse, 1, false); } // Call base class to paint text, selection handles and process hot regions base.Paint(chart, graphics); }
/// <summary> /// Paints the annotation object on the specified graphics. /// </summary> /// <param name="graphics"> /// A <see cref="ChartGraphics"/> /// </param> /// <param name="chart"> /// Reference to the <see cref="Chart"/> control that owns the annotation. /// </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)); // Get text 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; } if (this.Common.ProcessModePaint) { // Do not draw border if size is less that 10 pixels RectangleF absRectanglePosition = graphics.GetAbsoluteRectangle(rectanglePosition); if (absRectanglePosition.Width > 30f && absRectanglePosition.Height > 30f) { // Draw rectangle graphics.Draw3DBorderRel( _borderSkin, rectanglePosition, this.BackColor, this.BackHatchStyle, String.Empty, ChartImageWrapMode.Scaled, Color.Empty, ChartImageAlignmentStyle.Center, this.BackGradientStyle, this.BackSecondaryColor, this.LineColor, this.LineWidth, this.LineDashStyle); } } // Call base class to paint text, selection handles and process hot regions base.Paint(chart, graphics); }
/// <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) { // 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)); // Adjust coordinates AdjustLineCoordinates(ref firstPoint, ref secondPoint, ref selectionRect); // Check if text position is valid if (float.IsNaN(firstPoint.X) || float.IsNaN(firstPoint.Y) || float.IsNaN(secondPoint.X) || float.IsNaN(secondPoint.Y)) { return; } // Set line caps bool capChanged = false; LineCap oldStartCap = LineCap.Flat; LineCap oldEndCap = LineCap.Flat; 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; } } if (this.Common.ProcessModePaint) { // Draw line graphics.DrawLineRel( this.LineColor, this.LineWidth, this.LineDashStyle, firstPoint, secondPoint, this.ShadowColor, this.ShadowOffset); } if (this.Common.ProcessModeRegions) { // Create line graphics path using (GraphicsPath path = new GraphicsPath()) { path.AddLine( graphics.GetAbsolutePoint(firstPoint), graphics.GetAbsolutePoint(secondPoint)); using (Pen pen = (Pen)graphics.Pen.Clone()) { // Increase pen size by 2 pixels pen.DashStyle = DashStyle.Solid; pen.Width += 2; try { path.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, path, false, ReplaceKeywords(this.ToolTip), String.Empty, String.Empty, String.Empty, this, ChartElementType.Annotation); } } // Restore line caps if (capChanged) { graphics.Pen.StartCap = oldStartCap; graphics.Pen.EndCap = oldEndCap; } // Paint selection handles PaintSelectionHandles(graphics, selectionRect, null); }
/// <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); }
/// <summary> /// </summary> /// <param name="cg"></param> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> private PointF ToPixelsPos(ChartGraphics cg, double x, double y) { var p = new PointF((float) cg.GetPositionFromAxis(kChartAreaName, AxisName.X, x), (float) cg.GetPositionFromAxis(kChartAreaName, AxisName.Y, y)); return cg.GetAbsolutePoint(p); }
/// <summary> /// Return intensity of lightStyle for 3D Cube. There are tree types of lights: None, /// Simplistic and Realistic. None Style have same lightStyle intensity on /// all polygons. Normal vector doesn’t have influence on this type /// of lighting. Simplistic style have lightStyle source, which is /// rotated together with scene. Realistic lighting have fixed lightStyle /// source and intensity of lightStyle is change when scene is rotated. /// </summary> /// <param name="surfaceColor">Color used for polygons without lighting</param> /// <param name="front">Color corrected with intensity of lightStyle for Front side of the 3D Rectangle</param> /// <param name="back">Color corrected with intensity of lightStyle for Back side of the 3D Rectangle</param> /// <param name="left">Color corrected with intensity of lightStyle for Left side of the 3D Rectangle</param> /// <param name="right">Color corrected with intensity of lightStyle for Right side of the 3D Rectangle</param> /// <param name="top">Color corrected with intensity of lightStyle for Top side of the 3D Rectangle</param> /// <param name="bottom">Color corrected with intensity of lightStyle for Bottom side of the 3D Rectangle</param> internal void GetLight(Color surfaceColor, out Color front, out Color back, out Color left, out Color right, out Color top, out Color bottom) { switch (_lightStyle) { // LightStyle style is None case LightStyle.None: { front = surfaceColor; left = surfaceColor; top = surfaceColor; back = surfaceColor; right = surfaceColor; bottom = surfaceColor; break; } // LightStyle style is Simplistic case LightStyle.Simplistic: { front = surfaceColor; left = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25); top = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); back = surfaceColor; right = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25); bottom = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); break; } // LightStyle style is Realistic default: { // For Right Axis angle Realistic lightStyle should be different if (_rightAngleAxis) { // LightStyle source Vector Point3D lightSource = new Point3D(0F, 0F, -1F); Point3D [] rightPRpoints = new Point3D[1]; rightPRpoints[0] = lightSource; RightAngleProjection(rightPRpoints); // ****************************************************************** // Color correction. Angle between Normal vector of polygon and // vector of lightStyle source is used. // ****************************************************************** if (this._angleY >= 45 || this._angleY <= -45) { front = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[1]) / Math.PI); back = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[2]) / Math.PI); left = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0); right = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0); } else { front = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0); back = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 1); left = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[3]) / Math.PI); right = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[4]) / Math.PI); } top = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[5]) / Math.PI); bottom = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[6]) / Math.PI); } else { // LightStyle source Vector Point3D lightSource = new Point3D(0F, 0F, 1F); // ****************************************************************** // Color correction. Angle between Normal vector of polygon and // vector of lightStyle source is used. // ****************************************************************** front = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[1]) / Math.PI); back = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[2]) / Math.PI); left = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[3]) / Math.PI); right = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[4]) / Math.PI); top = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[5]) / Math.PI); bottom = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[6]) / Math.PI); } break; } } }
/// <summary> /// Paints an annotation object using the specified graphics. /// </summary> /// <param name="graphics"> /// A <see cref="ChartGraphics"/> object, used to paint the annotation object. /// </param> /// <param name="chart"> /// Reference to the <see cref="Chart"/> control. /// </param> override internal void Paint(Chart chart, ChartGraphics graphics) { // Paint all annotations in the group foreach (Annotation annotation in this.annotations) { annotation.Paint(chart, graphics); } if ((this.Common.ProcessModePaint && this.IsSelected) || this.Common.ProcessModeRegions) { // 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 rectangle orientation if (selectionRect.Width < 0) { selectionRect.X = selectionRect.Right; selectionRect.Width = -selectionRect.Width; } if (selectionRect.Height < 0) { selectionRect.Y = selectionRect.Bottom; selectionRect.Height = -selectionRect.Height; } // Check if text position is valid if (selectionRect.IsEmpty || float.IsNaN(selectionRect.X) || float.IsNaN(selectionRect.Y) || float.IsNaN(selectionRect.Right) || float.IsNaN(selectionRect.Bottom)) { return; } if (this.Common.ProcessModeRegions) { // Add hot region this.Common.HotRegionsList.AddHotRegion( selectionRect, ReplaceKeywords(this.ToolTip), String.Empty, String.Empty, String.Empty, this, ChartElementType.Annotation, String.Empty); } // Paint selection handles PaintSelectionHandles(graphics, selectionRect, null); } }
/// <summary> /// Return intensity of lightStyle for Polygons. There are tree types of lights: None, /// Simplistic and Realistic. None Style have same lightStyle intensity on /// all polygons. Normal vector doesn’t have influence on this type /// of lighting. Simplistic style have lightStyle source, which is /// rotated together with scene. Realistic lighting have fixed lightStyle /// source and intensity of lightStyle is change when scene is rotated. /// </summary> /// <param name="points">Points of the polygon</param> /// <param name="surfaceColor">Color used for polygons without lighting</param> /// <param name="visiblePolygon">This flag gets information if polygon is visible or not.</param> /// <param name="rotation">Y angle ( from -90 to 90 ) Should be used width switchSeriesOrder to get from -180 to 180</param> /// <param name="surfaceName">Used for lighting of front - back and left - right sides</param> /// <param name="switchSeriesOrder">Used to calculate real y angle</param> /// <returns>Color corrected with intensity of lightStyle</returns> internal Color GetPolygonLight(Point3D[] points, Color surfaceColor, bool visiblePolygon, float rotation, SurfaceNames surfaceName, bool switchSeriesOrder) { // Corrected color Color color = surfaceColor; // Direction of lightStyle source Point3D lightSource; lightSource = new Point3D(0F, 0F, 1F); // There are tree different lightStyle styles: None, Simplistic and realistic. switch (_lightStyle) { // LightStyle style is None case LightStyle.None: { // Use same color break; } // LightStyle style is Simplistic case LightStyle.Simplistic: { // Find two vectors of polygon Point3D firstVector = new Point3D(); firstVector.X = points[0].X - points[1].X; firstVector.Y = points[0].Y - points[1].Y; firstVector.Z = points[0].Z - points[1].Z; Point3D secondVector = new Point3D(); secondVector.X = points[2].X - points[1].X; secondVector.Y = points[2].Y - points[1].Y; secondVector.Z = points[2].Z - points[1].Z; // Find Normal vector for Polygon Point3D normalVector = new Point3D(); normalVector.X = firstVector.Y * secondVector.Z - firstVector.Z * secondVector.Y; normalVector.Y = firstVector.Z * secondVector.X - firstVector.X * secondVector.Z; normalVector.Z = firstVector.X * secondVector.Y - firstVector.Y * secondVector.X; // Polygon is left side ( like side of area chart ) if (surfaceName == SurfaceNames.Left) { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); } // Polygon is right side ( like side of area chart ) else if (surfaceName == SurfaceNames.Right) { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); } // Polygon is front side ( like side of area chart ) else if (surfaceName == SurfaceNames.Front) { color = surfaceColor; } // Polygon is back side ( like side of area chart ) else if (surfaceName == SurfaceNames.Back) { color = surfaceColor; } // Polygon has angle with bottom side ( Line chart or top of area chart ) else { float angleLeft; float angleRight; // Find angles between lightStyle and polygon for different y-axis angles. if (switchSeriesOrder) { if (rotation > 0 && rotation <= 90) { angleLeft = GetAngle(normalVector, _lightVectors[3]); angleRight = GetAngle(normalVector, _lightVectors[4]); } else { angleLeft = GetAngle(normalVector, _lightVectors[4]); angleRight = GetAngle(normalVector, _lightVectors[3]); } } else { if (rotation > 0 && rotation <= 90) { angleLeft = GetAngle(normalVector, _lightVectors[4]); angleRight = GetAngle(normalVector, _lightVectors[3]); } else { angleLeft = GetAngle(normalVector, _lightVectors[3]); angleRight = GetAngle(normalVector, _lightVectors[4]); } } if (Math.Abs(angleLeft - angleRight) < 0.01) { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25); } else if (angleLeft < angleRight) { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25); } else { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); } } break; } // LightStyle style is Realistic default: { // Find two vectors of polygon Point3D firstVector = new Point3D(); firstVector.X = points[0].X - points[1].X; firstVector.Y = points[0].Y - points[1].Y; firstVector.Z = points[0].Z - points[1].Z; Point3D secondVector = new Point3D(); secondVector.X = points[2].X - points[1].X; secondVector.Y = points[2].Y - points[1].Y; secondVector.Z = points[2].Z - points[1].Z; // Find Normal vector for Polygon Point3D normalVector = new Point3D(); normalVector.X = firstVector.Y * secondVector.Z - firstVector.Z * secondVector.Y; normalVector.Y = firstVector.Z * secondVector.X - firstVector.X * secondVector.Z; normalVector.Z = firstVector.X * secondVector.Y - firstVector.Y * secondVector.X; // ****************************************************************** // Color correction. Angle between Normal vector of polygon and // vector of lightStyle source is used. // ****************************************************************** if (surfaceName == SurfaceNames.Front) { lightSource.Z *= -1; color = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[2]) / Math.PI); } else if (surfaceName == SurfaceNames.Back) { lightSource.Z *= -1; color = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[1]) / Math.PI); } else { if (visiblePolygon) { lightSource.Z *= -1; } color = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, normalVector) / Math.PI); } break; } } return(color); }
/// <summary> /// Draw strip(s) or line(s). /// </summary> /// <param name="graph">Reference to the Chart Graphics object.</param> /// <param name="common">Common objects.</param> /// <param name="drawLinesOnly">Indicates if Lines or Stripes should be drawn.</param> internal void Paint( ChartGraphics graph, CommonElements common, bool drawLinesOnly) { // Strip lines are not supported in circular chart area if (this.Axis.ChartArea.chartAreaIsCurcular) { return; } // Get plot area position RectangleF plotAreaPosition = this.Axis.ChartArea.PlotAreaPosition.ToRectangleF(); // Detect if strip/line is horizontal or vertical bool horizontal = true; if (this.Axis.AxisPosition == AxisPosition.Bottom || this.Axis.AxisPosition == AxisPosition.Top) { horizontal = false; } // Get first series attached to this axis Series axisSeries = null; if (Axis.axisType == AxisName.X || Axis.axisType == AxisName.X2) { List <string> seriesArray = Axis.ChartArea.GetXAxesSeries((Axis.axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, Axis.SubAxisName); if (seriesArray.Count > 0) { axisSeries = Axis.Common.DataManager.Series[seriesArray[0]]; if (axisSeries != null && !axisSeries.IsXValueIndexed) { axisSeries = null; } } } // Get starting position from axis // NOTE: Starting position was changed from "this.Axis.minimum" to // fix the minimum scaleView location to fix issue #5962 -- AG double currentPosition = this.Axis.ViewMinimum; // Adjust start position depending on the interval type if (!Axis.ChartArea.chartAreaIsCurcular || Axis.axisType == AxisName.Y || Axis.axisType == AxisName.Y2) { double intervalToUse = this.Interval; // NOTE: fix for issue #5962 // Always use original grid interval for isInterlaced strip lines. if (this.interlaced) { // Automaticly generated isInterlaced strips have interval twice as big as major grids intervalToUse /= 2.0; } currentPosition = ChartHelper.AlignIntervalStart(currentPosition, intervalToUse, this.IntervalType, axisSeries); } // Too many tick marks if (this.Interval != 0) { if ((Axis.ViewMaximum - Axis.ViewMinimum) / ChartHelper.GetIntervalSize(currentPosition, this._interval, this._intervalType, axisSeries, 0, DateTimeIntervalType.Number, false) > ChartHelper.MaxNumOfGridlines) { return; } } DateTimeIntervalType offsetType = (IntervalOffsetType == DateTimeIntervalType.Auto) ? IntervalType : IntervalOffsetType; if (this.Interval == 0) { currentPosition = this.IntervalOffset; } /****************************************************************** * Removed by AG. Causing issues with interalced strip lines. * /****************************************************************** * else if(axisSeries != null && axisSeries.IsXValueIndexed) * { * // Align first position for indexed series * currentPosition += this.Axis.AlignIndexedIntervalStart( * currentPosition, * this.Interval, * this.IntervalType, * axisSeries, * this.IntervalOffset, * offsetType, * false); * } */ else { if (this.IntervalOffset > 0) { currentPosition += ChartHelper.GetIntervalSize(currentPosition, this.IntervalOffset, offsetType, axisSeries, 0, DateTimeIntervalType.Number, false); } else if (this.IntervalOffset < 0) { currentPosition -= ChartHelper.GetIntervalSize(currentPosition, -this.IntervalOffset, offsetType, axisSeries, 0, DateTimeIntervalType.Number, false); } } // Draw several lines or strips if Interval property is set int counter = 0; do { // Check if we do not exceed max number of elements if (counter++ > ChartHelper.MaxNumOfGridlines) { break; } // Draw strip if (this.StripWidth > 0 && !drawLinesOnly) { double stripRightPosition = currentPosition + ChartHelper.GetIntervalSize(currentPosition, this.StripWidth, this.StripWidthType, axisSeries, this.IntervalOffset, offsetType, false); if (stripRightPosition > this.Axis.ViewMinimum && currentPosition < this.Axis.ViewMaximum) { // Calculate strip rectangle RectangleF rect = RectangleF.Empty; double pos1 = (float)this.Axis.GetLinearPosition(currentPosition); double pos2 = (float)this.Axis.GetLinearPosition(stripRightPosition); if (horizontal) { rect.X = plotAreaPosition.X; rect.Width = plotAreaPosition.Width; rect.Y = (float)Math.Min(pos1, pos2); rect.Height = (float)Math.Max(pos1, pos2) - rect.Y; // Check rectangle boundaries rect.Intersect(plotAreaPosition); } else { rect.Y = plotAreaPosition.Y; rect.Height = plotAreaPosition.Height; rect.X = (float)Math.Min(pos1, pos2); rect.Width = (float)Math.Max(pos1, pos2) - rect.X; // Check rectangle boundaries rect.Intersect(plotAreaPosition); } if (rect.Width > 0 && rect.Height > 0) { // Start Svg Selection mode graph.StartHotRegion("", this._toolTip); if (!this.Axis.ChartArea.Area3DStyle.Enable3D) { // Draw strip graph.FillRectangleRel(rect, this.BackColor, this.BackHatchStyle, this.BackImage, this.BackImageWrapMode, this.BackImageTransparentColor, this.BackImageAlignment, this.BackGradientStyle, this.BackSecondaryColor, this.BorderColor, this.BorderWidth, this.BorderDashStyle, Color.Empty, 0, PenAlignment.Inset); } else { Draw3DStrip(graph, rect, horizontal); } // End Svg Selection mode graph.EndHotRegion(); // Draw strip line title PaintTitle(graph, rect); if (common.ProcessModeRegions) { if (!this.Axis.ChartArea.Area3DStyle.Enable3D) { common.HotRegionsList.AddHotRegion(rect, this.ToolTip, string.Empty, string.Empty, string.Empty, this, ChartElementType.StripLines, null); } } } } } // Draw line else if (this.StripWidth == 0 && drawLinesOnly) { if (currentPosition > this.Axis.ViewMinimum && currentPosition < this.Axis.ViewMaximum) { // Calculate line position PointF point1 = PointF.Empty; PointF point2 = PointF.Empty; if (horizontal) { point1.X = plotAreaPosition.X; point1.Y = (float)this.Axis.GetLinearPosition(currentPosition); point2.X = plotAreaPosition.Right; point2.Y = point1.Y; } else { point1.X = (float)this.Axis.GetLinearPosition(currentPosition); point1.Y = plotAreaPosition.Y; point2.X = point1.X; point2.Y = plotAreaPosition.Bottom; } // Start Svg Selection mode graph.StartHotRegion("", this._toolTip); // Draw Line if (!this.Axis.ChartArea.Area3DStyle.Enable3D) { graph.DrawLineRel(this.BorderColor, this.BorderWidth, this.BorderDashStyle, point1, point2); } else { graph.Draw3DGridLine(this.Axis.ChartArea, _borderColor, _borderWidth, _borderDashStyle, point1, point2, horizontal, Axis.Common, this); } // End Svg Selection mode graph.EndHotRegion(); // Draw strip line title PaintTitle(graph, point1, point2); if (common.ProcessModeRegions) { SizeF relBorderWidth = new SizeF(this.BorderWidth + 1, this.BorderWidth + 1); relBorderWidth = graph.GetRelativeSize(relBorderWidth); RectangleF lineRect = RectangleF.Empty; if (horizontal) { lineRect.X = point1.X; lineRect.Y = point1.Y - relBorderWidth.Height / 2f; lineRect.Width = point2.X - point1.X; lineRect.Height = relBorderWidth.Height; } else { lineRect.X = point1.X - relBorderWidth.Width / 2f; lineRect.Y = point1.Y; lineRect.Width = relBorderWidth.Width; lineRect.Height = point2.Y - point1.Y; } common.HotRegionsList.AddHotRegion(lineRect, this.ToolTip, null, null, null, this, ChartElementType.StripLines, null); } } } // Go to the next line/strip if (this.Interval > 0) { currentPosition += ChartHelper.GetIntervalSize(currentPosition, this.Interval, this.IntervalType, axisSeries, this.IntervalOffset, offsetType, false); } } while(this.Interval > 0 && currentPosition <= this.Axis.ViewMaximum); }
/// <summary> /// Draws strip line in 3d. /// </summary> /// <param name="graph">Chart graphics.</param> /// <param name="rect">Strip rectangle.</param> /// <param name="horizontal">Indicates that strip is horizontal</param> private void Draw3DStrip(ChartGraphics graph, RectangleF rect, bool horizontal) { ChartArea area = this.Axis.ChartArea; GraphicsPath path = null; DrawingOperationTypes operationType = DrawingOperationTypes.DrawElement; if (this.Axis.Common.ProcessModeRegions) { operationType |= DrawingOperationTypes.CalcElementPath; } // Draw strip on the back/front wall path = graph.Fill3DRectangle( rect, area.IsMainSceneWallOnFront() ? area.areaSceneDepth : 0f, 0, area.matrix3D, area.Area3DStyle.LightStyle, this.BackColor, this.BorderColor, this.BorderWidth, this.BorderDashStyle, operationType); if (this.Axis.Common.ProcessModeRegions) { this.Axis.Common.HotRegionsList.AddHotRegion(graph, path, false, this.ToolTip, null, null, null, this, ChartElementType.StripLines); } if (horizontal) { // Draw strip on the side wall (left or right) if (!area.IsSideSceneWallOnLeft()) { rect.X = rect.Right; } rect.Width = 0f; path = graph.Fill3DRectangle( rect, 0f, area.areaSceneDepth, area.matrix3D, area.Area3DStyle.LightStyle, this.BackColor, this.BorderColor, this.BorderWidth, this.BorderDashStyle, operationType); } else if (area.IsBottomSceneWallVisible()) { // Draw strip on the bottom wall (if visible) rect.Y = rect.Bottom; rect.Height = 0f; path = graph.Fill3DRectangle( rect, 0f, area.areaSceneDepth, area.matrix3D, area.Area3DStyle.LightStyle, this.BackColor, this.BorderColor, this.BorderWidth, this.BorderDashStyle, operationType); } if (this.Axis.Common.ProcessModeRegions) { this.Axis.Common.HotRegionsList.AddHotRegion(graph, path, false, this.ToolTip, null, null, null, this, ChartElementType.StripLines); } if (path != null) { path.Dispose(); } }
public void DrawPolygons(ChartGraphics cg, Series line1, Series line2) { FillRangePolygons(cg, line1, line2); //iterate through all the polygons and draw them for (int i = 0; i < RangePolygons.Length; i++) { //if the polygon is a BOTTOM range polygon than fill the color with transYellow //else fill with transBlue; if (RangePolygons[i].RangeType == System.Windows.Forms.DataVisualization.Charting.Utilities.RangePolygon.RANGETYPE.BOTTOM) RangePolygons[i].FillColor = this.bottomColor; else RangePolygons[i].FillColor = this.topColor; SolidBrush fillBrush = new SolidBrush(RangePolygons[i].FillColor); //do the actual drawing cg.Graphics.FillPolygon(fillBrush, RangePolygons[i].PolygonPoints); } }
/// <summary> /// Draw strip/line title text /// </summary> /// <param name="graph">Chart graphics object.</param> /// <param name="rect">Rectangle to draw in.</param> private void PaintTitle(ChartGraphics graph, RectangleF rect) { if (this.Text.Length > 0) { // Get title text string titleText = this.Text; // Prepare string format using (StringFormat format = new StringFormat()) { format.Alignment = this.TextAlignment; if (graph.IsRightToLeft) { if (format.Alignment == StringAlignment.Far) { format.Alignment = StringAlignment.Near; } else if (format.Alignment == StringAlignment.Near) { format.Alignment = StringAlignment.Far; } } format.LineAlignment = this.TextLineAlignment; // Adjust default title angle for horizontal lines int angle = 0; switch (this.TextOrientation) { case (TextOrientation.Rotated90): angle = 90; break; case (TextOrientation.Rotated270): angle = 270; break; case (TextOrientation.Auto): if (this.Axis.AxisPosition == AxisPosition.Bottom || this.Axis.AxisPosition == AxisPosition.Top) { angle = 270; } break; } // Set vertical text for horizontal lines if (angle == 90) { format.FormatFlags = StringFormatFlags.DirectionVertical; angle = 0; } else if (angle == 270) { format.FormatFlags = StringFormatFlags.DirectionVertical; angle = 180; } // Measure string size SizeF size = graph.MeasureStringRel(titleText.Replace("\\n", "\n"), this.Font, new SizeF(100, 100), format, this.GetTextOrientation()); // Adjust text size float zPositon = 0f; if (this.Axis.ChartArea.Area3DStyle.Enable3D) { // Get projection coordinates Point3D[] textSizeProjection = new Point3D[3]; zPositon = this.Axis.ChartArea.IsMainSceneWallOnFront() ? this.Axis.ChartArea.areaSceneDepth : 0f; textSizeProjection[0] = new Point3D(0f, 0f, zPositon); textSizeProjection[1] = new Point3D(size.Width, 0f, zPositon); textSizeProjection[2] = new Point3D(0f, size.Height, zPositon); // Transform coordinates of text size this.Axis.ChartArea.matrix3D.TransformPoints(textSizeProjection); // Adjust text size int index = this.Axis.ChartArea.IsMainSceneWallOnFront() ? 0 : 1; size.Width *= size.Width / (textSizeProjection[index].X - textSizeProjection[(index == 0) ? 1 : 0].X); size.Height *= size.Height / (textSizeProjection[2].Y - textSizeProjection[0].Y); } // Get relative size of the border width SizeF sizeBorder = graph.GetRelativeSize(new SizeF(this.BorderWidth, this.BorderWidth)); // Find the center of rotation PointF rotationCenter = PointF.Empty; if (format.Alignment == StringAlignment.Near) { // Near rotationCenter.X = rect.X + size.Width / 2 + sizeBorder.Width; } else if (format.Alignment == StringAlignment.Far) { // Far rotationCenter.X = rect.Right - size.Width / 2 - sizeBorder.Width; } else { // Center rotationCenter.X = (rect.Left + rect.Right) / 2; } if (format.LineAlignment == StringAlignment.Near) { // Near rotationCenter.Y = rect.Top + size.Height / 2 + sizeBorder.Height; } else if (format.LineAlignment == StringAlignment.Far) { // Far rotationCenter.Y = rect.Bottom - size.Height / 2 - sizeBorder.Height; } else { // Center rotationCenter.Y = (rect.Bottom + rect.Top) / 2; } // Reset string alignment to center point format.Alignment = StringAlignment.Center; format.LineAlignment = StringAlignment.Center; if (this.Axis.ChartArea.Area3DStyle.Enable3D) { // Get projection coordinates Point3D[] rotationCenterProjection = new Point3D[2]; rotationCenterProjection[0] = new Point3D(rotationCenter.X, rotationCenter.Y, zPositon); if (format.FormatFlags == StringFormatFlags.DirectionVertical) { rotationCenterProjection[1] = new Point3D(rotationCenter.X, rotationCenter.Y - 20f, zPositon); } else { rotationCenterProjection[1] = new Point3D(rotationCenter.X - 20f, rotationCenter.Y, zPositon); } // Transform coordinates of text rotation point this.Axis.ChartArea.matrix3D.TransformPoints(rotationCenterProjection); // Adjust rotation point rotationCenter = rotationCenterProjection[0].PointF; // Adjust angle of the text if (angle == 0 || angle == 180 || angle == 90 || angle == 270) { if (format.FormatFlags == StringFormatFlags.DirectionVertical) { angle += 90; } // Convert coordinates to absolute rotationCenterProjection[0].PointF = graph.GetAbsolutePoint(rotationCenterProjection[0].PointF); rotationCenterProjection[1].PointF = graph.GetAbsolutePoint(rotationCenterProjection[1].PointF); // Calcuate axis angle float angleXAxis = (float)Math.Atan( (rotationCenterProjection[1].Y - rotationCenterProjection[0].Y) / (rotationCenterProjection[1].X - rotationCenterProjection[0].X)); angleXAxis = (float)Math.Round(angleXAxis * 180f / (float)Math.PI); angle += (int)angleXAxis; } } // Draw string using (Brush brush = new SolidBrush(this.ForeColor)) { graph.DrawStringRel( titleText.Replace("\\n", "\n"), this.Font, brush, rotationCenter, format, angle, this.GetTextOrientation()); } } } }
/// <summary> /// Gets the polygon that is the right most polygon. /// A RangePolygon will only be created if line1 and line2 have the same final XValues /// </summary> /// <param name="cg">for finding the absolute coordinates</param> /// <param name="line1">line 1</param> /// <param name="line2">line 2</param> /// <param name="lastIntersection">last point of intersection</param> /// <param name="pID">id to give the new polygon</param> /// <returns>a RangePolygon, null otherwise</returns> private RangePolygon GetEndPolygon(ChartGraphics cg, Series line1, Series line2, DataPoint lastIntersection,int pID) { DataPoint line1X = line1.Points[line1.Points.Count - 1]; DataPoint line2X = line2.Points[line2.Points.Count - 1]; if (line1X.XValue == line2X.XValue) { return GetPolygonOfIntersection(cg, line1, line2, lastIntersection, line1X, pID); } return null; }
/// <summary> /// Helper method which calculates chart area plotting position in pixels. /// </summary> /// <param name="area">Chart area to get the plotting area position.</param> /// <param name="chartGraphics">Chart graphics object.</param> /// <returns>Chart area ploting area position in pixels.</returns> private RectangleF GetChartAreaPlottingPosition(ChartArea area, ChartGraphics chartGraphics) { RectangleF plottingRect = area.Position.ToRectangleF(); plottingRect.X += (area.Position.Width / 100F) * area.InnerPlotPosition.X; plottingRect.Y += (area.Position.Height / 100F) * area.InnerPlotPosition.Y; plottingRect.Width = (area.Position.Width / 100F) * area.InnerPlotPosition.Width; plottingRect.Height = (area.Position.Height / 100F) * area.InnerPlotPosition.Height; plottingRect = chartGraphics.GetAbsoluteRectangle(plottingRect); return plottingRect; }
/// <summary> /// if line1 and line2 have the same initial X index, then create a polygon for it, else /// ignore it. /// </summary> /// <param name="cg">Chart Graphics finding the absolute coordinates</param> /// <param name="line1">line 1</param> /// <param name="line2">line 2</param> /// <returns>a RangePolygon if line1 and line2 have the same initial x index, else null</returns> private RangePolygon GetStartPolygon(ChartGraphics cg, Series line1, Series line2, DataPoint firstIntersection,int pID) { DataPoint line1X = line1.Points[0]; DataPoint line2X = line2.Points[0]; if (line1X.XValue == line2X.XValue) { return GetPolygonOfIntersection(cg, line1, line2, line1X, firstIntersection,pID); } return null; }
/// <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) { // 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 text position RectangleF textPosition = new RectangleF(selectionRect.Location, selectionRect.Size); if (textPosition.Width < 0) { textPosition.X = textPosition.Right; textPosition.Width = -textPosition.Width; } if (textPosition.Height < 0) { textPosition.Y = textPosition.Bottom; textPosition.Height = -textPosition.Height; } // Check if text position is valid if (textPosition.IsEmpty || float.IsNaN(textPosition.X) || float.IsNaN(textPosition.Y) || float.IsNaN(textPosition.Right) || float.IsNaN(textPosition.Bottom)) { return; } if (this.Common.ProcessModePaint) { DrawText(graphics, textPosition, false, false); } if (this.Common.ProcessModeRegions) { // Add hot region if (isEllipse) { using (GraphicsPath ellipsePath = new GraphicsPath()) { ellipsePath.AddEllipse(textPosition); this.Common.HotRegionsList.AddHotRegion( graphics, ellipsePath, true, ReplaceKeywords(this.ToolTip), String.Empty, String.Empty, String.Empty, this, ChartElementType.Annotation); } } else { this.Common.HotRegionsList.AddHotRegion( textPosition, ReplaceKeywords(this.ToolTip), String.Empty, String.Empty, String.Empty, this, ChartElementType.Annotation, String.Empty); } } // Paint selection handles PaintSelectionHandles(graphics, selectionRect, null); }