1 //-------------------------------------------------------------
2 // <copyright company=
\92Microsoft Corporation
\92>
3 // Copyright © Microsoft Corporation. All Rights Reserved.
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
8 // File: ChartGraphics.cs
10 // Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
12 // Classes: ChartGraphics
14 // Purpose: Chart graphic class is used for drawing Chart
15 // elements as Rectangles, Pie slices, lines, areas
16 // etc. This class is used in all classes where
17 // drawing is necessary. The GDI+ graphic class is
18 // used throw this class. Encapsulates a GDI+ chart
19 // drawing functionality
21 // Reviewed: GS - Jul 31, 2002
22 // AG - August 7, 2002
23 // AG - Microsoft 16, 2007
25 //===================================================================
27 #region Used namespaces
31 using System.Drawing.Drawing2D;
32 using System.Drawing.Text;
33 using System.Drawing.Imaging;
34 using System.Diagnostics.CodeAnalysis;
37 using System.Windows.Forms.DataVisualization.Charting.Utilities;
38 using System.Windows.Forms.DataVisualization.Charting.Borders3D;
40 using System.Web.UI.DataVisualization.Charting.Utilities;
41 using System.Web.UI.DataVisualization.Charting.Borders3D;
47 namespace System.Windows.Forms.DataVisualization.Charting
49 namespace System.Web.UI.DataVisualization.Charting
56 /// Defines the style how the bars/columns are drawn.
58 internal enum BarDrawingStyle
61 /// Default bar/column style.
66 /// Cylinder bar/column style.
71 /// Emboss bar/column style.
76 /// LightToDark bar/column style.
81 /// Wedge bar/column style.
87 /// Defines the style how the pie and doughnut charts are drawn.
89 internal enum PieDrawingStyle
92 /// Default pie/doughnut drawing style.
97 /// Soft edge shadow is drawn on the edges of the pie/doughnut slices.
102 /// A shadow is drawn from the top to the bottom of the pie/doughnut chart.
108 /// An enumeration of line styles.
110 public enum ChartDashStyle
113 /// Line style not set
117 /// Specifies a line consisting of dashes.
121 /// Specifies a line consisting of a repeating pattern of dash-dot.
125 /// Specifies a line consisting of a repeating pattern of dash-dot-dot.
129 /// Specifies a line consisting of dots.
133 /// Specifies a solid line.
141 /// The ChartGraphics class provides all chart drawing capabilities.
142 /// It contains methods for drawing 2D primitives and also exposes
143 /// all ChartGraphics3D class methods for 3D shapes. Only this
144 /// class should be used for any drawing in the chart.
147 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
148 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
150 public partial class ChartGraphics : ChartElement
155 private CommonElements _common;
159 private SolidBrush _solidBrush;
160 private Matrix _myMatrix;
162 // Private fields which represents picture size
166 // Indicates that smoothing is applied while drawing shadows
167 internal bool softShadows = true;
169 // Anti aliasing flags
170 private AntiAliasingStyles _antiAliasing = AntiAliasingStyles.All;
172 // True if rendering into the metafile
173 internal bool IsMetafile = false;
177 #region Lines Methods
180 /// Draws a line connecting the two specified points.
182 /// <param name="color">Line color.</param>
183 /// <param name="width">Line width.</param>
184 /// <param name="style">Line style.</param>
185 /// <param name="firstPointF">A Point that represents the first point to connect.</param>
186 /// <param name="secondPointF">A Point that represents the second point to connect.</param>
187 internal void DrawLineRel(
190 ChartDashStyle style,
199 GetAbsolutePoint(firstPointF),
200 GetAbsolutePoint(secondPointF) );
204 /// Draws a line connecting the two specified points using absolute coordinates.
206 /// <param name="color">Line color.</param>
207 /// <param name="width">Line width.</param>
208 /// <param name="style">Line style.</param>
209 /// <param name="firstPoint">A Point that represents the first point to connect.</param>
210 /// <param name="secondPoint">A Point that represents the second point to connect.</param>
211 internal void DrawLineAbs(
214 ChartDashStyle style,
219 // Do not draw line if width is 0 or style not set
220 if( width == 0 || style == ChartDashStyle.NotSet )
226 if(_pen.Color != color)
232 if(_pen.Width != width)
238 if(_pen.DashStyle != GetPenStyle( style ))
240 _pen.DashStyle = GetPenStyle( style );
243 // Remember SmoothingMode and turn off anti aliasing for
244 // vertical or horizontal lines usinig 1 pixel dashed pen.
245 // This prevents anialiasing from completly smoothing the
247 SmoothingMode oldSmoothingMode = this.SmoothingMode;
248 if(width <= 1 && style != ChartDashStyle.Solid)
250 if(firstPoint.X == secondPoint.X ||
251 firstPoint.Y == secondPoint.Y)
253 this.SmoothingMode = SmoothingMode.Default;
259 (float)Math.Round(firstPoint.X),
260 (float)Math.Round(firstPoint.Y),
261 (float)Math.Round(secondPoint.X),
262 (float)Math.Round(secondPoint.Y) );
264 // Return old smoothing mode
265 this.SmoothingMode = oldSmoothingMode;
269 /// Draws a line with shadow connecting the two specified points.
271 /// <param name="color">Line color.</param>
272 /// <param name="width">Line width.</param>
273 /// <param name="style">Line style.</param>
274 /// <param name="firstPoint">A Point that represents the first point to connect.</param>
275 /// <param name="secondPoint">A Point that represents the second point to connect.</param>
276 /// <param name="shadowColor">Shadow Color.</param>
277 /// <param name="shadowOffset">Shadow Offset.</param>
278 internal void DrawLineRel(
281 ChartDashStyle style,
292 GetAbsolutePoint(firstPoint),
293 GetAbsolutePoint(secondPoint),
299 /// Draws a line with shadow connecting the two specified points.
301 /// <param name="color">Line color.</param>
302 /// <param name="width">Line width.</param>
303 /// <param name="style">Line style.</param>
304 /// <param name="firstPoint">A Point that represents the first point to connect.</param>
305 /// <param name="secondPoint">A Point that represents the second point to connect.</param>
306 /// <param name="shadowColor">Shadow Color.</param>
307 /// <param name="shadowOffset">Shadow Offset.</param>
308 internal void DrawLineAbs(
311 ChartDashStyle style,
318 if(shadowOffset != 0)
323 // Make shadow semi transparent
324 // if alpha value not used
325 if( shadowColor.A != 255 )
326 shColor = shadowColor;
328 shColor = Color.FromArgb(color.A/2, shadowColor);
330 // Set shadow line position
331 PointF firstShadow = new PointF( firstPoint.X + shadowOffset, firstPoint.Y + shadowOffset);
332 PointF secondShadow = new PointF( secondPoint.X + shadowOffset, secondPoint.Y + shadowOffset );
334 // Draw Shadow of Line
335 DrawLineAbs( shColor, width, style, firstShadow, secondShadow );
339 DrawLineAbs( color, width, style, firstPoint, secondPoint );
344 #region Pen and Brush Methods
347 /// Creates a Hatch Brush.
349 /// <param name="hatchStyle">Chart Hatch style.</param>
350 /// <param name="backColor">Back Color.</param>
351 /// <param name="foreColor">Fore Color.</param>
352 /// <returns>Brush</returns>
353 internal Brush GetHatchBrush(
354 ChartHatchStyle hatchStyle,
359 // Convert Chart Hatch Style enum
360 // to Hatch Style enum.
362 hatch = (HatchStyle)Enum.Parse(typeof(HatchStyle),hatchStyle.ToString());
364 // Create Hatch Brush
365 return new HatchBrush( hatch, foreColor, backColor );
369 /// Creates a textured brush.
371 /// <param name="name">Image file name or URL.</param>
372 /// <param name="backImageTransparentColor">Image transparent color.</param>
373 /// <param name="mode">Wrap mode.</param>
374 /// <param name="backColor">Image background color.</param>
375 /// <returns>Textured brush.</returns>
376 internal Brush GetTextureBrush(
378 Color backImageTransparentColor,
379 ChartImageWrapMode mode,
384 System.Drawing.Image image = _common.ImageLoader.LoadImage( name );
387 ImageAttributes attrib = new ImageAttributes();
388 attrib.SetWrapMode((mode == ChartImageWrapMode.Unscaled) ? WrapMode.Clamp : ((WrapMode)mode));
389 if(backImageTransparentColor != Color.Empty)
391 attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
394 // If image is a metafile background must be filled first
395 // Solves issue that background is not cleared correctly
396 if(backImageTransparentColor == Color.Empty &&
398 backColor != Color.Transparent)
400 TextureBrush backFilledBrush = null;
401 Bitmap bitmap = new Bitmap(image.Width, image.Height);
402 using(Graphics graphics = Graphics.FromImage(bitmap))
404 using(SolidBrush backBrush = new SolidBrush(backColor))
406 graphics.FillRectangle(backBrush, 0, 0, image.Width, image.Height);
407 graphics.DrawImageUnscaled(image, 0, 0);
408 backFilledBrush= new TextureBrush( bitmap, new RectangleF(0,0,image.Width,image.Height), attrib);
412 return backFilledBrush;
416 TextureBrush textureBrush;
418 if (ImageLoader.DoDpisMatch(image, this.Graphics))
419 textureBrush = new TextureBrush(image, new RectangleF(0, 0, image.Width, image.Height), attrib);
420 else // if the image dpi does not match the graphics dpi we have to scale the image
422 Image scaledImage = ImageLoader.GetScaledImage(image, this.Graphics);
423 textureBrush = new TextureBrush(scaledImage, new RectangleF(0, 0, scaledImage.Width, scaledImage.Height), attrib);
424 scaledImage.Dispose();
432 /// This method creates a gradient brush.
434 /// <param name="rectangle">A rectangle which has to be filled with a gradient color.</param>
435 /// <param name="firstColor">First color.</param>
436 /// <param name="secondColor">Second color.</param>
437 /// <param name="type ">Gradient type .</param>
438 /// <returns>Gradient Brush</returns>
439 internal Brush GetGradientBrush(
440 RectangleF rectangle,
446 // Increse the brush rectangle by 1 pixel to ensure the fit
447 rectangle.Inflate(1f, 1f);
449 Brush gradientBrush = null;
452 // Function which create gradient brush fires exception if
453 // rectangle size is zero.
454 if( rectangle.Height == 0 || rectangle.Width == 0 )
456 gradientBrush = new SolidBrush( Color.Black );
457 return gradientBrush;
460 // *******************************************
462 // *******************************************
463 // Check linear type .
464 if( type == GradientStyle.LeftRight || type == GradientStyle.VerticalCenter )
468 else if( type == GradientStyle.TopBottom || type == GradientStyle.HorizontalCenter )
472 else if( type == GradientStyle.DiagonalLeft )
474 angle = (float)(Math.Atan(rectangle.Width / rectangle.Height)* 180 / Math.PI);
476 else if( type == GradientStyle.DiagonalRight )
478 angle = (float)(180 - Math.Atan(rectangle.Width / rectangle.Height)* 180 / Math.PI);
481 // Create a linear gradient brush
482 if( type == GradientStyle.TopBottom || type == GradientStyle.LeftRight
483 || type == GradientStyle.DiagonalLeft || type == GradientStyle.DiagonalRight
484 || type == GradientStyle.HorizontalCenter || type == GradientStyle.VerticalCenter )
486 RectangleF tempRect = new RectangleF(rectangle.X,rectangle.Y,rectangle.Width,rectangle.Height);
487 // For Horizontal and vertical center gradient types
488 if( type == GradientStyle.HorizontalCenter )
490 // Resize and wrap gradient
491 tempRect.Height = tempRect.Height / 2F;
492 LinearGradientBrush linearGradientBrush = new LinearGradientBrush(tempRect, firstColor, secondColor, angle);
493 gradientBrush = linearGradientBrush;
494 linearGradientBrush.WrapMode = WrapMode.TileFlipX;
496 else if( type == GradientStyle.VerticalCenter )
498 // Resize and wrap gradient
499 tempRect.Width = tempRect.Width / 2F;
500 LinearGradientBrush linearGradientBrush = new LinearGradientBrush(tempRect, firstColor, secondColor, angle);
501 gradientBrush = linearGradientBrush;
502 linearGradientBrush.WrapMode = WrapMode.TileFlipX;
506 gradientBrush = new LinearGradientBrush( rectangle, firstColor, secondColor, angle );
508 return gradientBrush;
511 // *******************************************
512 // Gradient is not linear : From Center.
513 // *******************************************
516 GraphicsPath path = new GraphicsPath();
518 // Add a rectangle to the path
519 path.AddRectangle( rectangle );
521 // Create a gradient brush
522 PathGradientBrush pathGradientBrush = new PathGradientBrush(path);
523 gradientBrush = pathGradientBrush;
525 // Set the center color
526 pathGradientBrush.CenterColor = firstColor;
528 // Set the Surround color
529 Color[] colors = {secondColor};
530 pathGradientBrush.SurroundColors = colors;
537 return gradientBrush;
541 /// This method creates a gradient brush for pie. This gradient is one
542 /// of the types used only with pie and doughnut.
544 /// <param name="rectangle">A rectangle which has to be filled with a gradient color</param>
545 /// <param name="firstColor">First color</param>
546 /// <param name="secondColor">Second color</param>
547 /// <returns>Gradient Brush</returns>
548 internal Brush GetPieGradientBrush(
549 RectangleF rectangle,
554 // Create a path that consists of a single ellipse.
555 GraphicsPath path = new GraphicsPath();
556 path.AddEllipse( rectangle );
558 // Use the path to construct a brush.
559 PathGradientBrush gradientBrush = new PathGradientBrush(path);
561 // Set the color at the center of the path.
562 gradientBrush.CenterColor = firstColor;
564 // Set the color along the entire boundary
565 // of the path to aqua.
566 Color[] colors = {secondColor};
568 gradientBrush.SurroundColors = colors;
575 return gradientBrush;
580 /// Converts GDI+ line style to Chart Graph line style.
582 /// <param name="style">Chart Line style.</param>
583 /// <returns>GDI+ line style.</returns>
584 internal DashStyle GetPenStyle( ChartDashStyle style )
586 // Convert to chart line styles. The custom style doesn
\92t exist.
589 case ChartDashStyle.Dash:
590 return DashStyle.Dash;
591 case ChartDashStyle.DashDot:
592 return DashStyle.DashDot;
593 case ChartDashStyle.DashDotDot:
594 return DashStyle.DashDotDot;
595 case ChartDashStyle.Dot:
596 return DashStyle.Dot;
599 return DashStyle.Solid;
607 /// Creates polygon for multi-corner star marker.
609 /// <param name="rect">Marker rectangle.</param>
610 /// <param name="numberOfCorners">Number of corners (4 and up).</param>
611 /// <returns>Array of points.</returns>
612 internal PointF[] CreateStarPolygon(RectangleF rect, int numberOfCorners)
614 int numberOfCornersX2;
617 numberOfCornersX2 = numberOfCorners * 2;
621 PointF[] points = new PointF[numberOfCornersX2];
622 PointF[] tempPoints = new PointF[1];
624 for (int pointIndex = 0; pointIndex < numberOfCornersX2; pointIndex++)
626 tempPoints[0] = new PointF(rect.X + rect.Width/2f, (outside == true) ? rect.Y : rect.Y + rect.Height/4f);
627 Matrix matrix = new Matrix();
628 matrix.RotateAt(pointIndex*(360f/(numberOfCorners*2f)), new PointF(rect.X + rect.Width/2f, rect.Y + rect.Height/2f));
629 matrix.TransformPoints(tempPoints);
630 points[pointIndex] = tempPoints[0];
638 /// Draw marker using relative coordinates of the center.
640 /// <param name="point">Coordinates of the center.</param>
641 /// <param name="markerStyle">Marker style.</param>
642 /// <param name="markerSize">Marker size.</param>
643 /// <param name="markerColor">Marker color.</param>
644 /// <param name="markerBorderColor">Marker border color.</param>
645 /// <param name="markerBorderSize">Marker border size.</param>
646 /// <param name="markerImage">Marker image name.</param>
647 /// <param name="markerImageTransparentColor">Marker image transparent color.</param>
648 /// <param name="shadowSize">Marker shadow size.</param>
649 /// <param name="shadowColor">Marker shadow color.</param>
650 /// <param name="imageScaleRect">Rectangle to which marker image should be scaled.</param>
651 internal void DrawMarkerRel(
653 MarkerStyle markerStyle,
656 Color markerBorderColor,
657 int markerBorderSize,
659 Color markerImageTransparentColor,
662 RectangleF imageScaleRect
665 DrawMarkerAbs(this.GetAbsolutePoint(point), markerStyle, markerSize, markerColor, markerBorderColor, markerBorderSize, markerImage, markerImageTransparentColor, shadowSize, shadowColor, imageScaleRect, false);
669 /// Draw marker using absolute coordinates of the center.
671 /// <param name="point">Coordinates of the center.</param>
672 /// <param name="markerStyle">Marker style.</param>
673 /// <param name="markerSize">Marker size.</param>
674 /// <param name="markerColor">Marker color.</param>
675 /// <param name="markerBorderColor">Marker border color.</param>
676 /// <param name="markerBorderSize">Marker border size.</param>
677 /// <param name="markerImage">Marker image name.</param>
678 /// <param name="markerImageTransparentColor">Marker image transparent color.</param>
679 /// <param name="shadowSize">Marker shadow size.</param>
680 /// <param name="shadowColor">Marker shadow color.</param>
681 /// <param name="imageScaleRect">Rectangle to which marker image should be scaled.</param>
682 /// <param name="forceAntiAlias">Always use anti aliasing when drawing the marker.</param>
683 internal void DrawMarkerAbs(
685 MarkerStyle markerStyle,
688 Color markerBorderColor,
689 int markerBorderSize,
691 Color markerImageTransparentColor,
694 RectangleF imageScaleRect,
698 // Hide border when zero width specified
699 if(markerBorderSize <= 0)
701 markerBorderColor = Color.Transparent;
704 // Draw image instead of standart markers
705 if(markerImage.Length > 0)
708 System.Drawing.Image image = _common.ImageLoader.LoadImage( markerImage );
712 // Calculate image rectangle
713 RectangleF rect = RectangleF.Empty;
714 if (imageScaleRect == RectangleF.Empty)
716 SizeF size = new SizeF();
717 ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref size);
718 imageScaleRect.Width = size.Width;
719 imageScaleRect.Height = size.Height;
722 rect.X = point.X - imageScaleRect.Width / 2F;
723 rect.Y = point.Y - imageScaleRect.Height / 2F;
724 rect.Width = imageScaleRect.Width;
725 rect.Height = imageScaleRect.Height;
727 // Prepare image properties (transparent color)
728 ImageAttributes attrib = new ImageAttributes();
729 if (markerImageTransparentColor != Color.Empty)
731 attrib.SetColorKey(markerImageTransparentColor, markerImageTransparentColor, ColorAdjustType.Default);
735 if (shadowSize != 0 && shadowColor != Color.Empty)
737 ImageAttributes attribShadow = new ImageAttributes();
738 attribShadow.SetColorKey(markerImageTransparentColor, markerImageTransparentColor, ColorAdjustType.Default);
739 ColorMatrix colorMatrix = new ColorMatrix();
740 colorMatrix.Matrix00 = 0.25f; // Red
741 colorMatrix.Matrix11 = 0.25f; // Green
742 colorMatrix.Matrix22 = 0.25f; // Blue
743 colorMatrix.Matrix33 = 0.5f; // alpha
744 colorMatrix.Matrix44 = 1.0f; // w
745 attribShadow.SetColorMatrix(colorMatrix);
747 this.DrawImage(image,
748 new Rectangle((int)rect.X + shadowSize, (int)rect.Y + shadowSize, (int)rect.Width, (int)rect.Height),
749 0, 0, image.Width, image.Height,
755 this.DrawImage(image,
756 new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height),
757 0, 0, image.Width, image.Height,
763 // Draw standart marker using style, size and color
764 else if(markerStyle != MarkerStyle.None && markerSize > 0 && markerColor != Color.Empty)
766 // Enable antialising
767 SmoothingMode oldSmoothingMode = this.SmoothingMode;
770 this.SmoothingMode = SmoothingMode.AntiAlias;
773 // Create solid color brush
774 using (SolidBrush brush = new SolidBrush(markerColor))
776 // Calculate marker rectangle
777 RectangleF rect = RectangleF.Empty;
778 rect.X = point.X - ((float)markerSize) / 2F;
779 rect.Y = point.Y - ((float)markerSize) / 2F;
780 rect.Width = markerSize;
781 rect.Height = markerSize;
783 // Draw marker depending on style
786 case (MarkerStyle.Star4):
787 case (MarkerStyle.Star5):
788 case (MarkerStyle.Star6):
789 case (MarkerStyle.Star10):
791 // Set number of corners
792 int cornerNumber = 4;
793 if (markerStyle == MarkerStyle.Star5)
797 else if (markerStyle == MarkerStyle.Star6)
801 else if (markerStyle == MarkerStyle.Star10)
807 PointF[] points = CreateStarPolygon(rect, cornerNumber);
810 if (shadowSize != 0 && shadowColor != Color.Empty)
812 Matrix translateMatrix = this.Transform.Clone();
813 translateMatrix.Translate(shadowSize, shadowSize);
814 Matrix oldMatrix = this.Transform;
815 this.Transform = translateMatrix;
817 this.FillPolygon(new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)), points);
819 this.Transform = oldMatrix;
823 this.FillPolygon(brush, points);
824 this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
827 case (MarkerStyle.Circle):
829 // Draw marker shadow
830 if (shadowSize != 0 && shadowColor != Color.Empty)
834 using (SolidBrush shadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
836 RectangleF shadowRect = rect;
837 shadowRect.X += shadowSize;
838 shadowRect.Y += shadowSize;
839 this.FillEllipse(shadowBrush, shadowRect);
844 // Add circle to the graphics path
845 using (GraphicsPath path = new GraphicsPath())
847 path.AddEllipse(rect.X + shadowSize - 1, rect.Y + shadowSize - 1, rect.Width + 2, rect.Height + 2);
850 using (PathGradientBrush shadowBrush = new PathGradientBrush(path))
852 shadowBrush.CenterColor = shadowColor;
854 // Set the color along the entire boundary of the path
855 Color[] colors = { Color.Transparent };
856 shadowBrush.SurroundColors = colors;
857 shadowBrush.CenterPoint = new PointF(point.X, point.Y);
859 // Define brush focus scale
860 PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
861 if (focusScale.X < 0)
865 if (focusScale.Y < 0)
869 shadowBrush.FocusScales = focusScale;
872 this.FillPath(shadowBrush, path);
878 this.FillEllipse(brush, rect);
879 this.DrawEllipse(new Pen(markerBorderColor, markerBorderSize), rect);
882 case (MarkerStyle.Square):
884 // Draw marker shadow
885 if (shadowSize != 0 && shadowColor != Color.Empty)
887 FillRectangleShadowAbs(rect, shadowColor, shadowSize, shadowColor);
890 this.FillRectangle(brush, rect);
891 this.DrawRectangle(new Pen(markerBorderColor, markerBorderSize), (int)Math.Round(rect.X, 0), (int)Math.Round(rect.Y, 0), (int)Math.Round(rect.Width, 0), (int)Math.Round(rect.Height, 0));
894 case (MarkerStyle.Cross):
896 // Calculate cross line width and size
897 float crossLineWidth = (float)Math.Ceiling(markerSize / 4F);
898 float crossSize = markerSize;// * (float)Math.Sin(45f/180f*Math.PI);
900 // Calculate cross coordinates
901 PointF[] points = new PointF[12];
902 points[0].X = point.X - crossSize / 2F;
903 points[0].Y = point.Y + crossLineWidth / 2F;
904 points[1].X = point.X - crossSize / 2F;
905 points[1].Y = point.Y - crossLineWidth / 2F;
907 points[2].X = point.X - crossLineWidth / 2F;
908 points[2].Y = point.Y - crossLineWidth / 2F;
909 points[3].X = point.X - crossLineWidth / 2F;
910 points[3].Y = point.Y - crossSize / 2F;
911 points[4].X = point.X + crossLineWidth / 2F;
912 points[4].Y = point.Y - crossSize / 2F;
914 points[5].X = point.X + crossLineWidth / 2F;
915 points[5].Y = point.Y - crossLineWidth / 2F;
916 points[6].X = point.X + crossSize / 2F;
917 points[6].Y = point.Y - crossLineWidth / 2F;
918 points[7].X = point.X + crossSize / 2F;
919 points[7].Y = point.Y + crossLineWidth / 2F;
921 points[8].X = point.X + crossLineWidth / 2F;
922 points[8].Y = point.Y + crossLineWidth / 2F;
923 points[9].X = point.X + crossLineWidth / 2F;
924 points[9].Y = point.Y + crossSize / 2F;
925 points[10].X = point.X - crossLineWidth / 2F;
926 points[10].Y = point.Y + crossSize / 2F;
927 points[11].X = point.X - crossLineWidth / 2F;
928 points[11].Y = point.Y + crossLineWidth / 2F;
930 // Rotate cross coordinates 45 degrees
931 Matrix rotationMatrix = new Matrix();
932 rotationMatrix.RotateAt(45, point);
933 rotationMatrix.TransformPoints(points);
936 if (shadowSize != 0 && shadowColor != Color.Empty)
938 // Create translation matrix
939 Matrix translateMatrix = this.Transform.Clone();
940 translateMatrix.Translate(
941 (softShadows) ? shadowSize + 1 : shadowSize,
942 (softShadows) ? shadowSize + 1 : shadowSize);
943 Matrix oldMatrix = this.Transform;
944 this.Transform = translateMatrix;
948 using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
950 this.FillPolygon(softShadowBrush, points);
955 // Add polygon to the graphics path
956 using (GraphicsPath path = new GraphicsPath())
958 path.AddPolygon(points);
961 using (PathGradientBrush shadowBrush = new PathGradientBrush(path))
963 shadowBrush.CenterColor = shadowColor;
965 // Set the color along the entire boundary of the path
966 Color[] colors = { Color.Transparent };
967 shadowBrush.SurroundColors = colors;
968 shadowBrush.CenterPoint = new PointF(point.X, point.Y);
970 // Define brush focus scale
971 PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
972 if (focusScale.X < 0)
976 if (focusScale.Y < 0)
980 shadowBrush.FocusScales = focusScale;
983 this.FillPath(shadowBrush, path);
988 this.Transform = oldMatrix;
991 // Create translation matrix
992 Matrix translateMatrixShape = this.Transform.Clone();
993 Matrix oldMatrixShape = this.Transform;
994 this.Transform = translateMatrixShape;
996 this.FillPolygon(brush, points);
997 this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
999 this.Transform = oldMatrixShape;
1003 case (MarkerStyle.Diamond):
1005 PointF[] points = new PointF[4];
1006 points[0].X = rect.X;
1007 points[0].Y = rect.Y + rect.Height / 2F;
1008 points[1].X = rect.X + rect.Width / 2F;
1009 points[1].Y = rect.Top;
1010 points[2].X = rect.Right;
1011 points[2].Y = rect.Y + rect.Height / 2F;
1012 points[3].X = rect.X + rect.Width / 2F;
1013 points[3].Y = rect.Bottom;
1016 if (shadowSize != 0 && shadowColor != Color.Empty)
1018 Matrix translateMatrix = this.Transform.Clone();
1019 translateMatrix.Translate((softShadows) ? 0 : shadowSize,
1020 (softShadows) ? 0 : shadowSize);
1021 Matrix oldMatrix = this.Transform;
1022 this.Transform = translateMatrix;
1026 using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
1028 this.FillPolygon(softShadowBrush, points);
1033 // Calculate diamond size
1034 float diamondSize = markerSize * (float)Math.Sin(45f / 180f * Math.PI);
1036 // Calculate diamond rectangle position
1037 RectangleF diamondRect = RectangleF.Empty;
1038 diamondRect.X = point.X - ((float)diamondSize) / 2F;
1039 diamondRect.Y = point.Y - ((float)diamondSize) / 2F - shadowSize;
1040 diamondRect.Width = diamondSize;
1041 diamondRect.Height = diamondSize;
1043 // Set rotation matrix to 45
1044 translateMatrix.RotateAt(45, point);
1045 this.Transform = translateMatrix;
1047 FillRectangleShadowAbs(diamondRect, shadowColor, shadowSize, shadowColor);
1051 this.Transform = oldMatrix;
1054 this.FillPolygon(brush, points);
1055 this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
1058 case (MarkerStyle.Triangle):
1060 PointF[] points = new PointF[3];
1061 points[0].X = rect.X;
1062 points[0].Y = rect.Bottom;
1063 points[1].X = rect.X + rect.Width / 2F;
1064 points[1].Y = rect.Top;
1065 points[2].X = rect.Right;
1066 points[2].Y = rect.Bottom;
1068 // Draw image shadow
1069 if (shadowSize != 0 && shadowColor != Color.Empty)
1071 Matrix translateMatrix = this.Transform.Clone();
1072 translateMatrix.Translate((softShadows) ? shadowSize - 1 : shadowSize,
1073 (softShadows) ? shadowSize + 1 : shadowSize);
1074 Matrix oldMatrix = this.Transform;
1075 this.Transform = translateMatrix;
1079 using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
1081 this.FillPolygon(softShadowBrush, points);
1086 // Add polygon to the graphics path
1087 GraphicsPath path = new GraphicsPath();
1088 path.AddPolygon(points);
1090 // Create path brush
1091 PathGradientBrush shadowBrush = new PathGradientBrush(path);
1092 shadowBrush.CenterColor = shadowColor;
1094 // Set the color along the entire boundary of the path
1095 Color[] colors = { Color.Transparent };
1096 shadowBrush.SurroundColors = colors;
1097 shadowBrush.CenterPoint = new PointF(point.X, point.Y);
1099 // Define brush focus scale
1100 PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
1101 if (focusScale.X < 0)
1105 if (focusScale.Y < 0)
1109 shadowBrush.FocusScales = focusScale;
1112 this.FillPath(shadowBrush, path);
1115 this.Transform = oldMatrix;
1118 this.FillPolygon(brush, points);
1119 this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
1124 throw (new InvalidOperationException(SR.ExceptionGraphicsMarkerStyleUnknown));
1129 // Restore SmoothingMode
1132 this.SmoothingMode = oldSmoothingMode;
1139 #region String Methods
1142 /// Measures the specified string when drawn with the specified
1143 /// Font object and formatted with the specified StringFormat object.
1145 /// <param name="text">String to measure.</param>
1146 /// <param name="font">Font object defines the text format of the string.</param>
1147 /// <param name="layoutArea">SizeF structure that specifies the maximum layout area for the text.</param>
1148 /// <param name="stringFormat">StringFormat object that represents formatting information, such as line spacing, for the string.</param>
1149 /// <param name="textOrientation">Text orientation.</param>
1150 /// <returns>This method returns a SizeF structure that represents the size, in pixels, of the string specified in the text parameter as drawn with the font parameter and the stringFormat parameter.</returns>
1151 internal SizeF MeasureString(
1155 StringFormat stringFormat,
1156 TextOrientation textOrientation
1159 // Current implementation of the stacked text will simply insert a new
1160 // line character between all characters in the original string. This
1161 // apporach will not allow to show multiple lines of stacked text or
1162 // correctly handle text wrapping.
1163 if (textOrientation == TextOrientation.Stacked)
1165 text = GetStackedText(text);
1167 return this.MeasureString(text, font, layoutArea, stringFormat);
1171 /// Measures the specified text string when drawn with
1172 /// the specified Font object and formatted with the
1173 /// specified StringFormat object.
1175 /// <param name="text">The string to measure</param>
1176 /// <param name="font">The Font object used to determine the size of the text string. </param>
1177 /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
1178 /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
1179 /// <param name="textOrientation">Text orientation.</param>
1180 /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
1181 internal SizeF MeasureStringRel(
1185 StringFormat stringFormat,
1186 TextOrientation textOrientation)
1188 // Current implementation of the stacked text will simply insert a new
1189 // line character between all characters in the original string. This
1190 // apporach will not allow to show multiple lines of stacked text or
1191 // correctly handle text wrapping.
1192 if (textOrientation == TextOrientation.Stacked)
1194 text = GetStackedText(text);
1196 return this.MeasureStringRel(text, font, layoutArea, stringFormat);
1200 /// Draws the specified text string at the specified location with the specified Brush and Font objects using the formatting properties of the specified StringFormat object.
1202 /// <param name="text">String to draw.</param>
1203 /// <param name="font">Font object that defines the text format of the string.</param>
1204 /// <param name="brush">Brush object that determines the color and texture of the drawn text.</param>
1205 /// <param name="rect">Position of the drawn text in pixels.</param>
1206 /// <param name="format">StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
1207 /// <param name="textOrientation">Text orientation.</param>
1208 internal void DrawString(
1213 StringFormat format,
1214 TextOrientation textOrientation
1217 // Current implementation of the stacked text will simply insert a new
1218 // line character between all characters in the original string. This
1219 // apporach will not allow to show multiple lines of stacked text or
1220 // correctly handle text wrapping.
1221 if (textOrientation == TextOrientation.Stacked)
1223 text = GetStackedText(text);
1225 this.DrawString(text, font, brush, rect, format);
1231 /// <param name="text">Text.</param>
1232 /// <param name="font">Text Font.</param>
1233 /// <param name="brush">Text Brush.</param>
1234 /// <param name="position">Text Position.</param>
1235 /// <param name="format">Format and text alignment.</param>
1236 /// <param name="angle">Text angle.</param>
1237 /// <param name="textOrientation">Text orientation.</param>
1238 internal void DrawStringRel(
1240 System.Drawing.Font font,
1241 System.Drawing.Brush brush,
1243 System.Drawing.StringFormat format,
1245 TextOrientation textOrientation
1248 // Current implementation of the stacked text will simply insert a new
1249 // line character between all characters in the original string. This
1250 // apporach will not allow to show multiple lines of stacked text or
1251 // correctly handle text wrapping.
1252 if (textOrientation == TextOrientation.Stacked)
1254 text = GetStackedText(text);
1257 this.DrawStringRel(text, font, brush, position, format, angle);
1263 /// <param name="text">Text.</param>
1264 /// <param name="font">Text Font.</param>
1265 /// <param name="brush">Text Brush.</param>
1266 /// <param name="position">Text Position.</param>
1267 /// <param name="format">Format and text alignment.</param>
1268 /// <param name="textOrientation">Text orientation.</param>
1269 internal void DrawStringRel(
1271 System.Drawing.Font font,
1272 System.Drawing.Brush brush,
1273 RectangleF position,
1274 System.Drawing.StringFormat format,
1275 TextOrientation textOrientation
1278 // Current implementation of the stacked text will simply insert a new
1279 // line character between all characters in the original string. This
1280 // apporach will not allow to show multiple lines of stacked text or
1281 // correctly handle text wrapping.
1282 if (textOrientation == TextOrientation.Stacked)
1284 text = GetStackedText(text);
1287 this.DrawStringRel(text, font, brush, position, format);
1291 /// Function returned stacked text by inserting new line characters between
1292 /// all characters in the original string.
1294 /// <param name="text">Original text.</param>
1295 /// <returns>Stacked text.</returns>
1296 internal static string GetStackedText(string text)
1298 string result = string.Empty;
1299 foreach (char ch in text)
1311 /// Draw a string and fills it's background
1313 /// <param name="common">The Common elements object.</param>
1314 /// <param name="text">Text.</param>
1315 /// <param name="font">Text Font.</param>
1316 /// <param name="brush">Text Brush.</param>
1317 /// <param name="position">Text Position.</param>
1318 /// <param name="format">Format and text alignment.</param>
1319 /// <param name="angle">Text angle.</param>
1320 /// <param name="backPosition">Text background position.</param>
1321 /// <param name="backColor">Back Color</param>
1322 /// <param name="borderColor">Border Color</param>
1323 /// <param name="borderWidth">Border Width</param>
1324 /// <param name="borderDashStyle">Border Style</param>
1325 /// <param name="series">Series</param>
1326 /// <param name="point">Point</param>
1327 /// <param name="pointIndex">Point index in series</param>
1328 internal void DrawPointLabelStringRel(
1329 CommonElements common,
1331 System.Drawing.Font font,
1332 System.Drawing.Brush brush,
1333 RectangleF position,
1334 System.Drawing.StringFormat format,
1336 RectangleF backPosition,
1340 ChartDashStyle borderDashStyle,
1345 // Start Svg/Flash Selection mode
1346 this.StartHotRegion( point, true );
1349 DrawPointLabelBackground(
1362 // End Svg/Flash Selection mode
1363 this.EndHotRegion( );
1365 point._lastLabelText = text;
1369 // datapoint label alignments should appear as not RTL.
1370 using (StringFormat fmt = (StringFormat)format.Clone())
1372 if (fmt.Alignment == StringAlignment.Far)
1374 fmt.Alignment = StringAlignment.Near;
1376 else if (fmt.Alignment == StringAlignment.Near)
1378 fmt.Alignment = StringAlignment.Far;
1380 DrawStringRel(text,font,brush,position,fmt,angle);
1384 DrawStringRel(text, font, brush, position, format, angle);
1388 /// Draw a string and fills it's background
1390 /// <param name="common">The Common elements object.</param>
1391 /// <param name="text">Text.</param>
1392 /// <param name="font">Text Font.</param>
1393 /// <param name="brush">Text Brush.</param>
1394 /// <param name="position">Text Position.</param>
1395 /// <param name="format">Format and text alignment.</param>
1396 /// <param name="angle">Text angle.</param>
1397 /// <param name="backPosition">Text background position.</param>
1398 /// <param name="backColor">Back Color</param>
1399 /// <param name="borderColor">Border Color</param>
1400 /// <param name="borderWidth">Border Width</param>
1401 /// <param name="borderDashStyle">Border Style</param>
1402 /// <param name="series">Series</param>
1403 /// <param name="point">Point</param>
1404 /// <param name="pointIndex">Point index in series</param>
1405 internal void DrawPointLabelStringRel(
1406 CommonElements common,
1408 System.Drawing.Font font,
1409 System.Drawing.Brush brush,
1411 System.Drawing.StringFormat format,
1413 RectangleF backPosition,
1417 ChartDashStyle borderDashStyle,
1422 // Start Svg/Flash Selection mode
1423 this.StartHotRegion( point, true );
1426 DrawPointLabelBackground(
1439 // End Svg/Flash Selection mode
1440 this.EndHotRegion( );
1442 point._lastLabelText = text;
1446 // datapoint label alignments should appear as not RTL
1447 using (StringFormat fmt = (StringFormat)format.Clone())
1449 if (fmt.Alignment == StringAlignment.Far)
1451 fmt.Alignment = StringAlignment.Near;
1453 else if (fmt.Alignment == StringAlignment.Near)
1455 fmt.Alignment = StringAlignment.Far;
1457 DrawStringRel(text,font,brush,position,fmt,angle);
1461 DrawStringRel(text,font,brush,position,format,angle);
1465 /// Draw a string and fills it's background
1467 /// <param name="common">The Common elements object.</param>
1468 /// <param name="angle">Text angle.</param>
1469 /// <param name="textPosition">Text position.</param>
1470 /// <param name="backPosition">Text background position.</param>
1471 /// <param name="backColor">Back Color</param>
1472 /// <param name="borderColor">Border Color</param>
1473 /// <param name="borderWidth">Border Width</param>
1474 /// <param name="borderDashStyle">Border Style</param>
1475 /// <param name="series">Series</param>
1476 /// <param name="point">Point</param>
1477 /// <param name="pointIndex">Point index in series</param>
1478 private void DrawPointLabelBackground(
1479 CommonElements common,
1481 PointF textPosition,
1482 RectangleF backPosition,
1486 ChartDashStyle borderDashStyle,
1492 if(!backPosition.IsEmpty)
1494 RectangleF backPositionAbs = this.Round(this.GetAbsoluteRectangle(backPosition));
1496 // Get rotation point
1497 PointF rotationPoint = PointF.Empty;
1498 if(textPosition.IsEmpty)
1500 rotationPoint = new PointF(backPositionAbs.X + backPositionAbs.Width/2f, backPositionAbs.Y + backPositionAbs.Height/2f);
1504 rotationPoint = this.GetAbsolutePoint(textPosition);
1507 // Create a matrix and rotate it.
1508 _myMatrix = this.Transform.Clone();
1509 _myMatrix.RotateAt( angle, rotationPoint );
1512 GraphicsState graphicsState = this.Save();
1514 // Set transformatino
1515 this.Transform = _myMatrix;
1517 // Check for empty colors
1518 if( !backColor.IsEmpty ||
1519 !borderColor.IsEmpty)
1521 // Fill box around the label
1522 using(Brush brush = new SolidBrush(backColor))
1524 this.FillRectangle(brush, backPositionAbs);
1527 // deliant: Fix VSTS #156433 (2) Data Label Border in core always shows when the style is set to NotSet
1529 if( borderWidth > 0 &&
1530 !borderColor.IsEmpty && borderDashStyle != ChartDashStyle.NotSet)
1532 AntiAliasingStyles saveAntiAliasing = this.AntiAliasing;
1535 this.AntiAliasing = AntiAliasingStyles.None;
1536 using(Pen pen = new Pen(borderColor, borderWidth))
1538 pen.DashStyle = GetPenStyle( borderDashStyle );
1543 backPositionAbs.Width,
1544 backPositionAbs.Height);
1549 this.AntiAliasing = saveAntiAliasing;
1555 // Draw invisible rectangle to handle tooltips
1556 using(Brush brush = new SolidBrush(Color.Transparent))
1558 this.FillRectangle(brush, backPositionAbs);
1563 // Restore old state
1564 this.Restore(graphicsState);
1566 // Add point label hot region
1567 if( common != null &&
1568 common.ProcessModeRegions)
1570 #if !Microsoft_CONTROL
1571 // Remember all point attributes
1572 string oldToolTip = point.IsCustomPropertySet( CommonCustomProperties.ToolTip) ? point.ToolTip : null;
1573 string oldUrl = point.IsCustomPropertySet( CommonCustomProperties.Url) ? point.Url : null;
1574 string oldMapAreaAttributes = point.IsCustomPropertySet( CommonCustomProperties.MapAreaAttributes) ? point.MapAreaAttributes : null;
1575 string oldPostback = point.IsCustomPropertySet( CommonCustomProperties.PostBackValue) ? point.PostBackValue : null;
1576 object oldTag = point.Tag;
1577 // Set label attributes into the point attribute.
1578 // Workaround for the AddHotRegion method limitation.
1579 point.ToolTip = point.LabelToolTip;
1580 point.Url = point.LabelUrl;
1581 point.MapAreaAttributes = point.LabelMapAreaAttributes;
1582 point.PostBackValue = point.PostBackValue;
1583 #endif // !Microsoft_CONTROL
1588 common.HotRegionsList.AddHotRegion(
1596 // Convert rectangle to the graphics path and apply rotation transformation
1597 using (GraphicsPath path = new GraphicsPath())
1599 path.AddRectangle(backPositionAbs);
1600 path.Transform(_myMatrix);
1603 common.HotRegionsList.AddHotRegion(
1613 #if !Microsoft_CONTROL
1614 // Restore all point attributes
1615 if (oldToolTip != null) point.ToolTip = oldToolTip; else point.ResetToolTip();
1616 if (oldUrl != null) point.Url = oldUrl; else point.ResetUrl();
1617 if (oldMapAreaAttributes != null) point.MapAreaAttributes = oldMapAreaAttributes; else point.ResetMapAreaAttributes();
1618 if (oldPostback != null) point.PostBackValue = oldPostback; else point.ResetPostBackValue();
1620 #endif // !Microsoft_CONTROL
1622 // Set new hot region element type
1623 if (common.HotRegionsList.List != null && common.HotRegionsList.List.Count > 0)
1625 ((HotRegion)common.HotRegionsList.List[common.HotRegionsList.List.Count - 1]).Type =
1626 ChartElementType.DataPointLabel;
1635 /// <param name="text">Text.</param>
1636 /// <param name="font">Text Font.</param>
1637 /// <param name="brush">Text Brush.</param>
1638 /// <param name="position">Text Position.</param>
1639 /// <param name="format">Format and text alignment.</param>
1640 /// <param name="angle">Text angle.</param>
1641 internal void DrawStringRel(
1643 System.Drawing.Font font,
1644 System.Drawing.Brush brush,
1646 System.Drawing.StringFormat format,
1654 GetAbsolutePoint(position),
1662 /// <param name="text">Text.</param>
1663 /// <param name="font">Text Font.</param>
1664 /// <param name="brush">Text Brush.</param>
1665 /// <param name="absPosition">Text Position.</param>
1666 /// <param name="format">Format and text alignment.</param>
1667 /// <param name="angle">Text angle.</param>
1668 internal void DrawStringAbs(
1670 System.Drawing.Font font,
1671 System.Drawing.Brush brush,
1673 System.Drawing.StringFormat format,
1677 // Create a matrix and rotate it.
1678 _myMatrix = this.Transform.Clone();
1679 _myMatrix.RotateAt(angle, absPosition);
1682 GraphicsState graphicsState = this.Save();
1685 this.Transform = _myMatrix;
1687 // Draw text with anti-aliasing
1689 if( (AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
1690 this.TextRenderingHint = TextRenderingHint.AntiAlias;
1692 this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
1696 this.DrawString( text, font, brush, absPosition , format );
1698 // Restore old state
1699 this.Restore(graphicsState);
1703 /// This method is used by the axis title hot region generation code.
1704 /// It transforms the centered rectangle the same way as the Axis title text.
1706 /// <param name="center">Title center</param>
1707 /// <param name="size">Title text size</param>
1708 /// <param name="angle">Title rotation angle</param>
1709 /// <returns></returns>
1710 internal GraphicsPath GetTranformedTextRectPath(PointF center, SizeF size, int angle)
1712 // Text hot area is 10px greater than the size of text
1716 // Get the absolute center and create the centered rectangle points
1717 PointF absCenter = GetAbsolutePoint(center);
1718 PointF[] points = new PointF[] {
1719 new PointF(absCenter.X - size.Width / 2f, absCenter.Y - size.Height / 2f),
1720 new PointF(absCenter.X + size.Width / 2f, absCenter.Y - size.Height / 2f),
1721 new PointF(absCenter.X + size.Width / 2f, absCenter.Y + size.Height / 2f),
1722 new PointF(absCenter.X - size.Width / 2f, absCenter.Y + size.Height / 2f)};
1724 //Prepare the same tranformation matrix as used for the axis title
1725 Matrix matrix = this.Transform.Clone();
1726 matrix.RotateAt(angle, absCenter);
1727 //Tranform the rectangle points
1728 matrix.TransformPoints(points);
1730 //Return the path consisting of the rect points
1731 GraphicsPath path = new GraphicsPath();
1732 path.AddLines(points);
1733 path.CloseAllFigures();
1741 /// Draw label string.
1743 /// <param name="axis">Label axis.</param>
1744 /// <param name="labelRowIndex">Label text row index (0-10).</param>
1745 /// <param name="labelMark">Second row labels mark style.</param>
1746 /// <param name="markColor">Label mark line color.</param>
1747 /// <param name="text">Label text.</param>
1748 /// <param name="image">Label image name.</param>
1749 /// <param name="imageTransparentColor">Label image transparent color.</param>
1750 /// <param name="font">Text bont.</param>
1751 /// <param name="brush">Text brush.</param>
1752 /// <param name="position">Text position rectangle.</param>
1753 /// <param name="format">Label text format.</param>
1754 /// <param name="angle">Label text angle.</param>
1755 /// <param name="boundaryRect">Specifies the rectangle where the label text MUST be fitted.</param>
1756 /// <param name="label">Custom Label Item</param>
1757 /// <param name="truncatedLeft">Label is truncated on the left.</param>
1758 /// <param name="truncatedRight">Label is truncated on the right.</param>
1759 internal void DrawLabelStringRel(
1762 LabelMarkStyle labelMark,
1766 Color imageTransparentColor,
1767 System.Drawing.Font font,
1768 System.Drawing.Brush brush,
1769 RectangleF position,
1770 System.Drawing.StringFormat format,
1772 RectangleF boundaryRect,
1775 bool truncatedRight)
1777 Matrix oldTransform;
1778 using (StringFormat drawingFormat = (StringFormat)format.Clone())
1780 SizeF labelSize = SizeF.Empty;
1782 // Check that rectangle is not empty
1783 if (position.Width == 0 || position.Height == 0)
1788 // Find absolute position
1789 RectangleF absPosition = this.GetAbsoluteRectangle(position);
1791 // Make sure the rectangle is not empty
1792 if (absPosition.Width < 1f)
1794 absPosition.Width = 1f;
1796 if (absPosition.Height < 1f)
1798 absPosition.Height = 1f;
1802 // TESTING CODE: Shows labels rectangle position.
1803 // Rectangle rr = Rectangle.Round(absPosition);
1804 // rr.Width = (int)Math.Round(absPosition.Right) - rr.X;
1805 // rr.Height = (int)Math.Round(absPosition.Bottom) - rr.Y;
1806 // this.DrawRectangle(Pens.Red,rr.X, rr.Y, rr.Width, rr.Height);
1809 CommonElements common = axis.Common;
1810 if (common.ProcessModeRegions)
1812 common.HotRegionsList.AddHotRegion(Rectangle.Round(absPosition), label, ChartElementType.AxisLabels, false, true);
1815 //********************************************************************
1816 //** Draw labels in the second row
1817 //********************************************************************
1818 if (labelRowIndex > 0)
1820 drawingFormat.LineAlignment = StringAlignment.Center;
1821 drawingFormat.Alignment = StringAlignment.Center;
1824 if (axis.AxisPosition == AxisPosition.Left)
1828 else if (axis.AxisPosition == AxisPosition.Right)
1832 else if (axis.AxisPosition == AxisPosition.Top)
1835 else if (axis.AxisPosition == AxisPosition.Bottom)
1840 //********************************************************************
1841 //** Calculate rotation point
1842 //********************************************************************
1843 PointF rotationPoint = PointF.Empty;
1844 if (axis.AxisPosition == AxisPosition.Left)
1846 rotationPoint.X = absPosition.Right;
1847 rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
1849 else if (axis.AxisPosition == AxisPosition.Right)
1851 rotationPoint.X = absPosition.Left;
1852 rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
1854 else if (axis.AxisPosition == AxisPosition.Top)
1856 rotationPoint.X = absPosition.X + absPosition.Width / 2F;
1857 rotationPoint.Y = absPosition.Bottom;
1859 else if (axis.AxisPosition == AxisPosition.Bottom)
1861 rotationPoint.X = absPosition.X + absPosition.Width / 2F;
1862 rotationPoint.Y = absPosition.Top;
1865 //********************************************************************
1866 //** Adjust rectangle for horisontal axis
1867 //********************************************************************
1868 if ((axis.AxisPosition == AxisPosition.Top || axis.AxisPosition == AxisPosition.Bottom) &&
1871 // Get rectangle center
1872 rotationPoint.X = absPosition.X + absPosition.Width / 2F;
1873 rotationPoint.Y = (axis.AxisPosition == AxisPosition.Top) ? absPosition.Bottom : absPosition.Y;
1875 // Rotate rectangle 90 degrees
1876 RectangleF newRect = RectangleF.Empty;
1877 newRect.X = absPosition.X + absPosition.Width / 2F;
1878 newRect.Y = absPosition.Y - absPosition.Width / 2F;
1879 newRect.Height = absPosition.Width;
1880 newRect.Width = absPosition.Height;
1882 // Adjust values for bottom axis
1883 if (axis.AxisPosition == AxisPosition.Bottom)
1887 newRect.X -= newRect.Width;
1890 // Replace string alignment
1891 drawingFormat.Alignment = StringAlignment.Near;
1894 drawingFormat.Alignment = StringAlignment.Far;
1896 drawingFormat.LineAlignment = StringAlignment.Center;
1899 // Adjust values for bottom axis
1900 if (axis.AxisPosition == AxisPosition.Top)
1902 newRect.Y += absPosition.Height;
1905 newRect.X -= newRect.Width;
1908 // Replace string alignment
1909 drawingFormat.Alignment = StringAlignment.Far;
1912 drawingFormat.Alignment = StringAlignment.Near;
1914 drawingFormat.LineAlignment = StringAlignment.Center;
1917 // Set new label rect
1918 absPosition = newRect;
1921 //********************************************************************
1922 //** 90 degrees is a special case for vertical axes
1923 //********************************************************************
1924 if ((axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right) &&
1925 (angle == 90 || angle == -90))
1927 // Get rectangle center
1928 rotationPoint.X = absPosition.X + absPosition.Width / 2F;
1929 rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
1931 // Rotate rectangle 90 degrees
1932 RectangleF newRect = RectangleF.Empty;
1933 newRect.X = rotationPoint.X - absPosition.Height / 2F;
1934 newRect.Y = rotationPoint.Y - absPosition.Width / 2F;
1935 newRect.Height = absPosition.Width;
1936 newRect.Width = absPosition.Height;
1937 absPosition = newRect;
1939 // Replace string alignment
1940 StringAlignment align = drawingFormat.Alignment;
1941 drawingFormat.Alignment = drawingFormat.LineAlignment;
1942 drawingFormat.LineAlignment = align;
1945 if (drawingFormat.LineAlignment == StringAlignment.Far)
1946 drawingFormat.LineAlignment = StringAlignment.Near;
1947 else if (drawingFormat.LineAlignment == StringAlignment.Near)
1948 drawingFormat.LineAlignment = StringAlignment.Far;
1952 if (drawingFormat.Alignment == StringAlignment.Far)
1953 drawingFormat.Alignment = StringAlignment.Near;
1954 else if (drawingFormat.Alignment == StringAlignment.Near)
1955 drawingFormat.Alignment = StringAlignment.Far;
1959 //********************************************************************
1960 //** Create a matrix and rotate it.
1961 //********************************************************************
1962 oldTransform = null;
1965 _myMatrix = this.Transform.Clone();
1966 _myMatrix.RotateAt(angle, rotationPoint);
1969 oldTransform = this.Transform;
1972 this.Transform = _myMatrix;
1975 //********************************************************************
1976 //** Measure string exact rectangle and adjust label bounding rectangle
1977 //********************************************************************
1978 RectangleF labelRect = Rectangle.Empty;
1982 // Measure text size
1983 labelSize = this.MeasureString(text.Replace("\\n", "\n"), font, absPosition.Size, drawingFormat);
1985 // Calculate text rectangle
1986 labelRect.Width = labelSize.Width;
1987 labelRect.Height = labelSize.Height;
1988 if (drawingFormat.Alignment == StringAlignment.Far)
1990 labelRect.X = absPosition.Right - labelSize.Width;
1992 else if (drawingFormat.Alignment == StringAlignment.Near)
1994 labelRect.X = absPosition.X;
1996 else if (drawingFormat.Alignment == StringAlignment.Center)
1998 labelRect.X = absPosition.X + absPosition.Width / 2F - labelSize.Width / 2F;
2001 if (drawingFormat.LineAlignment == StringAlignment.Far)
2003 labelRect.Y = absPosition.Bottom - labelSize.Height;
2005 else if (drawingFormat.LineAlignment == StringAlignment.Near)
2007 labelRect.Y = absPosition.Y;
2009 else if (drawingFormat.LineAlignment == StringAlignment.Center)
2011 labelRect.Y = absPosition.Y + absPosition.Height / 2F - labelSize.Height / 2F;
2014 //If the angle is not vertical or horizontal
2015 if (angle != 0 && angle != 90 && angle != -90)
2017 // Adjust label rectangle so it will not overlap the plotting area
2018 offsetY = (float)Math.Sin((90 - angle) / 180F * Math.PI) * labelRect.Height / 2F;
2019 offsetX = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * labelRect.Height / 2F;
2021 if (axis.AxisPosition == AxisPosition.Left)
2023 _myMatrix.Translate(-offsetX, 0);
2025 else if (axis.AxisPosition == AxisPosition.Right)
2027 _myMatrix.Translate(offsetX, 0);
2029 else if (axis.AxisPosition == AxisPosition.Top)
2031 _myMatrix.Translate(0, -offsetY);
2033 else if (axis.AxisPosition == AxisPosition.Bottom)
2035 _myMatrix.Translate(0, offsetY);
2038 // Adjust label rectangle so it will be inside boundary
2039 if (boundaryRect != RectangleF.Empty)
2041 Region region = new Region(labelRect);
2042 region.Transform(_myMatrix);
2044 // Extend boundary rectangle to the chart picture border
2045 if (axis.AxisPosition == AxisPosition.Left)
2047 boundaryRect.Width += boundaryRect.X;
2050 else if (axis.AxisPosition == AxisPosition.Right)
2052 boundaryRect.Width = this._common.Width - boundaryRect.X;
2054 else if (axis.AxisPosition == AxisPosition.Top)
2056 boundaryRect.Height += boundaryRect.Y;
2059 else if (axis.AxisPosition == AxisPosition.Bottom)
2061 boundaryRect.Height = this._common.Height - boundaryRect.Y;
2064 // Exclude boundary rectangle from the label rectangle
2065 region.Exclude(this.GetAbsoluteRectangle(boundaryRect));
2067 // If any part of the label was outside bounding rectangle
2068 if (!region.IsEmpty(Graphics))
2070 this.Transform = oldTransform;
2071 RectangleF truncateRect = region.GetBounds(Graphics);
2073 float sizeChange = truncateRect.Width / (float)Math.Cos(Math.Abs(angle) / 180F * Math.PI);
2074 if (axis.AxisPosition == AxisPosition.Left)
2076 sizeChange -= labelRect.Height * (float)Math.Tan(Math.Abs(angle) / 180F * Math.PI);
2077 absPosition.Y = labelRect.Y;
2078 absPosition.X = labelRect.X + sizeChange;
2079 absPosition.Width = labelRect.Width - sizeChange;
2080 absPosition.Height = labelRect.Height;
2082 else if (axis.AxisPosition == AxisPosition.Right)
2084 sizeChange -= labelRect.Height * (float)Math.Tan(Math.Abs(angle) / 180F * Math.PI);
2085 absPosition.Y = labelRect.Y;
2086 absPosition.X = labelRect.X;
2087 absPosition.Width = labelRect.Width - sizeChange;
2088 absPosition.Height = labelRect.Height;
2090 else if (axis.AxisPosition == AxisPosition.Top)
2092 absPosition.Y = labelRect.Y;
2093 absPosition.X = labelRect.X;
2094 absPosition.Width = labelRect.Width - sizeChange;
2095 absPosition.Height = labelRect.Height;
2098 absPosition.X += sizeChange;
2101 else if (axis.AxisPosition == AxisPosition.Bottom)
2103 absPosition.Y = labelRect.Y;
2104 absPosition.X = labelRect.X;
2105 absPosition.Width = labelRect.Width - sizeChange;
2106 absPosition.Height = labelRect.Height;
2109 absPosition.X += sizeChange;
2115 // Update transformation matrix
2116 this.Transform = _myMatrix;
2119 //********************************************************************
2120 //** Reserve space on the left for the label iamge
2121 //********************************************************************
2122 RectangleF absPositionWithoutImage = new RectangleF(absPosition.Location, absPosition.Size);
2124 System.Drawing.Image labelImage = null;
2125 SizeF imageAbsSize = new SizeF();
2127 if (image.Length > 0)
2129 labelImage = axis.Common.ImageLoader.LoadImage(label.Image);
2131 if (labelImage != null)
2133 ImageLoader.GetAdjustedImageSize(labelImage, this.Graphics, ref imageAbsSize);
2135 // Adjust label position using image size
2136 absPositionWithoutImage.Width -= imageAbsSize.Width;
2137 absPositionWithoutImage.X += imageAbsSize.Width;
2140 if (absPositionWithoutImage.Width < 1f)
2142 absPositionWithoutImage.Width = 1f;
2147 //********************************************************************
2148 //** Draw tick marks for labels in second row
2149 //********************************************************************
2150 if (labelRowIndex > 0 && labelMark != LabelMarkStyle.None)
2152 // Make sure that me know the exact size of the text
2153 labelSize = this.MeasureString(
2154 text.Replace("\\n", "\n"),
2156 absPositionWithoutImage.Size,
2159 // Adjust for label image
2160 SizeF labelSizeWithImage = new SizeF(labelSize.Width, labelSize.Height);
2161 if (labelImage != null)
2163 labelSizeWithImage.Width += imageAbsSize.Width;
2167 DrawSecondRowLabelMark(
2178 //********************************************************************
2179 //** Make sure that one line label will not disapear with LineLimit
2181 //********************************************************************
2182 if ((drawingFormat.FormatFlags & StringFormatFlags.LineLimit) != 0)
2184 // Measure string height out of one character
2185 drawingFormat.FormatFlags ^= StringFormatFlags.LineLimit;
2186 SizeF size = this.MeasureString("I", font, absPosition.Size, drawingFormat);
2188 // If height of one characte is more than rectangle heigjt - remove LineLimit flag
2189 if (size.Height < absPosition.Height)
2191 drawingFormat.FormatFlags |= StringFormatFlags.LineLimit;
2197 if ((drawingFormat.FormatFlags & StringFormatFlags.NoClip) != 0)
2199 drawingFormat.FormatFlags ^= StringFormatFlags.NoClip;
2202 // Measure string height out of one character without clipping
2203 SizeF size = this.MeasureString("I", font, absPosition.Size, drawingFormat);
2205 // Clear NoClip flag
2206 drawingFormat.FormatFlags ^= StringFormatFlags.NoClip;
2208 // If height of one characte is more than rectangle heigt - set NoClip flag
2209 if (size.Height > absPosition.Height)
2211 float delta = size.Height - absPosition.Height;
2212 absPosition.Y -= delta / 2f;
2213 absPosition.Height += delta;
2217 //********************************************************************
2219 //********************************************************************
2222 // label alignment on the axis should appear as not RTL.
2223 using (StringFormat fmt = (StringFormat)drawingFormat.Clone())
2226 if (fmt.Alignment == StringAlignment.Far)
2228 fmt.Alignment = StringAlignment.Near;
2230 else if (fmt.Alignment == StringAlignment.Near)
2232 fmt.Alignment = StringAlignment.Far;
2234 this.DrawString(text.Replace("\\n", "\n"), font, brush,
2235 absPositionWithoutImage,
2241 this.DrawString(text.Replace("\\n", "\n"), font, brush,
2242 absPositionWithoutImage,
2245 // Add separate hot region for the label
2246 if (common.ProcessModeRegions)
2248 using (GraphicsPath path = new GraphicsPath())
2250 path.AddRectangle(labelRect);
2251 path.Transform(this.Transform);
2252 string url = string.Empty;
2253 string mapAreaAttributes = string.Empty;
2254 string postbackValue = string.Empty;
2255 #if !Microsoft_CONTROL
2257 mapAreaAttributes = label.MapAreaAttributes;
2258 postbackValue = label.PostBackValue;
2259 #endif // !Microsoft_CONTROL
2260 common.HotRegionsList.AddHotRegion(
2269 ChartElementType.AxisLabels);
2273 //********************************************************************
2275 //********************************************************************
2276 if (labelImage != null)
2278 // Make sure we no the text size
2279 if (labelSize.IsEmpty)
2281 labelSize = this.MeasureString(
2282 text.Replace("\\n", "\n"),
2284 absPositionWithoutImage.Size,
2288 // Calculate image rectangle
2289 RectangleF imageRect = new RectangleF(
2290 absPosition.X + (absPosition.Width - imageAbsSize.Width - labelSize.Width) / 2,
2291 absPosition.Y + (absPosition.Height - imageAbsSize.Height) / 2,
2293 imageAbsSize.Height);
2295 if (drawingFormat.LineAlignment == StringAlignment.Center)
2297 imageRect.Y = absPosition.Y + (absPosition.Height - imageAbsSize.Height) / 2;
2299 else if (drawingFormat.LineAlignment == StringAlignment.Far)
2301 imageRect.Y = absPosition.Bottom - (labelSize.Height + imageAbsSize.Height) / 2;
2303 else if (drawingFormat.LineAlignment == StringAlignment.Near)
2305 imageRect.Y = absPosition.Top + (labelSize.Height - imageAbsSize.Height) / 2;
2308 if (drawingFormat.Alignment == StringAlignment.Center)
2310 imageRect.X = absPosition.X + (absPosition.Width - imageAbsSize.Width - labelSize.Width) / 2;
2312 else if (drawingFormat.Alignment == StringAlignment.Far)
2314 imageRect.X = absPosition.Right - imageAbsSize.Width - labelSize.Width;
2316 else if (drawingFormat.Alignment == StringAlignment.Near)
2318 imageRect.X = absPosition.X;
2321 // Create image attribute
2322 ImageAttributes attrib = new ImageAttributes();
2323 if (imageTransparentColor != Color.Empty)
2325 attrib.SetColorKey(imageTransparentColor, imageTransparentColor, ColorAdjustType.Default);
2331 Rectangle.Round(imageRect),
2332 0, 0, labelImage.Width, labelImage.Height,
2336 // Add separate hot region for the label image
2337 if (common.ProcessModeRegions)
2339 using (GraphicsPath path = new GraphicsPath())
2341 path.AddRectangle(imageRect);
2342 path.Transform(this.Transform);
2343 string imageUrl = string.Empty;
2344 string imageMapAreaAttributes = string.Empty;
2345 string postbackValue = string.Empty;
2346 #if !Microsoft_CONTROL
2347 imageUrl = label.ImageUrl;
2348 imageMapAreaAttributes = label.ImageMapAreaAttributes;
2349 postbackValue = label.PostBackValue;
2350 #endif // !Microsoft_CONTROL
2351 common.HotRegionsList.AddHotRegion(
2357 imageMapAreaAttributes,
2360 ChartElementType.AxisLabelImage);
2367 if(oldTransform != null)
2369 this.Transform = oldTransform;
2374 /// Draw box marks for the labels in second row
2376 /// <param name="axis">Axis object.</param>
2377 /// <param name="markColor">Label mark color.</param>
2378 /// <param name="absPosition">Absolute position of the text.</param>
2379 /// <param name="truncatedLeft">Label is truncated on the left.</param>
2380 /// <param name="truncatedRight">Label is truncated on the right.</param>
2381 /// <param name="originalTransform">Original transformation matrix.</param>
2382 private void DrawSecondRowLabelBoxMark(
2385 RectangleF absPosition,
2387 bool truncatedRight,
2388 Matrix originalTransform)
2390 // Remeber current and then reset original matrix
2391 Matrix curentMatrix = this.Transform;
2392 if(originalTransform != null)
2394 this.Transform = originalTransform;
2397 // Calculate center of the text rectangle
2398 PointF centerNotRound = new PointF(absPosition.X + absPosition.Width/2F, absPosition.Y + absPosition.Height/2F);
2400 // Rotate rectangle 90 degrees
2401 if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
2403 RectangleF newRect = RectangleF.Empty;
2404 newRect.X = centerNotRound.X - absPosition.Height / 2F;
2405 newRect.Y = centerNotRound.Y - absPosition.Width / 2F;
2406 newRect.Height = absPosition.Width;
2407 newRect.Width = absPosition.Height;
2408 absPosition = newRect;
2411 // Get axis position
2412 float axisPosRelative = (float)axis.GetAxisPosition(true);
2413 PointF axisPositionAbs = new PointF(axisPosRelative, axisPosRelative);
2414 axisPositionAbs = this.GetAbsolutePoint(axisPositionAbs);
2416 // Round position to achieve crisp lines with antialiasing
2417 Rectangle absPositionRounded = Rectangle.Round(absPosition);
2419 // Make sure the right and bottom position is not shifted during rounding
2420 absPositionRounded.Width = (int)Math.Round(absPosition.Right) - absPositionRounded.X;
2421 absPositionRounded.Height = (int)Math.Round(absPosition.Bottom) - absPositionRounded.Y;
2424 Pen markPen = new Pen(
2425 (markColor.IsEmpty) ? axis.MajorTickMark.LineColor : markColor,
2426 axis.MajorTickMark.LineWidth);
2429 markPen.DashStyle = GetPenStyle( axis.MajorTickMark.LineDashStyle );
2431 // Draw top/bottom lines
2432 if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
2434 this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Top, absPositionRounded.Left, absPositionRounded.Bottom);
2435 this.DrawLine(markPen, absPositionRounded.Right, absPositionRounded.Top, absPositionRounded.Right, absPositionRounded.Bottom);
2439 this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Top, absPositionRounded.Right, absPositionRounded.Top);
2440 this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Bottom, absPositionRounded.Right, absPositionRounded.Bottom);
2446 if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
2450 (axis.AxisPosition == AxisPosition.Left) ? absPositionRounded.Left : absPositionRounded.Right,
2451 absPositionRounded.Bottom,
2453 absPositionRounded.Bottom);
2459 absPositionRounded.Left,
2460 (axis.AxisPosition == AxisPosition.Top) ? absPositionRounded.Top : absPositionRounded.Bottom,
2461 absPositionRounded.Left,
2469 if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
2473 (axis.AxisPosition == AxisPosition.Left) ? absPositionRounded.Left : absPositionRounded.Right,
2474 absPositionRounded.Top,
2476 absPositionRounded.Top);
2482 absPositionRounded.Right,
2483 (axis.AxisPosition == AxisPosition.Top) ? absPositionRounded.Top : absPositionRounded.Bottom,
2484 absPositionRounded.Right,
2490 if( markPen != null )
2495 // Restore currentmatrix
2496 if(originalTransform != null)
2498 this.Transform = curentMatrix;
2504 /// Draw marks for the labels in second row
2506 /// <param name="axis">Axis object.</param>
2507 /// <param name="markColor">Label mark color.</param>
2508 /// <param name="absPosition">Absolute position of the text.</param>
2509 /// <param name="labelSize">Exact mesured size of the text.</param>
2510 /// <param name="labelMark">Label mark style to draw.</param>
2511 /// <param name="truncatedLeft">Label is truncated on the left.</param>
2512 /// <param name="truncatedRight">Label is truncated on the right.</param>
2513 /// <param name="oldTransform">Original transformation matrix.</param>
2514 private void DrawSecondRowLabelMark(
2517 RectangleF absPosition,
2519 LabelMarkStyle labelMark,
2521 bool truncatedRight,
2522 Matrix oldTransform)
2524 // Do not draw marking line if width is 0 and style or color are not set
2525 if( axis.MajorTickMark.LineWidth == 0 ||
2526 axis.MajorTickMark.LineDashStyle == ChartDashStyle.NotSet ||
2527 axis.MajorTickMark.LineColor == Color.Empty)
2532 // Remember SmoothingMode and turn off anti aliasing for
2533 // vertical or horizontal lines of the label markers.
2534 SmoothingMode oldSmoothingMode = this.SmoothingMode;
2535 this.SmoothingMode = SmoothingMode.None;
2539 if(labelMark == LabelMarkStyle.Box)
2541 DrawSecondRowLabelBoxMark(
2552 // Calculate center of the text rectangle
2553 Point center = Point.Round(new PointF(absPosition.X + absPosition.Width/2F, absPosition.Y + absPosition.Height/2F));
2555 // Round position to achieve crisp lines with antialiasing
2556 Rectangle absPositionRounded = Rectangle.Round(absPosition);
2558 // Make sure the right and bottom position is not shifted during rounding
2559 absPositionRounded.Width = (int)Math.Round(absPosition.Right) - absPositionRounded.X;
2560 absPositionRounded.Height = (int)Math.Round(absPosition.Bottom) - absPositionRounded.Y;
2563 // Arrays of points for the left and right marking lines
2564 PointF[] leftLine = new PointF[3];
2565 PointF[] rightLine = new PointF[3];
2567 // Calculate marking lines coordinates
2568 leftLine[0].X = absPositionRounded.Left;
2569 leftLine[0].Y = absPositionRounded.Bottom;
2570 leftLine[1].X = absPositionRounded.Left;
2571 leftLine[1].Y = center.Y;
2572 leftLine[2].X = (float)Math.Round((double)center.X - labelSize.Width/2F - 1F);
2573 leftLine[2].Y = center.Y;
2575 rightLine[0].X = absPositionRounded.Right;
2576 rightLine[0].Y = absPositionRounded.Bottom;
2577 rightLine[1].X = absPositionRounded.Right;
2578 rightLine[1].Y = center.Y;
2579 rightLine[2].X = (float)Math.Round((double)center.X + labelSize.Width/2F - 1F);
2580 rightLine[2].Y = center.Y;
2582 if(axis.AxisPosition == AxisPosition.Bottom)
2584 leftLine[0].Y = absPositionRounded.Top;
2585 rightLine[0].Y = absPositionRounded.Top;
2588 // Remove third point to draw only side marks
2589 if(labelMark == LabelMarkStyle.SideMark)
2591 leftLine[2] = leftLine[1];
2592 rightLine[2] = rightLine[1];
2597 leftLine[0] = leftLine[1];
2601 rightLine[0] = rightLine[1];
2605 Pen markPen = new Pen(
2606 (markColor.IsEmpty) ? axis.MajorTickMark.LineColor : markColor,
2607 axis.MajorTickMark.LineWidth);
2610 markPen.DashStyle = GetPenStyle( axis.MajorTickMark.LineDashStyle );
2612 // Draw marking lines
2613 this.DrawLines(markPen, leftLine);
2614 this.DrawLines(markPen, rightLine);
2617 if( markPen != null )
2623 // Restore previous SmoothingMode
2624 this.SmoothingMode = oldSmoothingMode;
2628 /// Measures the specified text string when drawn with
2629 /// the specified Font object and formatted with the
2630 /// specified StringFormat object.
2632 /// <param name="text">The string to measure</param>
2633 /// <param name="font">The Font object used to determine the size of the text string. </param>
2634 /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
2635 internal SizeF MeasureStringRel( string text, Font font )
2640 newSize = this.MeasureString( text, font );
2642 // Convert to relative Coordinates
2643 return GetRelativeSize( newSize );
2647 /// Measures the specified text string when drawn with
2648 /// the specified Font object and formatted with the
2649 /// specified StringFormat object.
2651 /// <param name="text">The string to measure</param>
2652 /// <param name="font">The Font object used to determine the size of the text string. </param>
2653 /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
2654 /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
2655 /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
2656 internal SizeF MeasureStringRel( string text, Font font, SizeF layoutArea, StringFormat stringFormat )
2658 SizeF size, newSize;
2660 // Get absolute coordinates
2661 size = GetAbsoluteSize( layoutArea );
2663 newSize = this.MeasureString( text, font, size, stringFormat );
2665 // Convert to relative Coordinates
2666 return GetRelativeSize( newSize );
2670 /// Measures the specified text string when drawn with
2671 /// the specified Font object and formatted with the
2672 /// specified StringFormat object.
2674 /// <param name="text">The string to measure</param>
2675 /// <param name="font">The Font object used to determine the size of the text string. </param>
2676 /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
2677 internal Size MeasureStringAbs( string text, Font font )
2680 SizeF size = this.MeasureString( text, font );
2681 return new Size( (int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));
2685 /// Measures the specified text string when drawn with
2686 /// the specified Font object and formatted with the
2687 /// specified StringFormat object.
2689 /// <param name="text">The string to measure</param>
2690 /// <param name="font">The Font object used to determine the size of the text string. </param>
2691 /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
2692 /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
2693 /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
2694 internal Size MeasureStringAbs( string text, Font font, SizeF layoutArea, StringFormat stringFormat )
2696 SizeF size = this.MeasureString( text, font, layoutArea, stringFormat );
2697 return new Size( (int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));
2701 /// Draws the specified text string at the specified location
2702 /// with the specified Brush object and font. The formatting
2703 /// properties in the specified StringFormat object are applied
2706 /// <param name="text">A string object that specifies the text to draw.</param>
2707 /// <param name="font">A Font object that specifies the font face and size with which to draw the text.</param>
2708 /// <param name="brush">A Brush object that determines the color and/or texture of the drawn text.</param>
2709 /// <param name="layoutRectangle">A RectangleF structure that specifies the location of the drawn text.</param>
2710 /// <param name="format">A StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
2711 internal void DrawStringRel( string text, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format )
2715 // Check that rectangle is not empty
2716 if(layoutRectangle.Width == 0 || layoutRectangle.Height == 0)
2721 // Get absolute coordinates
2722 rect = GetAbsoluteRectangle( layoutRectangle );
2724 // Draw text with anti-aliasing
2726 if( (this.AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
2728 this.TextRenderingHint = TextRenderingHint.AntiAlias;
2732 this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
2736 this.DrawString( text, font, brush, rect, format );
2741 /// Draws the specified text string at the specified location
2742 /// with the specified angle and with the specified Brush object and font. The
2743 /// formatting properties in the specified StringFormat object are applied
2746 /// <param name="text">A string object that specifies the text to draw.</param>
2747 /// <param name="font">A Font object that specifies the font face and size with which to draw the text.</param>
2748 /// <param name="brush">A Brush object that determines the color and/or texture of the drawn text.</param>
2749 /// <param name="layoutRectangle">A RectangleF structure that specifies the location of the drawn text.</param>
2750 /// <param name="format">A StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
2751 /// <param name="angle">A angle of the text</param>
2752 internal void DrawStringRel(
2756 RectangleF layoutRectangle,
2757 StringFormat format,
2763 Matrix oldTransform;
2764 PointF rotationCenter = PointF.Empty;
2766 // Check that rectangle is not empty
2767 if(layoutRectangle.Width == 0 || layoutRectangle.Height == 0)
2772 // Get absolute coordinates
2773 rect = GetAbsoluteRectangle( layoutRectangle );
2775 size = this.MeasureString( text, font, rect.Size, format );
2778 // Find the center of rotation
2779 if( format.Alignment == StringAlignment.Near )
2781 rotationCenter.X = rect.X + size.Width / 2;
2782 rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
2784 else if( format.Alignment == StringAlignment.Far )
2786 rotationCenter.X = rect.Right - size.Width / 2;
2787 rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
2791 rotationCenter.X = ( rect.Left + rect.Right ) / 2;
2792 rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
2794 // Create a matrix and rotate it.
2795 _myMatrix = this.Transform.Clone();
2796 _myMatrix.RotateAt( angle, rotationCenter);
2799 oldTransform = this.Transform;
2802 this.Transform = _myMatrix;
2804 // Draw text with anti-aliasing
2806 if( (AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
2808 this.TextRenderingHint = TextRenderingHint.AntiAlias;
2812 this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
2816 this.DrawString( text, font, brush, rect, format );
2819 this.Transform = oldTransform;
2824 #region Rectangle Methods
2827 /// Draws different shadows to create bar styles.
2829 /// <param name="barDrawingStyle">Bar drawing style.</param>
2830 /// <param name="isVertical">True if a vertical bar.</param>
2831 /// <param name="rect">Rectangle position.</param>
2832 internal void DrawRectangleBarStyle(BarDrawingStyle barDrawingStyle, bool isVertical, RectangleF rect)
2834 // Check if non-default bar drawing style is specified
2835 if(barDrawingStyle != BarDrawingStyle.Default)
2837 // Check column/bar size
2838 if(rect.Width > 0 && rect.Height > 0)
2841 if(barDrawingStyle == BarDrawingStyle.Cylinder)
2843 // Calculate gradient position
2844 RectangleF gradientRect = rect;
2847 gradientRect.Width *= 0.3f;
2851 gradientRect.Height *= 0.3f;
2853 if(gradientRect.Width > 0 && gradientRect.Height > 0)
2855 this.FillRectangleAbs(
2858 ChartHatchStyle.None,
2860 ChartImageWrapMode.Scaled,
2862 ChartImageAlignmentStyle.Center,
2863 (isVertical) ? GradientStyle.LeftRight : GradientStyle.TopBottom,
2864 Color.FromArgb(120, Color.White),
2867 ChartDashStyle.NotSet,
2868 PenAlignment.Inset );
2873 gradientRect.X += gradientRect.Width + 1f;
2874 gradientRect.Width = rect.Right - gradientRect.X;
2878 gradientRect.Y += gradientRect.Height + 1f;
2879 gradientRect.Height = rect.Bottom - gradientRect.Y;
2882 this.FillRectangleAbs(
2884 Color.FromArgb(120, Color.White),
2885 ChartHatchStyle.None,
2887 ChartImageWrapMode.Scaled,
2889 ChartImageAlignmentStyle.Center,
2890 (isVertical) ? GradientStyle.LeftRight : GradientStyle.TopBottom,
2891 Color.FromArgb(150, Color.Black),
2894 ChartDashStyle.NotSet,
2895 PenAlignment.Inset );
2899 else if(barDrawingStyle == BarDrawingStyle.Emboss)
2901 // Calculate width of shadows used to create the effect
2902 float shadowSize = 3f;
2903 if(rect.Width < 6f || rect.Height < 6f)
2907 else if(rect.Width < 15f || rect.Height < 15f)
2912 // Create and draw left/top path
2913 using(GraphicsPath path = new GraphicsPath())
2915 // Add shadow polygon to the path
2916 PointF[] points = new PointF[] {
2917 new PointF(rect.Left, rect.Bottom),
2918 new PointF(rect.Left, rect.Top),
2919 new PointF(rect.Right, rect.Top),
2920 new PointF(rect.Right - shadowSize, rect.Top + shadowSize),
2921 new PointF(rect.Left + shadowSize, rect.Top + shadowSize),
2922 new PointF(rect.Left + shadowSize, rect.Bottom - shadowSize) };
2923 path.AddPolygon(points);
2926 using(SolidBrush leftTopBrush = new SolidBrush(Color.FromArgb(100, Color.White)))
2928 // Fill shadow path on the left-bottom side of the bar
2929 this.FillPath(leftTopBrush, path);
2933 // Create and draw top/right path
2934 using(GraphicsPath path = new GraphicsPath())
2936 // Add shadow polygon to the path
2937 PointF[] points = new PointF[] {
2938 new PointF(rect.Right, rect.Top),
2939 new PointF(rect.Right, rect.Bottom),
2940 new PointF(rect.Left, rect.Bottom),
2941 new PointF(rect.Left + shadowSize, rect.Bottom - shadowSize),
2942 new PointF(rect.Right - shadowSize, rect.Bottom - shadowSize),
2943 new PointF(rect.Right - shadowSize, rect.Top + shadowSize) };
2944 path.AddPolygon(points);
2947 using(SolidBrush bottomRightBrush = new SolidBrush(Color.FromArgb(80, Color.Black)))
2949 // Fill shadow path on the left-bottom side of the bar
2950 this.FillPath(bottomRightBrush, path);
2954 else if(barDrawingStyle == BarDrawingStyle.LightToDark)
2956 // Calculate width of shadows used to create the effect
2957 float shadowSize = 4f;
2958 if(rect.Width < 6f || rect.Height < 6f)
2962 else if(rect.Width < 15f || rect.Height < 15f)
2967 // Calculate gradient position
2968 RectangleF gradientRect = rect;
2969 gradientRect.Inflate(-shadowSize, -shadowSize);
2972 gradientRect.Height = (float)Math.Floor(gradientRect.Height / 3f);
2976 gradientRect.X = gradientRect.Right - (float)Math.Floor(gradientRect.Width / 3f);
2977 gradientRect.Width = (float)Math.Floor(gradientRect.Width / 3f);
2979 if(gradientRect.Width > 0 && gradientRect.Height > 0)
2981 this.FillRectangleAbs(
2983 (isVertical) ? Color.FromArgb(120, Color.White) : Color.Transparent,
2984 ChartHatchStyle.None,
2986 ChartImageWrapMode.Scaled,
2988 ChartImageAlignmentStyle.Center,
2989 (isVertical) ? GradientStyle.TopBottom : GradientStyle.LeftRight,
2990 (isVertical) ? Color.Transparent : Color.FromArgb(120, Color.White),
2993 ChartDashStyle.NotSet,
2994 PenAlignment.Inset );
2996 gradientRect = rect;
2997 gradientRect.Inflate(-shadowSize, -shadowSize);
3000 gradientRect.Y = gradientRect.Bottom - (float)Math.Floor(gradientRect.Height / 3f);
3001 gradientRect.Height = (float)Math.Floor(gradientRect.Height / 3f);
3005 gradientRect.Width = (float)Math.Floor(gradientRect.Width / 3f);
3009 this.FillRectangleAbs(
3011 (!isVertical) ? Color.FromArgb(80, Color.Black) : Color.Transparent,
3012 ChartHatchStyle.None,
3014 ChartImageWrapMode.Scaled,
3016 ChartImageAlignmentStyle.Center,
3017 (isVertical) ? GradientStyle.TopBottom : GradientStyle.LeftRight,
3018 (!isVertical) ? Color.Transparent : Color.FromArgb(80, Color.Black),
3021 ChartDashStyle.NotSet,
3022 PenAlignment.Inset );
3026 else if(barDrawingStyle == BarDrawingStyle.Wedge)
3028 // Calculate wedge size to fit the rectangle
3029 float size = (isVertical) ? rect.Width / 2f : rect.Height / 2f;
3030 if(isVertical && 2f * size > rect.Height)
3032 size = rect.Height/2f;
3034 if(!isVertical && 2f * size > rect.Width)
3036 size = rect.Width/2f;
3039 // Draw left/bottom shadow
3040 RectangleF gradientRect = rect;
3041 using(GraphicsPath path = new GraphicsPath())
3045 path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size, gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size);
3046 path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size, gradientRect.Right, gradientRect.Bottom);
3047 path.AddLine(gradientRect.Right, gradientRect.Bottom, gradientRect.Right, gradientRect.Y);
3051 path.AddLine(gradientRect.X + size, gradientRect.Y + gradientRect.Height/2f, gradientRect.Right - size, gradientRect.Y + gradientRect.Height/2f);
3052 path.AddLine(gradientRect.Right - size, gradientRect.Y + gradientRect.Height/2f, gradientRect.Right, gradientRect.Bottom);
3053 path.AddLine(gradientRect.Right, gradientRect.Bottom, gradientRect.Left, gradientRect.Bottom);
3055 path.CloseAllFigures();
3057 // Create brush and fill path
3058 using(SolidBrush brush = new SolidBrush(Color.FromArgb(90, Color.Black)))
3060 this.FillPath(brush, path);
3064 // Draw top/right triangle
3065 using(GraphicsPath path = new GraphicsPath())
3069 path.AddLine(gradientRect.X, gradientRect.Y, gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size);
3070 path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size, gradientRect.Right, gradientRect.Y);
3074 path.AddLine(gradientRect.Right, gradientRect.Y, gradientRect.Right - size, gradientRect.Y + gradientRect.Height / 2f);
3075 path.AddLine(gradientRect.Right - size, gradientRect.Y + gradientRect.Height / 2f, gradientRect.Right, gradientRect.Bottom);
3078 // Create brush and fill path
3079 using(SolidBrush brush = new SolidBrush(Color.FromArgb(50, Color.Black)))
3081 // Fill shadow path on the left-bottom side of the bar
3082 this.FillPath(brush, path);
3085 using(Pen penDark = new Pen(Color.FromArgb(20, Color.Black), 1))
3087 this.DrawPath(penDark, path);
3092 rect.X + rect.Width/2f,
3094 rect.X + rect.Width/2f,
3095 rect.Bottom - size);
3102 rect.Y + rect.Height/2f,
3104 rect.Bottom - rect.Height/2f);
3109 using(Pen pen = new Pen(Color.FromArgb(40, Color.White), 1))
3111 this.DrawPath(pen, path);
3116 rect.X + rect.Width/2f,
3118 rect.X + rect.Width/2f,
3119 rect.Bottom - size);
3126 rect.Y + rect.Height/2f,
3128 rect.Bottom - rect.Height/2f);
3134 // Draw bottom/left triangle
3135 using(GraphicsPath path = new GraphicsPath())
3139 path.AddLine(gradientRect.X, gradientRect.Bottom, gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size);
3140 path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size, gradientRect.Right, gradientRect.Bottom);
3144 path.AddLine(gradientRect.X, gradientRect.Y, gradientRect.X + size, gradientRect.Y + gradientRect.Height / 2f);
3145 path.AddLine(gradientRect.X + size, gradientRect.Y + gradientRect.Height / 2f, gradientRect.X, gradientRect.Bottom);
3149 using(SolidBrush brush = new SolidBrush(Color.FromArgb(50, Color.Black)))
3151 // Fill shadow path on the left-bottom side of the bar
3152 this.FillPath(brush, path);
3155 using(Pen penDark = new Pen(Color.FromArgb(20, Color.Black), 1))
3157 this.DrawPath(penDark, path);
3159 using(Pen pen = new Pen(Color.FromArgb(40, Color.White), 1))
3161 this.DrawPath(pen, path);
3171 /// Draw a bar with shadow.
3173 /// <param name="rectF">Size of rectangle</param>
3174 /// <param name="backColor">Color of rectangle</param>
3175 /// <param name="backHatchStyle">Hatch style</param>
3176 /// <param name="backImage">Back Image</param>
3177 /// <param name="backImageWrapMode">Image mode</param>
3178 /// <param name="backImageTransparentColor">Image transparent color.</param>
3179 /// <param name="backImageAlign">Image alignment</param>
3180 /// <param name="backGradientStyle">Gradient type </param>
3181 /// <param name="backSecondaryColor">Gradient End Color</param>
3182 /// <param name="borderColor">Border Color</param>
3183 /// <param name="borderWidth">Border Width</param>
3184 /// <param name="borderDashStyle">Border Style</param>
3185 /// <param name="shadowColor">Shadow Color</param>
3186 /// <param name="shadowOffset">Shadow Offset</param>
3187 /// <param name="penAlignment">Pen Alignment</param>
3188 /// <param name="barDrawingStyle">Bar drawing style.</param>
3189 /// <param name="isVertical">True if a vertical bar.</param>
3190 internal void FillRectangleRel( RectangleF rectF,
3192 ChartHatchStyle backHatchStyle,
3194 ChartImageWrapMode backImageWrapMode,
3195 Color backImageTransparentColor,
3196 ChartImageAlignmentStyle backImageAlign,
3197 GradientStyle backGradientStyle,
3198 Color backSecondaryColor,
3201 ChartDashStyle borderDashStyle,
3204 PenAlignment penAlignment,
3205 BarDrawingStyle barDrawingStyle,
3208 this.FillRectangleRel(
3214 backImageTransparentColor,
3232 /// Draw a bar with shadow.
3234 /// <param name="rectF">Size of rectangle</param>
3235 /// <param name="backColor">Color of rectangle</param>
3236 /// <param name="backHatchStyle">Hatch style</param>
3237 /// <param name="backImage">Back Image</param>
3238 /// <param name="backImageWrapMode">Image mode</param>
3239 /// <param name="backImageTransparentColor">Image transparent color.</param>
3240 /// <param name="backImageAlign">Image alignment</param>
3241 /// <param name="backGradientStyle">Gradient type </param>
3242 /// <param name="backSecondaryColor">Gradient End Color</param>
3243 /// <param name="borderColor">Border Color</param>
3244 /// <param name="borderWidth">Border Width</param>
3245 /// <param name="borderDashStyle">Border Style</param>
3246 /// <param name="shadowColor">Shadow Color</param>
3247 /// <param name="shadowOffset">Shadow Offset</param>
3248 /// <param name="penAlignment">Pen Alignment</param>
3249 internal void FillRectangleRel( RectangleF rectF,
3251 ChartHatchStyle backHatchStyle,
3253 ChartImageWrapMode backImageWrapMode,
3254 Color backImageTransparentColor,
3255 ChartImageAlignmentStyle backImageAlign,
3256 GradientStyle backGradientStyle,
3257 Color backSecondaryColor,
3260 ChartDashStyle borderDashStyle,
3263 PenAlignment penAlignment )
3265 this.FillRectangleRel(
3271 backImageTransparentColor,
3284 BarDrawingStyle.Default,
3289 /// Draws rectangle or circle (inside rectangle) with shadow.
3291 /// <param name="rectF">Size of rectangle</param>
3292 /// <param name="backColor">Color of rectangle</param>
3293 /// <param name="backHatchStyle">Hatch style</param>
3294 /// <param name="backImage">Back Image</param>
3295 /// <param name="backImageWrapMode">Image mode</param>
3296 /// <param name="backImageTransparentColor">Image transparent color.</param>
3297 /// <param name="backImageAlign">Image alignment</param>
3298 /// <param name="backGradientStyle">Gradient type </param>
3299 /// <param name="backSecondaryColor">Gradient End Color</param>
3300 /// <param name="borderColor">Border Color</param>
3301 /// <param name="borderWidth">Border Width</param>
3302 /// <param name="borderDashStyle">Border Style</param>
3303 /// <param name="shadowColor">Shadow Color</param>
3304 /// <param name="shadowOffset">Shadow Offset</param>
3305 /// <param name="penAlignment">Pen Alignment</param>
3306 /// <param name="circular">Draw circular shape inside the rectangle.</param>
3307 /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
3308 /// <param name="circle3D">3D Circle must be drawn.</param>
3309 internal void FillRectangleRel( RectangleF rectF,
3311 ChartHatchStyle backHatchStyle,
3313 ChartImageWrapMode backImageWrapMode,
3314 Color backImageTransparentColor,
3315 ChartImageAlignmentStyle backImageAlign,
3316 GradientStyle backGradientStyle,
3317 Color backSecondaryColor,
3320 ChartDashStyle borderDashStyle,
3323 PenAlignment penAlignment,
3325 int circularSectorsCount,
3328 this.FillRectangleRel(
3334 backImageTransparentColor,
3345 circularSectorsCount,
3347 BarDrawingStyle.Default,
3353 /// Draws rectangle or circle (inside rectangle) with shadow.
3355 /// <param name="rectF">Size of rectangle</param>
3356 /// <param name="backColor">Color of rectangle</param>
3357 /// <param name="backHatchStyle">Hatch style</param>
3358 /// <param name="backImage">Back Image</param>
3359 /// <param name="backImageWrapMode">Image mode</param>
3360 /// <param name="backImageTransparentColor">Image transparent color.</param>
3361 /// <param name="backImageAlign">Image alignment</param>
3362 /// <param name="backGradientStyle">Gradient type </param>
3363 /// <param name="backSecondaryColor">Gradient End Color</param>
3364 /// <param name="borderColor">Border Color</param>
3365 /// <param name="borderWidth">Border Width</param>
3366 /// <param name="borderDashStyle">Border Style</param>
3367 /// <param name="shadowColor">Shadow Color</param>
3368 /// <param name="shadowOffset">Shadow Offset</param>
3369 /// <param name="penAlignment">Pen Alignment</param>
3370 /// <param name="circular">Draw circular shape inside the rectangle.</param>
3371 /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
3372 /// <param name="circle3D">3D Circle must be drawn.</param>
3373 /// <param name="barDrawingStyle">Bar drawing style.</param>
3374 /// <param name="isVertical">True if a vertical bar.</param>
3375 internal void FillRectangleRel( RectangleF rectF,
3377 ChartHatchStyle backHatchStyle,
3379 ChartImageWrapMode backImageWrapMode,
3380 Color backImageTransparentColor,
3381 ChartImageAlignmentStyle backImageAlign,
3382 GradientStyle backGradientStyle,
3383 Color backSecondaryColor,
3386 ChartDashStyle borderDashStyle,
3389 PenAlignment penAlignment,
3391 int circularSectorsCount,
3393 BarDrawingStyle barDrawingStyle,
3397 Brush backBrush = null;
3399 // Remember SmoothingMode and turn off anti aliasing
3400 SmoothingMode oldSmoothingMode = this.SmoothingMode;
3403 this.SmoothingMode = SmoothingMode.Default;
3407 if( backColor.IsEmpty )
3409 backColor = Color.White;
3412 if( backSecondaryColor.IsEmpty )
3414 backSecondaryColor = Color.White;
3417 if( borderColor.IsEmpty || borderDashStyle == ChartDashStyle.NotSet)
3422 // Get absolute coordinates
3423 RectangleF rect = GetAbsoluteRectangle( rectF );
3425 // Rectangle width and height can not be very small value
3426 if( rect.Width < 1.0F && rect.Width > 0.0F )
3431 if( rect.Height < 1.0F && rect.Height > 0.0F )
3437 rect = Round( rect );
3439 // For inset alignment resize fill rectangle
3440 RectangleF fillRect;
3441 if( penAlignment == PenAlignment.Inset &&
3444 // SVG and Metafiles do not support inset pen styles - use same rectangle
3445 if( this.ActiveRenderingType == RenderingType.Svg ||
3448 fillRect = new RectangleF( rect.X, rect.Y, rect.Width, rect.Height);
3450 else if (this.Graphics.Transform.Elements[0] != 1f ||
3451 this.Graphics.Transform.Elements[3] != 1f)
3453 // Do not reduce filling rectangle if scaling is used in the graphics
3454 // transformations. Rounding may cause a 1 pixel gap between the border
3456 fillRect = new RectangleF( rect.X, rect.Y, rect.Width, rect.Height);
3460 // The fill rectangle is resized because of border size.
3461 fillRect = new RectangleF(
3462 rect.X + borderWidth,
3463 rect.Y + borderWidth,
3464 rect.Width - borderWidth * 2f + 1,
3465 rect.Height - borderWidth * 2f + 1);
3470 // The fill rectangle is same
3474 // Fix for issue #6714:
3475 // Make sure the rectangle coordinates fit the control. In same cases rectangle width or
3476 // hight ca be extremly large. Drawing such a rectangle may cause an overflow exception.
3477 // The code below restricts the maximum size to double the chart size. See issue
3478 // description for more information. -AG.
3479 if(fillRect.Width > 2f * this._width)
3481 fillRect.Width = 2f * this._width;
3483 if(fillRect.Height > 2f * this._height)
3485 fillRect.Height = 2f * this._height;
3489 if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
3492 brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor);
3494 else if( backHatchStyle != ChartHatchStyle.None )
3496 brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
3498 else if( backGradientStyle != GradientStyle.None )
3500 // If a gradient type is set create a brush with gradient
3501 brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
3506 if(backColor == Color.Empty || backColor == Color.Transparent)
3512 brush = new SolidBrush(backColor);
3517 FillRectangleShadowAbs( rect, shadowColor, shadowOffset, backColor, circular, circularSectorsCount );
3519 // Draw rectangle image
3520 if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
3523 System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
3525 // Prepare image properties (transparent color)
3526 ImageAttributes attrib = new ImageAttributes();
3527 if(backImageTransparentColor != Color.Empty)
3529 attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
3532 // Draw scaled image
3533 RectangleF imageRect = new RectangleF();
3534 imageRect.X = fillRect.X;
3535 imageRect.Y = fillRect.Y;
3536 imageRect.Width = fillRect.Width;
3537 imageRect.Height = fillRect.Height;
3539 SizeF imageAbsSize = new SizeF();
3541 // Calculate unscaled image position
3542 if(backImageWrapMode == ChartImageWrapMode.Unscaled)
3544 ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageAbsSize);
3546 // Calculate image position
3547 imageRect.Width = Math.Min(fillRect.Width, imageAbsSize.Width);
3548 imageRect.Height = Math.Min(fillRect.Height, imageAbsSize.Height);
3550 // Adjust position with alignment property
3551 if(imageRect.Width < fillRect.Width)
3553 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
3554 backImageAlign == ChartImageAlignmentStyle.Right ||
3555 backImageAlign == ChartImageAlignmentStyle.TopRight)
3557 imageRect.X = fillRect.Right - imageRect.Width;
3559 else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
3560 backImageAlign == ChartImageAlignmentStyle.Center ||
3561 backImageAlign == ChartImageAlignmentStyle.Top)
3563 imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
3566 if(imageRect.Height < fillRect.Height)
3568 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
3569 backImageAlign == ChartImageAlignmentStyle.Bottom ||
3570 backImageAlign == ChartImageAlignmentStyle.BottomLeft)
3572 imageRect.Y = fillRect.Bottom - imageRect.Height;
3574 else if(backImageAlign == ChartImageAlignmentStyle.Left ||
3575 backImageAlign == ChartImageAlignmentStyle.Center ||
3576 backImageAlign == ChartImageAlignmentStyle.Right)
3578 imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
3584 // Fill background with brush
3588 this.DrawCircleAbs( null, brush, fillRect, circularSectorsCount, circle3D );
3590 this.FillRectangle( brush, fillRect );
3594 this.DrawImage(image,
3595 new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
3597 (backImageWrapMode == ChartImageWrapMode.Unscaled) ? imageRect.Width * image.Width / imageAbsSize.Width : image.Width,
3598 (backImageWrapMode == ChartImageWrapMode.Unscaled) ? imageRect.Height * image.Height / imageAbsSize.Height : image.Height,
3605 if(backBrush != null && backImageTransparentColor != Color.Empty)
3607 // Fill background with brush
3609 this.DrawCircleAbs( null, backBrush, fillRect, circularSectorsCount, circle3D );
3611 this.FillRectangle( backBrush, fillRect );
3617 this.DrawCircleAbs( null, brush, fillRect, circularSectorsCount, circle3D );
3619 this.FillRectangle( brush, fillRect );
3623 // Draw different bar style
3624 this.DrawRectangleBarStyle(barDrawingStyle, isVertical, fillRect);
3627 if( borderWidth > 0 && borderDashStyle != ChartDashStyle.NotSet)
3629 // Set a border line color
3630 if(_pen.Color != borderColor)
3632 _pen.Color = borderColor;
3635 // Set a border line width
3636 if(_pen.Width != borderWidth)
3638 _pen.Width = borderWidth;
3641 // Set pen alignment
3642 if(_pen.Alignment != penAlignment)
3644 _pen.Alignment = penAlignment;
3647 // Set a border line style
3648 if(_pen.DashStyle != GetPenStyle( borderDashStyle ))
3650 _pen.DashStyle = GetPenStyle( borderDashStyle );
3656 this.DrawCircleAbs( _pen, null, rect, circularSectorsCount, false );
3660 // NOTE: Rectangle with single pixel inset border is drawn 1 pixel larger
3661 // in the .Net Framework. Increase size by 1 pixel to solve the issue.
3662 if(_pen.Alignment == PenAlignment.Inset && _pen.Width > 1f)
3669 this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width, rect.Height );
3673 // Dispose Image and Gradient
3679 // Return old smoothing mode
3680 this.SmoothingMode = oldSmoothingMode;
3684 /// Draw Shadow for a bar
3686 /// <param name="rect">Bar rectangle</param>
3687 /// <param name="shadowColor">Shadow Color</param>
3688 /// <param name="shadowOffset">Shadow Offset</param>
3689 /// <param name="backColor">Back Color</param>
3690 internal void FillRectangleShadowAbs(
3696 FillRectangleShadowAbs(
3706 /// Draw Shadow for a bar
3708 /// <param name="rect">Bar rectangle</param>
3709 /// <param name="shadowColor">Shadow Color</param>
3710 /// <param name="shadowOffset">Shadow Offset</param>
3711 /// <param name="backColor">Back Color</param>
3712 /// <param name="circular">Draw circular shape inside the rectangle.</param>
3713 /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
3714 internal void FillRectangleShadowAbs(
3720 int circularSectorsCount)
3722 // Do not draw shadoe for empty rectangle
3723 if(rect.Height == 0 || rect.Width == 0 || shadowOffset == 0)
3728 // Do not draw shadow if color is IsEmpty or offset is 0
3729 if (shadowOffset == 0 || shadowColor == Color.Empty)
3734 // For non-circualr shadow with transparent background - use clipping
3735 bool clippingUsed = false;
3736 Region oldClipRegion = null;
3737 if (!circular && backColor == Color.Transparent)
3739 clippingUsed = true;
3740 oldClipRegion = this.Clip;
3741 Region region = new Region();
3742 region.MakeInfinite();
3747 // Draw usual or "soft" shadows
3748 if(!softShadows || circularSectorsCount > 2)
3750 RectangleF absolute;
3751 RectangleF offset = RectangleF.Empty;
3753 absolute = Round( rect );
3755 // Change shadow color
3756 using (SolidBrush shadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(backColor.A / 2, shadowColor)))
3759 offset.X = absolute.X + shadowOffset;
3760 offset.Y = absolute.Y + shadowOffset;
3761 offset.Width = absolute.Width;
3762 offset.Height = absolute.Height;
3766 this.DrawCircleAbs(null, shadowBrush, offset, circularSectorsCount, false);
3768 this.FillRectangle(shadowBrush, offset);
3774 RectangleF absolute;
3775 RectangleF offset = RectangleF.Empty;
3777 absolute = Round( rect );
3781 offset.X = absolute.X + shadowOffset - 1;
3782 offset.Y = absolute.Y + shadowOffset - 1;
3783 offset.Width = absolute.Width + 2;
3784 offset.Height = absolute.Height + 2;
3786 // Calculate rounded rect radius
3787 float radius = shadowOffset * 0.7f;
3788 radius = (float)Math.Max(radius, 2f);
3789 radius = (float)Math.Min(radius, offset.Width/4f);
3790 radius = (float)Math.Min(radius, offset.Height/4f);
3791 radius = (float)Math.Ceiling(radius);
3794 radius = offset.Width/2f;
3797 // Create rounded rectangle path
3798 GraphicsPath path = new GraphicsPath();
3799 if(circular && offset.Width != offset.Height)
3801 float radiusX = offset.Width/2f;
3802 float radiusY = offset.Height/2f;
3803 path.AddLine(offset.X+radiusX, offset.Y, offset.Right-radiusX, offset.Y);
3804 path.AddArc(offset.Right-2f*radiusX, offset.Y, 2f*radiusX, 2f*radiusY, 270, 90);
3805 path.AddLine(offset.Right, offset.Y + radiusY, offset.Right, offset.Bottom - radiusY);
3806 path.AddArc(offset.Right-2f*radiusX, offset.Bottom-2f*radiusY, 2f*radiusX, 2f*radiusY, 0, 90);
3807 path.AddLine(offset.Right-radiusX, offset.Bottom, offset.X + radiusX, offset.Bottom);
3808 path.AddArc(offset.X, offset.Bottom-2f*radiusY, 2f*radiusX, 2f*radiusY, 90, 90);
3809 path.AddLine(offset.X, offset.Bottom-radiusY, offset.X, offset.Y+radiusY);
3810 path.AddArc(offset.X, offset.Y, 2f*radiusX, 2f*radiusY, 180, 90);
3814 path.AddLine(offset.X+radius, offset.Y, offset.Right-radius, offset.Y);
3815 path.AddArc(offset.Right-2f*radius, offset.Y, 2f*radius, 2f*radius, 270, 90);
3816 path.AddLine(offset.Right, offset.Y + radius, offset.Right, offset.Bottom - radius);
3817 path.AddArc(offset.Right-2f*radius, offset.Bottom-2f*radius, 2f*radius, 2f*radius, 0, 90);
3818 path.AddLine(offset.Right-radius, offset.Bottom, offset.X + radius, offset.Bottom);
3819 path.AddArc(offset.X, offset.Bottom-2f*radius, 2f*radius, 2f*radius, 90, 90);
3820 path.AddLine(offset.X, offset.Bottom-radius, offset.X, offset.Y+radius);
3821 path.AddArc(offset.X, offset.Y, 2f*radius, 2f*radius, 180, 90);
3824 PathGradientBrush shadowBrush = new PathGradientBrush(path);
3825 shadowBrush.CenterColor = shadowColor;
3827 // Set the color along the entire boundary of the path
3828 Color[] colors = {Color.Transparent};
3829 shadowBrush.SurroundColors = colors;
3830 shadowBrush.CenterPoint = new PointF(offset.X + offset.Width/2f, offset.Y + offset.Height/2f);
3832 // Define brush focus scale
3833 PointF focusScale = new PointF(1-2f*shadowOffset/offset.Width, 1-2f*shadowOffset/offset.Height);
3834 if(focusScale.X < 0)
3836 if(focusScale.Y < 0)
3838 shadowBrush.FocusScales = focusScale;
3841 this.FillPath(shadowBrush, path);
3844 // Reset clip region
3847 Region region = this.Clip;
3848 this.Clip = oldClipRegion;
3854 /// Gets the path of the polygon which represent the circular area.
3856 /// <param name="position">Circle position.</param>
3857 /// <param name="polygonSectorsNumber">Number of sectors for the polygon.</param>
3858 /// <returns>Graphics path of the polygon circle.</returns>
3859 internal GraphicsPath GetPolygonCirclePath(RectangleF position, int polygonSectorsNumber)
3861 PointF firstPoint = new PointF(position.X + position.Width/2f, position.Y);
3862 PointF centerPoint = new PointF(position.X + position.Width/2f, position.Y + position.Height/2f);
3863 float sectorSize = 0f;
3864 GraphicsPath path = new GraphicsPath();
3865 PointF prevPoint = PointF.Empty;
3866 float curentSector = 0f;
3869 if(polygonSectorsNumber <= 2)
3871 // Circle sector size
3876 // Polygon sector size
3877 sectorSize = 360f / ((float)polygonSectorsNumber);
3880 // Loop throug all sectors
3881 for(curentSector = 0f; curentSector < 360f; curentSector += sectorSize)
3884 Matrix matrix = new Matrix();
3885 matrix.RotateAt(curentSector, centerPoint);
3887 // Get point and rotate it
3888 PointF[] points = new PointF[] { firstPoint };
3889 matrix.TransformPoints(points);
3891 // Add point into the path
3892 if(!prevPoint.IsEmpty)
3894 path.AddLine(prevPoint, points[0]);
3897 // Remember last point
3898 prevPoint = points[0];
3901 path.CloseAllFigures();
3907 /// Fills and/or draws border as circle or polygon.
3909 /// <param name="pen">Border pen.</param>
3910 /// <param name="brush">Border brush.</param>
3911 /// <param name="position">Circle position.</param>
3912 /// <param name="polygonSectorsNumber">Number of sectors for the polygon.</param>
3913 /// <param name="circle3D">Indicates that circle should be 3D..</param>
3914 internal void DrawCircleAbs(Pen pen, Brush brush, RectangleF position, int polygonSectorsNumber, bool circle3D)
3916 bool fill3DCircle = (circle3D && brush != null);
3919 if(polygonSectorsNumber <= 2 && !fill3DCircle)
3923 this.FillEllipse(brush, position);
3927 this.DrawEllipse(pen, position);
3931 // Draw circle as polygon with specified number of sectors
3934 PointF firstPoint = new PointF(position.X + position.Width/2f, position.Y);
3935 PointF centerPoint = new PointF(position.X + position.Width/2f, position.Y + position.Height/2f);
3936 float sectorSize = 0f;
3937 PointF prevPoint = PointF.Empty;
3938 float curentSector = 0f;
3940 using (GraphicsPath path = new GraphicsPath())
3942 // Remember current smoothing mode
3943 SmoothingMode oldMode = this.SmoothingMode;
3946 this.SmoothingMode = SmoothingMode.None;
3950 if (polygonSectorsNumber <= 2)
3952 // Circle sector size
3957 // Polygon sector size
3958 sectorSize = 360f / ((float)polygonSectorsNumber);
3961 // Loop throug all sectors
3962 for (curentSector = 0f; curentSector < 360f; curentSector += sectorSize)
3965 Matrix matrix = new Matrix();
3966 matrix.RotateAt(curentSector, centerPoint);
3968 // Get point and rotate it
3969 PointF[] points = new PointF[] { firstPoint };
3970 matrix.TransformPoints(points);
3972 // Add point into the path
3973 if (!prevPoint.IsEmpty)
3975 path.AddLine(prevPoint, points[0]);
3977 // Fill each segment separatly for the 3D look
3980 path.AddLine(points[0], centerPoint);
3981 path.AddLine(centerPoint, prevPoint);
3982 using (Brush sectorBrush = GetSector3DBrush(brush, curentSector, sectorSize))
3984 this.FillPath(sectorBrush, path);
3990 // Remember last point
3991 prevPoint = points[0];
3994 path.CloseAllFigures();
3996 // Fill last segment for the 3D look
3997 if (!prevPoint.IsEmpty && fill3DCircle)
3999 path.AddLine(prevPoint, firstPoint);
4000 path.AddLine(firstPoint, centerPoint);
4001 path.AddLine(centerPoint, prevPoint);
4002 using (Brush sectorBrush = GetSector3DBrush(brush, curentSector, sectorSize))
4004 this.FillPath(sectorBrush, path);
4012 this.SmoothingMode = oldMode;
4015 if (brush != null && !circle3D)
4017 this.FillPath(brush, path);
4021 this.DrawPath(pen, path);
4028 /// Creates 3D sector brush.
4030 /// <param name="brush">Original brush.</param>
4031 /// <param name="curentSector">Sector position.</param>
4032 /// <param name="sectorSize">Sector size.</param>
4033 /// <returns>3D brush.</returns>
4034 [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
4035 Justification = "Too large of a code change to justify making this change")]
4036 internal Brush GetSector3DBrush(Brush brush, float curentSector, float sectorSize)
4038 // Get color from the brush
4039 Color brushColor = Color.Gray;
4040 if(brush is HatchBrush)
4042 brushColor = ((HatchBrush)brush).BackgroundColor;
4044 else if(brush is LinearGradientBrush)
4046 brushColor = ((LinearGradientBrush)brush).LinearColors[0];
4048 else if(brush is PathGradientBrush)
4050 brushColor = ((PathGradientBrush)brush).CenterColor;
4052 else if(brush is SolidBrush)
4054 brushColor = ((SolidBrush)brush).Color;
4057 // Adjust sector angle
4058 curentSector -= sectorSize / 2f;
4060 // Make adjustment for polygon circle with 5 segments
4061 // to avoid the issue that bottom segment is too dark
4062 if(sectorSize == 72f && curentSector == 180f)
4064 curentSector *= 0.8f;
4067 // No angles more than 180
4068 if(curentSector > 180)
4070 curentSector = 360f - curentSector;
4072 curentSector = curentSector / 180F;
4075 brushColor = GetBrightGradientColor( brushColor, curentSector);
4078 return new SolidBrush(brushColor);
4082 /// This method creates gradient color with brightness
4084 /// <param name="beginColor">Start color for gradient.</param>
4085 /// <param name="position">Position used between Start and end color.</param>
4086 /// <returns>Calculated Gradient color from gradient position</returns>
4087 internal Color GetBrightGradientColor( Color beginColor, double position )
4089 double brightness = 0.5;
4090 if( position < brightness )
4092 return GetGradientColor( Color.FromArgb(beginColor.A,255,255,255), beginColor, 1 - brightness + position );
4094 else if( -brightness + position < 1 )
4096 return GetGradientColor( beginColor, Color.Black, -brightness + position);
4100 return Color.FromArgb( beginColor.A, 0, 0, 0 );
4105 /// Draw Rectangle using absolute coordinates.
4107 /// <param name="rect">Size of rectangle</param>
4108 /// <param name="backColor">Color of rectangle</param>
4109 /// <param name="backHatchStyle">Hatch Style</param>
4110 /// <param name="backImage">Image URL</param>
4111 /// <param name="backImageWrapMode">Image Mode</param>
4112 /// <param name="backImageTransparentColor">Image transparent color.</param>
4113 /// <param name="backImageAlign">Image alignment.</param>
4114 /// <param name="backGradientStyle">Gradient AxisName</param>
4115 /// <param name="backSecondaryColor">End Gradient color</param>
4116 /// <param name="borderColor">Border Color</param>
4117 /// <param name="borderWidth">Border Width</param>
4118 /// <param name="borderDashStyle">Border Style</param>
4119 /// <param name="penAlignment">Border is outside or inside rectangle</param>
4120 internal void FillRectangleAbs( RectangleF rect,
4122 ChartHatchStyle backHatchStyle,
4124 ChartImageWrapMode backImageWrapMode,
4125 Color backImageTransparentColor,
4126 ChartImageAlignmentStyle backImageAlign,
4127 GradientStyle backGradientStyle,
4128 Color backSecondaryColor,
4131 ChartDashStyle borderDashStyle,
4132 PenAlignment penAlignment )
4135 Brush backBrush = null;
4137 // Turn off Antialias
4138 SmoothingMode oldMode = this.SmoothingMode;
4139 this.SmoothingMode = SmoothingMode.None;
4142 if( backColor.IsEmpty )
4143 backColor = Color.White;
4145 if( backSecondaryColor.IsEmpty )
4146 backSecondaryColor = Color.White;
4148 if( borderColor.IsEmpty )
4150 borderColor = Color.White;
4154 // Set a border line color
4155 _pen.Color = borderColor;
4157 // Set a border line width
4158 _pen.Width = borderWidth;
4160 // Set pen alignment
4161 _pen.Alignment = penAlignment;
4163 // Set a border line style
4164 _pen.DashStyle = GetPenStyle( borderDashStyle );
4166 if( backGradientStyle == GradientStyle.None )
4169 _solidBrush.Color = backColor;
4170 brush = _solidBrush;
4174 // If a gradient type is set create a brush with gradient
4175 brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
4178 if( backHatchStyle != ChartHatchStyle.None )
4180 brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
4183 if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
4186 brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
4189 // For inset alignment resize fill rectangle
4190 RectangleF fillRect;
4192 // The fill rectangle is same
4193 fillRect = new RectangleF( rect.X + borderWidth, rect.Y + borderWidth, rect.Width - borderWidth * 2, rect.Height - borderWidth * 2 );
4195 // FillRectangle and DrawRectangle works differently with RectangleF.
4196 fillRect.Width += 1;
4197 fillRect.Height += 1;
4199 // Draw rectangle image
4200 if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
4203 System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
4206 // Prepare image properties (transparent color)
4207 ImageAttributes attrib = new ImageAttributes();
4208 if(backImageTransparentColor != Color.Empty)
4210 attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
4213 // Draw scaled image
4214 RectangleF imageRect = new RectangleF();
4215 imageRect.X = fillRect.X;
4216 imageRect.Y = fillRect.Y;
4217 imageRect.Width = fillRect.Width;
4218 imageRect.Height = fillRect.Height;
4220 // Draw unscaled image using align property
4221 if(backImageWrapMode == ChartImageWrapMode.Unscaled)
4223 SizeF imageAbsSize = new SizeF();
4225 ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageAbsSize);
4227 // Calculate image position
4228 imageRect.Width = imageAbsSize.Width;
4229 imageRect.Height = imageAbsSize.Height;
4231 // Adjust position with alignment property
4232 if(imageRect.Width < fillRect.Width)
4234 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
4235 backImageAlign == ChartImageAlignmentStyle.Right ||
4236 backImageAlign == ChartImageAlignmentStyle.TopRight)
4238 imageRect.X = fillRect.Right - imageRect.Width;
4240 else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
4241 backImageAlign == ChartImageAlignmentStyle.Center ||
4242 backImageAlign == ChartImageAlignmentStyle.Top)
4244 imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
4247 if(imageRect.Height < fillRect.Height)
4249 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
4250 backImageAlign == ChartImageAlignmentStyle.Bottom ||
4251 backImageAlign == ChartImageAlignmentStyle.BottomLeft)
4253 imageRect.Y = fillRect.Bottom - imageRect.Height;
4255 else if(backImageAlign == ChartImageAlignmentStyle.Left ||
4256 backImageAlign == ChartImageAlignmentStyle.Center ||
4257 backImageAlign == ChartImageAlignmentStyle.Right)
4259 imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
4265 // Fill background with brush
4266 this.FillRectangle( brush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1);
4269 this.DrawImage(image,
4270 new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
4271 0, 0, image.Width, image.Height,
4278 if(backBrush != null && backImageTransparentColor != Color.Empty)
4280 // Fill background with brush
4281 this.FillRectangle( backBrush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
4283 this.FillRectangle( brush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
4286 // Set pen alignment
4287 if(borderDashStyle != ChartDashStyle.NotSet)
4289 if( borderWidth > 1 )
4290 this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
4291 else if( borderWidth == 1 )
4292 this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width, rect.Height );
4295 // Dispose Image and Gradient
4296 if( backGradientStyle != GradientStyle.None )
4300 if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
4304 if( backHatchStyle != ChartHatchStyle.None )
4309 // Set Old Smoothing Mode
4310 this.SmoothingMode = oldMode;
4314 /// Fills graphics path with shadow using absolute coordinates.
4316 /// <param name="path">Graphics path to fill.</param>
4317 /// <param name="backColor">Color of rectangle</param>
4318 /// <param name="backHatchStyle">Hatch Style</param>
4319 /// <param name="backImage">Image URL</param>
4320 /// <param name="backImageWrapMode">Image Mode</param>
4321 /// <param name="backImageTransparentColor">Image transparent color.</param>
4322 /// <param name="backImageAlign">Image alignment.</param>
4323 /// <param name="backGradientStyle">Gradient AxisName</param>
4324 /// <param name="backSecondaryColor">End Gradient color</param>
4325 /// <param name="borderColor">Border Color</param>
4326 /// <param name="borderWidth">Border Width</param>
4327 /// <param name="borderDashStyle">Border Style</param>
4328 /// <param name="penAlignment">Border is outside or inside rectangle</param>
4329 /// <param name="shadowOffset">Shadow offset.</param>
4330 /// <param name="shadowColor">Shadow color.</param>
4331 internal void DrawPathAbs(
4334 ChartHatchStyle backHatchStyle,
4336 ChartImageWrapMode backImageWrapMode,
4337 Color backImageTransparentColor,
4338 ChartImageAlignmentStyle backImageAlign,
4339 GradientStyle backGradientStyle,
4340 Color backSecondaryColor,
4343 ChartDashStyle borderDashStyle,
4344 PenAlignment penAlignment,
4349 if(shadowOffset != 0 && shadowColor != Color.Transparent)
4351 // Save graphics state and apply translate transformation
4352 GraphicsState graphicsState = this.Save();
4353 this.TranslateTransform(shadowOffset, shadowOffset);
4355 if(backColor == Color.Transparent &&
4356 backSecondaryColor.IsEmpty )
4361 ChartHatchStyle.None,
4363 ChartImageWrapMode.Scaled,
4365 ChartImageAlignmentStyle.Center,
4371 PenAlignment.Center);
4378 ChartHatchStyle.None,
4380 ChartImageWrapMode.Scaled,
4382 ChartImageAlignmentStyle.Center,
4387 ChartDashStyle.NotSet,
4388 PenAlignment.Center);
4391 // Restore graphics state
4392 this.Restore(graphicsState);
4402 backImageTransparentColor,
4413 /// Fills graphics path using absolute coordinates.
4415 /// <param name="path">Graphics path to fill.</param>
4416 /// <param name="backColor">Color of rectangle</param>
4417 /// <param name="backHatchStyle">Hatch Style</param>
4418 /// <param name="backImage">Image URL</param>
4419 /// <param name="backImageWrapMode">Image Mode</param>
4420 /// <param name="backImageTransparentColor">Image transparent color.</param>
4421 /// <param name="backImageAlign">Image alignment.</param>
4422 /// <param name="backGradientStyle">Gradient AxisName</param>
4423 /// <param name="backSecondaryColor">End Gradient color</param>
4424 /// <param name="borderColor">Border Color</param>
4425 /// <param name="borderWidth">Border Width</param>
4426 /// <param name="borderDashStyle">Border Style</param>
4427 /// <param name="penAlignment">Border is outside or inside rectangle</param>
4428 internal void DrawPathAbs( GraphicsPath path,
4430 ChartHatchStyle backHatchStyle,
4432 ChartImageWrapMode backImageWrapMode,
4433 Color backImageTransparentColor,
4434 ChartImageAlignmentStyle backImageAlign,
4435 GradientStyle backGradientStyle,
4436 Color backSecondaryColor,
4439 ChartDashStyle borderDashStyle,
4440 PenAlignment penAlignment )
4443 Brush backBrush = null;
4446 if( backColor.IsEmpty )
4447 backColor = Color.White;
4449 if( backSecondaryColor.IsEmpty )
4450 backSecondaryColor = Color.White;
4452 if( borderColor.IsEmpty )
4454 borderColor = Color.White;
4458 // Set pen properties
4459 _pen.Color = borderColor;
4460 _pen.Width = borderWidth;
4461 _pen.Alignment = penAlignment;
4462 _pen.DashStyle = GetPenStyle( borderDashStyle );
4464 if( backGradientStyle == GradientStyle.None )
4466 // Set solid brush color.
4467 _solidBrush.Color = backColor;
4468 brush = _solidBrush;
4472 // If a gradient type is set create a brush with gradient
4473 RectangleF pathRect = path.GetBounds();
4474 pathRect.Inflate(new SizeF(2,2));
4475 brush = GetGradientBrush(
4479 backGradientStyle );
4482 if( backHatchStyle != ChartHatchStyle.None )
4484 brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
4487 if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
4490 brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
4493 // For inset alignment resize fill rectangle
4494 RectangleF fillRect = path.GetBounds();
4496 // Draw rectangle image
4497 if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
4500 System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
4502 // Prepare image properties (transparent color)
4503 ImageAttributes attrib = new ImageAttributes();
4504 if(backImageTransparentColor != Color.Empty)
4506 attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
4509 // Draw scaled image
4510 RectangleF imageRect = new RectangleF();
4511 imageRect.X = fillRect.X;
4512 imageRect.Y = fillRect.Y;
4513 imageRect.Width = fillRect.Width;
4514 imageRect.Height = fillRect.Height;
4516 // Draw unscaled image using align property
4517 if(backImageWrapMode == ChartImageWrapMode.Unscaled)
4519 SizeF imageSize = new SizeF();
4521 ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageSize);
4523 // Calculate image position
4524 imageRect.Width = imageSize.Width;
4525 imageRect.Height = imageSize.Height;
4527 // Adjust position with alignment property
4528 if(imageRect.Width < fillRect.Width)
4530 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
4531 backImageAlign == ChartImageAlignmentStyle.Right ||
4532 backImageAlign == ChartImageAlignmentStyle.TopRight)
4534 imageRect.X = fillRect.Right - imageRect.Width;
4536 else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
4537 backImageAlign == ChartImageAlignmentStyle.Center ||
4538 backImageAlign == ChartImageAlignmentStyle.Top)
4540 imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
4543 if(imageRect.Height < fillRect.Height)
4545 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
4546 backImageAlign == ChartImageAlignmentStyle.Bottom ||
4547 backImageAlign == ChartImageAlignmentStyle.BottomLeft)
4549 imageRect.Y = fillRect.Bottom - imageRect.Height;
4551 else if(backImageAlign == ChartImageAlignmentStyle.Left ||
4552 backImageAlign == ChartImageAlignmentStyle.Center ||
4553 backImageAlign == ChartImageAlignmentStyle.Right)
4555 imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
4561 // Fill background with brush
4562 this.FillPath( brush, path );
4565 Region oldClipRegion = this.Clip;
4566 this.Clip = new Region(path);
4567 this.DrawImage(image,
4568 new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
4569 0, 0, image.Width, image.Height,
4572 this.Clip = oldClipRegion;
4578 if(backBrush != null && backImageTransparentColor != Color.Empty)
4580 // Fill background with brush
4581 this.FillPath( backBrush, path);
4583 this.FillPath( brush, path);
4587 if(borderColor != Color.Empty && borderWidth > 0 && borderDashStyle != ChartDashStyle.NotSet)
4589 this.DrawPath( _pen, path );
4594 /// Creates brush with specified properties.
4596 /// <param name="rect">Gradient rectangle</param>
4597 /// <param name="backColor">Color of rectangle</param>
4598 /// <param name="backHatchStyle">Hatch style</param>
4599 /// <param name="backImage">Back Image</param>
4600 /// <param name="backImageWrapMode">Image mode</param>
4601 /// <param name="backImageTransparentColor">Image transparent color.</param>
4602 /// <param name="backGradientStyle">Gradient type </param>
4603 /// <param name="backSecondaryColor">Gradient End Color</param>
4604 /// <returns>New brush object.</returns>
4605 internal Brush CreateBrush(
4608 ChartHatchStyle backHatchStyle,
4610 ChartImageWrapMode backImageWrapMode,
4611 Color backImageTransparentColor,
4612 GradientStyle backGradientStyle,
4613 Color backSecondaryColor
4616 Brush brush = new SolidBrush(backColor);
4618 if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
4620 brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
4622 else if( backHatchStyle != ChartHatchStyle.None )
4624 brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
4626 else if( backGradientStyle != GradientStyle.None )
4628 // If a gradient type is set create a brush with gradient
4629 brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
4637 #region Coordinates converter
4640 /// This method takes a RectangleF structure that is using absolute coordinates
4641 /// and returns a RectangleF object that uses relative coordinates.
4643 /// <param name="rectangle">RectangleF structure in absolute coordinates.</param>
4644 /// <returns>RectangleF structure in relative coordinates.</returns>
4645 public RectangleF GetRelativeRectangle( RectangleF rectangle )
4648 if (rectangle == null)
4649 throw new ArgumentNullException("rectangle");
4651 RectangleF relative = RectangleF.Empty;
4653 // Convert absolute coordinates to relative coordinates
4654 relative.X = rectangle.X * 100F / ((float)(_width - 1));
4655 relative.Y = rectangle.Y * 100F / ((float)(_height - 1));
4656 relative.Width = rectangle.Width * 100F / ((float)(_width - 1));
4657 relative.Height = rectangle.Height * 100F / ((float)(_height - 1));
4659 // Return Relative coordinates
4664 /// This method takes a PointF object that is using absolute coordinates
4665 /// and returns a PointF object that uses relative coordinates.
4667 /// <param name="point">PointF object in absolute coordinates.</param>
4668 /// <returns>PointF object in relative coordinates.</returns>
4669 public PointF GetRelativePoint( PointF point )
4673 throw new ArgumentNullException("point");
4675 PointF relative = PointF.Empty;
4677 // Convert absolute coordinates to relative coordinates
4678 relative.X = point.X * 100F / ((float)(_width - 1));
4679 relative.Y = point.Y * 100F / ((float)(_height - 1));
4681 // Return Relative coordinates
4687 /// This method takes a SizeF object that uses absolute coordinates
4688 /// and returns a SizeF object that uses relative coordinates.
4690 /// <param name="size">SizeF object in absolute coordinates.</param>
4691 /// <returns>SizeF object in relative coordinates.</returns>
4692 public SizeF GetRelativeSize( SizeF size )
4696 throw new ArgumentNullException("size");
4698 SizeF relative = SizeF.Empty;
4700 // Convert absolute coordinates to relative coordinates
4701 relative.Width = size.Width * 100F / ((float)(_width - 1));
4702 relative.Height = size.Height * 100F / ((float)(_height - 1));
4704 // Return relative coordinates
4709 /// This method takes a PointF object and converts its relative coordinates
4710 /// to absolute coordinates.
4712 /// <param name="point">PointF object in relative coordinates.</param>
4713 /// <returns>PointF object in absolute coordinates.</returns>
4714 public PointF GetAbsolutePoint( PointF point )
4718 throw new ArgumentNullException("point");
4720 PointF absolute = PointF.Empty;
4722 // Convert relative coordinates to absolute coordinates
4723 absolute.X = point.X * (_width - 1) / 100F;
4724 absolute.Y = point.Y * (_height - 1) / 100F;
4726 // Return Absolute coordinates
4731 /// This method takes a RectangleF structure and converts its relative coordinates
4732 /// to absolute coordinates.
4734 /// <param name="rectangle">RectangleF object in relative coordinates.</param>
4735 /// <returns>RectangleF object in absolute coordinates.</returns>
4736 public RectangleF GetAbsoluteRectangle( RectangleF rectangle )
4739 if (rectangle == null)
4740 throw new ArgumentNullException("rectangle");
4742 RectangleF absolute = RectangleF.Empty;
4744 // Convert relative coordinates to absolute coordinates
4745 absolute.X = rectangle.X * (_width - 1) / 100F;
4746 absolute.Y = rectangle.Y * (_height - 1) / 100F;
4747 absolute.Width = rectangle.Width * (_width - 1) / 100F;
4748 absolute.Height = rectangle.Height * (_height - 1) / 100F;
4750 // Return Absolute coordinates
4755 /// This method takes a SizeF object that uses relative coordinates
4756 /// and returns a SizeF object that uses absolute coordinates.
4758 /// <param name="size">SizeF object in relative coordinates.</param>
4759 /// <returns>SizeF object in absolute coordinates.</returns>
4760 public SizeF GetAbsoluteSize( SizeF size )
4764 throw new ArgumentNullException("size");
4766 SizeF absolute = SizeF.Empty;
4768 // Convert relative coordinates to absolute coordinates
4769 absolute.Width = size.Width * (_width - 1) / 100F;
4770 absolute.Height = size.Height * (_height - 1) / 100F;
4772 // Return Absolute coordinates
4779 #region Border drawing helper methods
4782 /// Helper function which creates a rounded rectangle path.
4784 /// <param name="rect">Rectangle coordinates.</param>
4785 /// <param name="cornerRadius">Array of 4 corners radius.</param>
4786 /// <returns>Graphics path object.</returns>
4787 internal GraphicsPath CreateRoundedRectPath(RectangleF rect, float[] cornerRadius)
4789 // Create rounded rectangle path
4790 GraphicsPath path = new GraphicsPath();
4791 path.AddLine(rect.X+cornerRadius[0], rect.Y, rect.Right-cornerRadius[1], rect.Y);
4792 path.AddArc(rect.Right-2f*cornerRadius[1], rect.Y, 2f*cornerRadius[1], 2f*cornerRadius[2], 270, 90);
4793 path.AddLine(rect.Right, rect.Y + cornerRadius[2], rect.Right, rect.Bottom - cornerRadius[3]);
4794 path.AddArc(rect.Right-2f*cornerRadius[4], rect.Bottom-2f*cornerRadius[3], 2f*cornerRadius[4], 2f*cornerRadius[3], 0, 90);
4795 path.AddLine(rect.Right-cornerRadius[4], rect.Bottom, rect.X + cornerRadius[5], rect.Bottom);
4796 path.AddArc(rect.X, rect.Bottom-2f*cornerRadius[6], 2f*cornerRadius[5], 2f*cornerRadius[6], 90, 90);
4797 path.AddLine(rect.X, rect.Bottom-cornerRadius[6], rect.X, rect.Y+cornerRadius[7]);
4798 path.AddArc(rect.X, rect.Y, 2f*cornerRadius[0], 2f*cornerRadius[7], 180, 90);
4804 /// Helper function which draws a shadow of the rounded rect.
4806 /// <param name="rect">Rectangle coordinates.</param>
4807 /// <param name="cornerRadius">Array of 4 corners radius.</param>
4808 /// <param name="radius">Rounding radius.</param>
4809 /// <param name="centerColor">Center color.</param>
4810 /// <param name="surroundColor">Surrounding color.</param>
4811 /// <param name="shadowScale">Shadow scale value.</param>
4812 internal void DrawRoundedRectShadowAbs(RectangleF rect, float[] cornerRadius, float radius, Color centerColor, Color surroundColor, float shadowScale)
4814 // Create rounded rectangle path
4815 GraphicsPath path = CreateRoundedRectPath(rect, cornerRadius);
4817 // Create gradient brush
4818 PathGradientBrush shadowBrush = new PathGradientBrush(path);
4819 shadowBrush.CenterColor = centerColor;
4821 // Set the color along the entire boundary of the path
4822 Color[] colors = {surroundColor};
4823 shadowBrush.SurroundColors = colors;
4824 shadowBrush.CenterPoint = new PointF(rect.X + rect.Width/2f, rect.Y + rect.Height/2f);
4826 // Define brush focus scale
4827 PointF focusScale = new PointF(1-shadowScale*radius/rect.Width, 1-shadowScale*radius/rect.Height);
4828 shadowBrush.FocusScales = focusScale;
4830 // Draw rounded rectangle
4831 this.FillPath(shadowBrush, path);
4840 /// Draws 3D border in absolute coordinates.
4842 /// <param name="borderSkin">Border skin object.</param>
4843 /// <param name="rect">Rectangle of the border (pixel coordinates).</param>
4844 /// <param name="backColor">Color of rectangle</param>
4845 /// <param name="backHatchStyle">Hatch style</param>
4846 /// <param name="backImage">Back Image</param>
4847 /// <param name="backImageWrapMode">Image mode</param>
4848 /// <param name="backImageTransparentColor">Image transparent color.</param>
4849 /// <param name="backImageAlign">Image alignment</param>
4850 /// <param name="backGradientStyle">Gradient type </param>
4851 /// <param name="backSecondaryColor">Gradient End Color</param>
4852 /// <param name="borderColor">Border Color</param>
4853 /// <param name="borderWidth">Border Width</param>
4854 /// <param name="borderDashStyle">Border Style</param>
4855 internal void Draw3DBorderRel(
4856 BorderSkin borderSkin,
4859 ChartHatchStyle backHatchStyle,
4861 ChartImageWrapMode backImageWrapMode,
4862 Color backImageTransparentColor,
4863 ChartImageAlignmentStyle backImageAlign,
4864 GradientStyle backGradientStyle,
4865 Color backSecondaryColor,
4868 ChartDashStyle borderDashStyle)
4870 Draw3DBorderAbs(borderSkin, GetAbsoluteRectangle(rect), backColor, backHatchStyle,
4871 backImage, backImageWrapMode, backImageTransparentColor, backImageAlign, backGradientStyle,
4872 backSecondaryColor, borderColor, borderWidth, borderDashStyle);
4877 /// Draws 3D border in absolute coordinates.
4879 /// <param name="borderSkin">Border skin object.</param>
4880 /// <param name="absRect">Rectangle of the border (pixel coordinates).</param>
4881 /// <param name="backColor">Color of rectangle</param>
4882 /// <param name="backHatchStyle">Hatch style</param>
4883 /// <param name="backImage">Back Image</param>
4884 /// <param name="backImageWrapMode">Image mode</param>
4885 /// <param name="backImageTransparentColor">Image transparent color.</param>
4886 /// <param name="backImageAlign">Image alignment</param>
4887 /// <param name="backGradientStyle">Gradient type </param>
4888 /// <param name="backSecondaryColor">Gradient End Color</param>
4889 /// <param name="borderColor">Border Color</param>
4890 /// <param name="borderWidth">Border Width</param>
4891 /// <param name="borderDashStyle">Border Style</param>
4892 internal void Draw3DBorderAbs(
4893 BorderSkin borderSkin,
4896 ChartHatchStyle backHatchStyle,
4898 ChartImageWrapMode backImageWrapMode,
4899 Color backImageTransparentColor,
4900 ChartImageAlignmentStyle backImageAlign,
4901 GradientStyle backGradientStyle,
4902 Color backSecondaryColor,
4905 ChartDashStyle borderDashStyle)
4907 // Check input parameters
4908 if(_common == null || borderSkin.SkinStyle == BorderSkinStyle.None || absRect.Width == 0 || absRect.Height == 0)
4913 // Find required border interface
4914 IBorderType borderTypeInterface = _common.BorderTypeRegistry.GetBorderType(borderSkin.SkinStyle.ToString());
4915 if(borderTypeInterface != null)
4917 borderTypeInterface.Resolution = this.Graphics.DpiX;
4919 borderTypeInterface.DrawBorder(this, borderSkin, absRect, backColor, backHatchStyle, backImage, backImageWrapMode,
4920 backImageTransparentColor, backImageAlign, backGradientStyle, backSecondaryColor,
4921 borderColor, borderWidth, borderDashStyle);
4930 /// Helper function that retrieves pie drawing style.
4932 /// <param name="point">Data point to get the drawing style for.</param>
4933 /// <returns>pie drawing style.</returns>
4934 internal static PieDrawingStyle GetPieDrawingStyle(DataPoint point)
4936 // Get column drawing style
4937 PieDrawingStyle pieDrawingStyle = PieDrawingStyle.Default;
4938 string styleName = point[CustomPropertyName.PieDrawingStyle];
4939 if(styleName != null)
4941 if(String.Compare(styleName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
4943 pieDrawingStyle = PieDrawingStyle.Default;
4945 else if (String.Compare(styleName, "SoftEdge", StringComparison.OrdinalIgnoreCase) == 0)
4947 pieDrawingStyle = PieDrawingStyle.SoftEdge;
4949 else if (String.Compare(styleName, "Concave", StringComparison.OrdinalIgnoreCase) == 0)
4951 pieDrawingStyle = PieDrawingStyle.Concave;
4955 throw( new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid( styleName, "PieDrawingStyle")));
4958 return pieDrawingStyle;
4962 /// Draws a pie defined by an ellipse specified by a Rectangle structure and two radial lines.
4964 /// <param name="rect">Rectangle structure that represents the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
4965 /// <param name="startAngle">Angle measured in degrees clockwise from the x-axis to the first side of the pie shape.</param>
4966 /// <param name="sweepAngle">Angle measured in degrees clockwise from the startAngle parameter to the second side of the pie shape.</param>
4967 /// <param name="backColor">Fill color</param>
4968 /// <param name="backHatchStyle">Fill Hatch Style</param>
4969 /// <param name="backImage">Fill texture</param>
4970 /// <param name="backImageWrapMode">Texture image mode</param>
4971 /// <param name="backImageTransparentColor">Texture transparent color</param>
4972 /// <param name="backGradientStyle">Fill Gradient type </param>
4973 /// <param name="backSecondaryColor">Fill Gradient Second Color</param>
4974 /// <param name="borderColor">Border Color</param>
4975 /// <param name="borderWidth">Border Width</param>
4976 /// <param name="borderDashStyle">Border Style</param>
4977 /// <param name="shadow">True if shadow is active</param>
4978 /// <param name="doughnut">True if Doughnut is drawn instead of pie</param>
4979 /// <param name="doughnutRadius">Internal radius of the doughnut</param>
4980 /// <param name="pieDrawingStyle">Pie drawing style.</param>
4981 internal void DrawPieRel(
4986 ChartHatchStyle backHatchStyle,
4988 ChartImageWrapMode backImageWrapMode,
4989 Color backImageTransparentColor,
4990 GradientStyle backGradientStyle,
4991 Color backSecondaryColor,
4994 ChartDashStyle borderDashStyle,
4997 float doughnutRadius,
4998 PieDrawingStyle pieDrawingStyle
5001 Pen borderPen = null; // Pen
5002 Brush fillBrush; // Brush
5004 // Get absolute rectangle
5005 RectangleF absRect = GetAbsoluteRectangle( rect );
5007 if( doughnutRadius == 100.0 )
5012 if( doughnutRadius == 0.0 )
5018 if( backHatchStyle != ChartHatchStyle.None )
5020 // Create Hatch Brush
5021 fillBrush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
5023 else if( backGradientStyle != GradientStyle.None )
5025 // Create gradient brush
5026 if( backGradientStyle == GradientStyle.Center )
5028 fillBrush = GetPieGradientBrush( absRect, backColor, backSecondaryColor );
5032 using (GraphicsPath path = new GraphicsPath())
5034 path.AddPie(absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle);
5035 fillBrush = GetGradientBrush(path.GetBounds(), backColor, backSecondaryColor, backGradientStyle);
5039 else if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled )
5041 // Create textured brush
5042 fillBrush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
5046 // Create solid brush
5047 fillBrush = new SolidBrush( backColor );
5050 // Create border Pen
5051 borderPen = new Pen( borderColor, borderWidth );
5053 // Set a border line style
5054 borderPen.DashStyle = GetPenStyle( borderDashStyle );
5056 // Use rounded line joins
5057 borderPen.LineJoin = LineJoin.Round;
5062 using (GraphicsPath path = new GraphicsPath())
5065 path.AddArc(absRect.X + absRect.Width * doughnutRadius / 200 - 1, absRect.Y + absRect.Height * doughnutRadius / 200 - 1, absRect.Width - absRect.Width * doughnutRadius / 100 + 2, absRect.Height - absRect.Height * doughnutRadius / 100 + 2, startAngle, sweepAngle);
5066 path.AddArc(absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle + sweepAngle, -sweepAngle);
5070 this.FillPath(fillBrush, path);
5073 // Draw Pie gradien effects
5074 this.DrawPieGradientEffects(pieDrawingStyle, absRect, startAngle, sweepAngle, doughnutRadius);
5076 // Draw Doughnut Border
5079 borderDashStyle != ChartDashStyle.NotSet)
5081 this.DrawPath(borderPen, path);
5088 // Draw Soft shadow for pie slice
5089 if( shadow && softShadows )
5091 DrawPieSoftShadow( startAngle, sweepAngle, absRect, backColor );
5095 // Fill Pie for normal shadow or colored pie slice
5096 this.FillPie( fillBrush, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
5098 // Draw Pie gradien effects
5099 this.DrawPieGradientEffects( pieDrawingStyle, absRect, startAngle, sweepAngle, -1f);
5106 borderDashStyle != ChartDashStyle.NotSet)
5108 this.DrawPie( borderPen, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
5112 // Dispose graphics objects
5113 if( borderPen != null )
5115 borderPen.Dispose();
5118 if( fillBrush != null )
5120 fillBrush.Dispose();
5124 private void DrawPieGradientEffects(
5125 PieDrawingStyle pieDrawingStyle,
5126 RectangleF position,
5129 float doughnutRadius)
5131 if(pieDrawingStyle == PieDrawingStyle.Concave)
5133 // Calculate the size of the shadow. Note: For Doughnut chart shadow is drawn
5134 // twice on the outside and inside radius.
5135 float minSize = (float)Math.Min(position.Width, position.Height);
5136 float shadowSize = minSize * 0.05f;
5138 // Create brush path
5139 RectangleF gradientPath = position;
5140 gradientPath.Inflate(-shadowSize, -shadowSize);
5141 using(GraphicsPath brushPath = new GraphicsPath())
5143 brushPath.AddEllipse(gradientPath);
5145 // Create shadow path
5146 using(GraphicsPath path = new GraphicsPath())
5148 if(doughnutRadius < 0f)
5150 path.AddPie(Rectangle.Round(gradientPath), startAngle, sweepAngle);
5155 gradientPath.X + position.Width * doughnutRadius /200 - 1 - shadowSize,
5156 gradientPath.Y + position.Height * doughnutRadius /200 - 1 - shadowSize,
5157 gradientPath.Width - position.Width * doughnutRadius / 100 + 2 + 2f * shadowSize,
5158 gradientPath.Height - position.Height * doughnutRadius / 100 + 2 + 2f * shadowSize,
5161 path.AddArc( gradientPath.X, gradientPath.Y, gradientPath.Width, gradientPath.Height, startAngle + sweepAngle, -sweepAngle );
5164 // Create linear gradient brush
5165 gradientPath.Inflate(1f, 1f);
5166 using(LinearGradientBrush brush = new LinearGradientBrush(
5170 LinearGradientMode.Vertical) )
5172 ColorBlend colorBlend = new ColorBlend(3);
5173 colorBlend.Colors[0] = Color.FromArgb(100, Color.Black);
5174 colorBlend.Colors[1] = Color.Transparent;
5175 colorBlend.Colors[2] = Color.FromArgb(140, Color.White);
5176 colorBlend.Positions[0] = 0f;
5177 colorBlend.Positions[1] = 0.5f;
5178 colorBlend.Positions[2] = 1f;
5179 brush.InterpolationColors = colorBlend;
5182 this.FillPath( brush, path );
5188 else if(pieDrawingStyle == PieDrawingStyle.SoftEdge)
5190 // Calculate the size of the shadow. Note: For Doughnut chart shadow is drawn
5191 // twice on the outside and inside radius.
5192 float minSize = (float)Math.Min(position.Width, position.Height);
5193 float shadowSize = minSize/10f;
5194 if(doughnutRadius > 0f)
5196 shadowSize = (minSize * doughnutRadius / 100f) / 8f;
5199 // Create brush path
5200 using(GraphicsPath brushPath = new GraphicsPath())
5202 brushPath.AddEllipse(position);
5204 // Create shadow path
5205 using(GraphicsPath path = new GraphicsPath())
5207 path.AddArc( position.X + shadowSize, position.Y + shadowSize, position.Width - shadowSize * 2f, position.Height - shadowSize * 2f, startAngle, sweepAngle );
5208 path.AddArc( position.X, position.Y, position.Width, position.Height, startAngle + sweepAngle, -sweepAngle );
5211 // Create shadow brush
5212 using( PathGradientBrush brush = new PathGradientBrush(brushPath) )
5214 brush.CenterColor = Color.Transparent;
5215 brush.SurroundColors = new Color[] { Color.FromArgb(100, Color.Black) };
5217 Blend blend = new Blend(3);
5218 blend.Positions[0] = 0f;
5219 blend.Factors[0] = 0f;
5220 blend.Positions[1] = shadowSize / (minSize / 2f);
5221 blend.Factors[1] = 1f;
5222 blend.Positions[2] = 1f;
5223 blend.Factors[2] = 1f;
5224 brush.Blend = blend;
5227 this.FillPath( brush, path );
5231 // Draw inner shadow for the doughnut chart
5232 if(doughnutRadius > 0f)
5234 // Create brush path
5235 using(GraphicsPath brushInsidePath = new GraphicsPath())
5237 RectangleF innerPosition = position;
5238 innerPosition.Inflate(- position.Width * doughnutRadius / 200f + shadowSize, -position.Height * doughnutRadius / 200f + shadowSize);
5239 brushInsidePath.AddEllipse(innerPosition);
5241 // Create shadow path
5242 using(GraphicsPath path = new GraphicsPath())
5244 path.AddArc( innerPosition.X + shadowSize, innerPosition.Y + shadowSize, innerPosition.Width - 2f * shadowSize, innerPosition.Height - 2f * shadowSize, startAngle, sweepAngle );
5245 path.AddArc( innerPosition.X, innerPosition.Y, innerPosition.Width, innerPosition.Height, startAngle + sweepAngle, -sweepAngle );
5248 // Create shadow brush
5249 using( PathGradientBrush brushInner = new PathGradientBrush(brushInsidePath) )
5251 brushInner.CenterColor = Color.FromArgb(100, Color.Black);
5252 brushInner.SurroundColors = new Color[] { Color.Transparent };
5254 Blend blend = new Blend(3);
5255 blend.Positions[0] = 0f;
5256 blend.Factors[0] = 0f;
5257 blend.Positions[1] = shadowSize / (innerPosition.Width / 2f);
5258 blend.Factors[1] = 1f;
5259 blend.Positions[2] = 1f;
5260 blend.Factors[2] = 1f;
5261 brushInner.Blend = blend;
5264 this.FillPath( brushInner, path );
5274 /// The soft shadow of the pie
5276 /// <param name="startAngle">Angle measured in degrees clockwise from the x-axis to the first side of the pie shape.</param>
5277 /// <param name="sweepAngle">Angle measured in degrees clockwise from the startAngle parameter to the second side of the pie shape.</param>
5278 /// <param name="absRect">Rectangle of the pie in absolute coordinates</param>
5279 /// <param name="backColor">Fill color</param>
5280 private void DrawPieSoftShadow( float startAngle, float sweepAngle, RectangleF absRect, Color backColor )
5282 GraphicsPath path = new GraphicsPath();
5284 path.AddEllipse( absRect.X, absRect.Y, absRect.Width, absRect.Height );
5286 PathGradientBrush brush = new PathGradientBrush( path );
5289 Color.FromArgb( 0, backColor ),
5290 Color.FromArgb( backColor.A, backColor ),
5291 Color.FromArgb( backColor.A, backColor )};
5293 float[] relativePositions = {
5296 1.0f}; // at the center point.
5298 ColorBlend colorBlend = new ColorBlend();
5299 colorBlend.Colors = colors;
5300 colorBlend.Positions = relativePositions;
5301 brush.InterpolationColors = colorBlend;
5303 this.FillPie( brush, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
5308 #region Arrow Methods
5313 /// <param name="position">Position of the arrow</param>
5314 /// <param name="orientation">Orientation of the arrow - left, right, top, bottom </param>
5315 /// <param name="type">Arrow style: Triangle, Sharp Triangle, Lines</param>
5316 /// <param name="color">Color of the arrow</param>
5317 /// <param name="lineWidth">Line width</param>
5318 /// <param name="lineDashStyle">Line Dash style</param>
5319 /// <param name="shift">Distance from the chart area</param>
5320 /// <param name="size">Arrow size</param>
5321 internal void DrawArrowRel( PointF position, ArrowOrientation orientation, AxisArrowStyle type, Color color, int lineWidth, ChartDashStyle lineDashStyle, double shift, double size )
5323 // Check if arrow should be drawn
5324 if(type == AxisArrowStyle.None)
5330 using (SolidBrush brush = new SolidBrush(color))
5332 PointF endPoint = PointF.Empty; // End point of axis line
5333 PointF[] points; // arrow points
5334 PointF absolutePosition; // Absolute position of axis
5336 absolutePosition = GetAbsolutePoint(position);
5338 // Arrow type is triangle
5339 if (type == AxisArrowStyle.Triangle)
5341 points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
5343 endPoint = GetRelativePoint(endPoint);
5346 DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
5349 this.FillPolygon(brush, points);
5352 // Arrow type is sharp triangle
5353 else if (type == AxisArrowStyle.SharpTriangle)
5355 points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
5357 endPoint = GetRelativePoint(endPoint);
5360 DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
5363 this.FillPolygon(brush, points);
5366 // Arrow type is 'Lines'
5367 else if (type == AxisArrowStyle.Lines)
5369 points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
5371 points[0] = GetRelativePoint(points[0]);
5372 points[1] = GetRelativePoint(points[1]);
5373 points[2] = GetRelativePoint(points[2]);
5375 endPoint = GetRelativePoint(endPoint);
5378 DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
5379 DrawLineRel(color, lineWidth, lineDashStyle, points[0], points[2]);
5380 DrawLineRel(color, lineWidth, lineDashStyle, points[1], points[2]);
5387 /// This function calculates points for polygon, which represents
5388 /// shape of an arrow. There are four different orientations
5389 /// of arrow and three arrow types.
5391 /// <param name="position">Arrow position</param>
5392 /// <param name="orientation">Arrow orientation ( Left, Right, Top, Bottom )</param>
5393 /// <param name="shift">Distance from chart area to the arrow</param>
5394 /// <param name="size">Arrow size</param>
5395 /// <param name="type">Arrow style.</param>
5396 /// <param name="endPoint">End point of the axis and the beginning of arrow</param>
5397 /// <returns>Polygon points</returns>
5398 private PointF[] GetArrowShape( PointF position, ArrowOrientation orientation, double shift, double size, AxisArrowStyle type, ref PointF endPoint )
5400 PointF[] points = new PointF[3]; // Polygon points
5401 double sharp; // Size for sharp triangle
5403 // Four different orientations for AxisArrowStyle
5404 switch( orientation )
5407 case ArrowOrientation.Top:
5408 // Get absolute size for arrow
5409 // Arrow size has to have the same shape when width and height
5410 // are changed. When the picture is resized, width of the chart
5411 // picture is used only for arrow size.
5412 size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
5413 shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Height;
5415 // Size for sharp and regular triangle
5416 if( type == AxisArrowStyle.SharpTriangle )
5421 points[0].X = position.X - (float)size;
5422 points[0].Y = position.Y - (float)shift;
5423 points[1].X = position.X + (float)size;
5424 points[1].Y = position.Y - (float)shift;
5425 points[2].X = position.X;
5426 points[2].Y = position.Y - (float)shift - (float)sharp;
5427 // End of the axis line
5428 endPoint.X = position.X;
5429 if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
5430 endPoint.Y = points[1].Y;
5432 endPoint.Y = points[2].Y;
5435 // Bottom orientation
5436 case ArrowOrientation.Bottom:
5437 // Get absolute size for arrow
5438 // Arrow size has to have the same shape when width and height
5439 // are changed. When the picture is resized, width of the chart
5440 // picture is used only for arrow size.
5441 size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
5442 shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Height;
5444 // Size for sharp and regular triangle
5445 if( type == AxisArrowStyle.SharpTriangle )
5450 points[0].X = position.X - (float)size;
5451 points[0].Y = position.Y + (float)shift;
5452 points[1].X = position.X + (float)size;
5453 points[1].Y = position.Y + (float)shift;
5454 points[2].X = position.X;
5455 points[2].Y = position.Y + (float)shift + (float)sharp;
5456 // End of the axis line
5457 endPoint.X = position.X;
5458 if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
5459 endPoint.Y = points[1].Y;
5461 endPoint.Y = points[2].Y;
5464 case ArrowOrientation.Left:
5465 // Get absolute size for arrow
5466 size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
5467 shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Width;
5469 // Size for sharp and regular triangle
5470 if( type == AxisArrowStyle.SharpTriangle )
5475 points[0].Y = position.Y - (float)size;
5476 points[0].X = position.X - (float)shift;
5477 points[1].Y = position.Y + (float)size;
5478 points[1].X = position.X - (float)shift;
5479 points[2].Y = position.Y;
5480 points[2].X = position.X - (float)shift - (float)sharp;
5481 // End of the axis line
5482 endPoint.Y = position.Y;
5483 if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
5484 endPoint.X = points[1].X;
5486 endPoint.X = points[2].X;
5488 // Right orientation
5489 case ArrowOrientation.Right:
5490 // Get absolute size for arrow
5491 size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
5492 shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Width;
5494 // Size for sharp and regular triangle
5495 if( type == AxisArrowStyle.SharpTriangle )
5500 points[0].Y = position.Y - (float)size;
5501 points[0].X = position.X + (float)shift;
5502 points[1].Y = position.Y + (float)size;
5503 points[1].X = position.X + (float)shift;
5504 points[2].Y = position.Y;
5505 points[2].X = position.X + (float)shift + (float)sharp;
5506 // End of the axis line
5507 endPoint.Y = position.Y;
5508 if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
5509 endPoint.X = points[1].X;
5511 endPoint.X = points[2].X;
5520 #region Other methods and properties
5523 /// Helper function that retrieves bar drawing style.
5525 /// <param name="point">Data point to get the drawing style for.</param>
5526 /// <returns>Bar drawing style.</returns>
5527 internal static BarDrawingStyle GetBarDrawingStyle(DataPoint point)
5529 // Get column drawing style
5530 BarDrawingStyle barDrawingStyle = BarDrawingStyle.Default;
5531 string styleName = point[CustomPropertyName.DrawingStyle];
5532 if(styleName != null)
5534 if(String.Compare(styleName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
5536 barDrawingStyle = BarDrawingStyle.Default;
5538 else if (String.Compare(styleName, "Cylinder", StringComparison.OrdinalIgnoreCase) == 0)
5540 barDrawingStyle = BarDrawingStyle.Cylinder;
5542 else if (String.Compare(styleName, "Emboss", StringComparison.OrdinalIgnoreCase) == 0)
5544 barDrawingStyle = BarDrawingStyle.Emboss;
5546 else if (String.Compare(styleName, "LightToDark", StringComparison.OrdinalIgnoreCase) == 0)
5548 barDrawingStyle = BarDrawingStyle.LightToDark;
5550 else if (String.Compare(styleName, "Wedge", StringComparison.OrdinalIgnoreCase) == 0)
5552 barDrawingStyle = BarDrawingStyle.Wedge;
5556 throw (new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid(styleName, "DrawingStyle")));
5559 return barDrawingStyle;
5564 /// Find rounding coordinates for a rectangle
5566 /// <param name="rect">Rectangle which has to be rounded</param>
5567 /// <returns>Rounded rectangle</returns>
5568 internal RectangleF Round(RectangleF rect)
5570 float left = (float)Math.Round( (double)rect.Left );
5571 float right = (float)Math.Round( (double)rect.Right );
5572 float top = (float)Math.Round( (double)rect.Top );
5573 float bottom = (float)Math.Round( (double)rect.Bottom );
5575 return new RectangleF( left, top, right - left, bottom - top );
5579 /// This method takes a given axis value for a specified axis and returns the relative pixel value.
5581 /// <param name="chartAreaName">Chart area name.</param>
5582 /// <param name="axis">An AxisName enum value that identifies the relevant axis.</param>
5583 /// <param name="axisValue">The axis value that needs to be converted to a relative pixel value.</param>
5584 /// <returns>The converted axis value, in relative pixel coordinates.</returns>
5585 public double GetPositionFromAxis( string chartAreaName, AxisName axis, double axisValue )
5587 if( axis == AxisName.X )
5588 return _common.ChartPicture.ChartAreas[chartAreaName].AxisX.GetLinearPosition( axisValue );
5590 if( axis == AxisName.X2 )
5591 return _common.ChartPicture.ChartAreas[chartAreaName].AxisX2.GetLinearPosition( axisValue );
5593 if( axis == AxisName.Y )
5594 return _common.ChartPicture.ChartAreas[chartAreaName].AxisY.GetLinearPosition( axisValue );
5596 if( axis == AxisName.Y2 )
5597 return _common.ChartPicture.ChartAreas[chartAreaName].AxisY2.GetLinearPosition( axisValue );
5603 /// Set picture size
5605 /// <param name="width">Width</param>
5606 /// <param name="height">Height</param>
5607 internal void SetPictureSize( int width, int height )
5609 this._width = width;
5610 this._height = height;
5616 /// <param name="common">Common elements class</param>
5617 internal ChartGraphics(CommonElements common)
5619 // Set Common elements
5620 this._common = common;
5621 base.Common = common;
5622 // Create a pen object
5623 _pen = new Pen(Color.Black);
5625 // Create a brush object
5626 _solidBrush = new SolidBrush(Color.Black);
5630 /// Chart Graphics Anti alias mode
5632 internal AntiAliasingStyles AntiAliasing
5636 return _antiAliasing;
5640 _antiAliasing = value;
5642 // Graphics mode not set
5643 if( Graphics == null )
5646 // Convert Chart's anti alias enumeration to GDI+ SmoothingMode
5647 if( (_antiAliasing & AntiAliasingStyles.Graphics) == AntiAliasingStyles.Graphics )
5649 this.SmoothingMode = SmoothingMode.AntiAlias;
5653 this.SmoothingMode = SmoothingMode.None;
5659 /// Gets reusable pen.
5663 get { return _pen; }
5667 /// Sets the clipping region of this Graphics object
5668 /// to the rectangle specified by a RectangleF structure.
5670 /// <param name="region">Region rectangle</param>
5671 internal void SetClip( RectangleF region )
5673 this.SetClipAbs( GetAbsoluteRectangle( region ) );
5678 #region Color manipulation methods
5681 /// Returns the gradient color from a gradient position.
5683 /// <param name="beginColor">The color from the gradient beginning</param>
5684 /// <param name="endColor">The color from the gradient end.</param>
5685 /// <param name="relativePosition">The relative position.</param>
5686 /// <returns>Result color.</returns>
5687 static internal Color GetGradientColor(Color beginColor, Color endColor, double relativePosition)
5689 // Check if position is valid
5690 if(relativePosition < 0 || relativePosition > 1 || double.IsNaN(relativePosition))
5695 // Extracts Begin color
5696 int nBRed = beginColor.R;
5697 int nBGreen = beginColor.G;
5698 int nBBlue = beginColor.B;
5700 // Extracts End color
5701 int nERed = endColor.R;
5702 int nEGreen = endColor.G;
5703 int nEBlue = endColor.B;
5705 // Gradient positions for Red, Green and Blue colors
5706 double dRRed = nBRed + (nERed - nBRed) * relativePosition;
5707 double dRGreen = nBGreen + (nEGreen - nBGreen) * relativePosition;
5708 double dRBlue = nBBlue + (nEBlue - nBBlue) * relativePosition;
5710 // Make sure colors are in range from 0 to 255
5724 // Return a gradient color position
5725 return Color.FromArgb(beginColor.A, (int)dRRed, (int)dRGreen, (int)dRBlue);
5732 /// Returns chart right to left flag
5734 internal bool IsRightToLeft
5742 return Common.ChartPicture.RightToLeft == RightToLeft.Yes;
5746 #endregion //RightToLeft
5748 #region IDisposable Members
5750 /// Releases unmanaged and - optionally - managed resources
5752 /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
5753 protected override void Dispose(bool disposing)
5757 // Free up managed resources
5763 if (_solidBrush != null)
5765 _solidBrush.Dispose();
5768 if (_myMatrix != null)
5770 _myMatrix.Dispose();
5774 base.Dispose(disposing);