/// <summary> /// Render this <see cref="GraphObj"/> object to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphObjList"/> collection object. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="PaneBase"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> public abstract void Draw( Graphics g, PaneBase pane, float scaleFactor );
/// <summary> /// Determine if the specified screen point lies inside the bounding box of this /// <see cref="GraphObj"/>. /// </summary> /// <param name="pt">The screen point, in pixels</param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="PaneBase"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <returns>true if the point lies in the bounding box, false otherwise</returns> public virtual bool PointInBox( PointF pt, PaneBase pane, Graphics g, float scaleFactor ) { GraphPane gPane = pane as GraphPane; if ( gPane != null && _isClippedToChartRect && !gPane.Chart.Rect.Contains( pt ) ) return false; return true; }
/// <summary> /// Determines the shape type and Coords values for this GraphObj /// </summary> override public void GetCoords( PaneBase pane, Graphics g, float scaleFactor, out string shape, out string coords ) { // transform the x,y location from the user-defined // coordinate frame to the screen pixel location RectangleF pixRect = _location.TransformRect( pane ); shape = "rect"; coords = String.Format( "{0:f0},{1:f0},{2:f0},{3:f0}", pixRect.Left, pixRect.Top, pixRect.Right, pixRect.Bottom ); }
/// <summary> /// Determines the shape type and Coords values for this GraphObj /// </summary> public override void GetCoords( PaneBase pane, Graphics g, float scaleFactor, out string shape, out string coords ) { // transform the x,y location from the user-defined // coordinate frame to the screen pixel location PointF pix = _location.Transform( pane ); PointF[] pts = _fontSpec.GetBox( g, _text, pix.X, pix.Y, _location.AlignH, _location.AlignV, scaleFactor, new SizeF() ); shape = "poly"; coords = String.Format( "{0:f0},{1:f0},{2:f0},{3:f0},{4:f0},{5:f0},{6:f0},{7:f0},", pts[0].X, pts[0].Y, pts[1].X, pts[1].Y, pts[2].X, pts[2].Y, pts[3].X, pts[3].Y ); }
/// <summary> /// Create a <see cref="Pen" /> object based on the properties of this /// <see cref="LineBase" />. /// </summary> /// <param name="pane">The owner <see cref="GraphPane" /> of this /// <see cref="LineBase" />. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <param name="dataValue">The data value to be used for a value-based /// color gradient. This is only applicable if <see cref="Fill.Type">GradientFill.Type</see> /// is one of <see cref="FillType.GradientByX"/>, /// <see cref="FillType.GradientByY"/>, <see cref="FillType.GradientByZ"/>, /// or <see cref="FillType.GradientByColorValue" />. /// </param> /// <returns>A <see cref="Pen" /> object with the properties of this <see cref="LineBase" /> /// </returns> public Pen GetPen( PaneBase pane, float scaleFactor, PointPair dataValue ) { Color color = _color; if ( _gradientFill.IsGradientValueType ) color = _gradientFill.GetGradientColor( dataValue ); Pen pen = new Pen( color, pane.ScaledPenWidth( _width, scaleFactor ) ); pen.DashStyle = _style; if ( _style == DashStyle.Custom ) { CustomDashes.SetupPen(pen, this, dataValue); } return pen; }
/// <summary> /// Render this object to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphObjList"/> collection object. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> override public void Draw( Graphics g, PaneBase pane, float scaleFactor ) { // Convert the arrow coordinates from the user coordinate system // to the screen coordinate system RectangleF pixRect = this.Location.TransformRect( pane ); // Clip the rect to just outside the PaneRect so we don't end up with wild coordinates. RectangleF tmpRect = pane.Rect; tmpRect.Inflate( 20, 20 ); pixRect.Intersect( tmpRect ); if ( Math.Abs( pixRect.Left ) < 100000 && Math.Abs( pixRect.Top ) < 100000 && Math.Abs( pixRect.Right ) < 100000 && Math.Abs( pixRect.Bottom ) < 100000 ) { // If the box is to be filled, fill it _fill.Draw( g, pixRect ); // Draw the border around the box if required _border.Draw( g, pane, scaleFactor, pixRect ); } }
/// <summary> /// Render this object to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphObjList"/> collection object. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> public override void Draw(Graphics g, PaneBase pane, float scaleFactor) { // Convert the arrow coordinates from the user coordinate system // to the screen coordinate system PointF pix1 = Location.TransformTopLeft(pane); PointF pix2 = Location.TransformBottomRight(pane); if (pix1.X > -10000 && pix1.X < 100000 && pix1.Y > -100000 && pix1.Y < 100000 && pix2.X > -10000 && pix2.X < 100000 && pix2.Y > -100000 && pix2.Y < 100000) { // calculate the length and the angle of the arrow "vector" double dy = pix2.Y - pix1.Y; double dx = pix2.X - pix1.X; float angle = (float) Math.Atan2(dy, dx)*180.0F/(float) Math.PI; var length = (float) Math.Sqrt(dx*dx + dy*dy); // Save the old transform matrix Matrix transform = g.Transform; // Move the coordinate system so it is located at the starting point // of this arrow g.TranslateTransform(pix1.X, pix1.Y); // Rotate the coordinate system according to the angle of this arrow // about the starting point g.RotateTransform(angle); // get a pen according to this arrow properties using (var pen = new Pen(_color, pane.ScaledPenWidth(_penWidth, scaleFactor))) { pen.DashStyle = _style; g.DrawLine(pen, 0, 0, length, 0); } // Restore the transform matrix back to its original state g.Transform = transform; } }
/// <summary> /// Render this <see cref="GraphObj"/> object to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphObjList"/> collection object. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="PaneBase"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> abstract public void Draw(Graphics g, PaneBase pane, float scaleFactor);
/// <summary> /// Transform the <see cref="RectangleF"/> for this object as defined by the /// <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and /// <see cref="Height"/> properties. /// </summary> /// <remarks> /// This method transforms the location to output device pixel units. /// The <see cref="AlignH"/> and <see cref="AlignV"/> properties are honored in /// this transformation. /// </remarks> /// <value>A <see cref="RectangleF"/> in pixel units.</value> public RectangleF TransformRect(PaneBase pane) { PointF pix1 = TransformTopLeft(pane); PointF pix2 = TransformBottomRight(pane); //PointF pix3 = TransformTopLeft( pane, pix2.X - pix1.X, pix2.Y - pix1.Y ); return new RectangleF(pix1.X, pix1.Y, Math.Abs(pix2.X - pix1.X), Math.Abs(pix2.Y - pix1.Y)); }
public Pen GetPen( PaneBase pane, float scaleFactor, PointPair dataValue ) { Color color = _color; if ( _gradientFill.IsGradientValueType ) color = _gradientFill.GetGradientColor( dataValue ); Pen pen = new Pen( color, pane.ScaledPenWidth( _width, scaleFactor ) ); pen.DashStyle = _style; if ( _style == DashStyle.Custom ) { if ( _dashOff > 1e-10 && _dashOn > 1e-10 ) { pen.DashStyle = DashStyle.Custom; float[] pattern = new float[2]; pattern[0] = _dashOn; pattern[1] = _dashOff; pen.DashPattern = pattern; } else pen.DashStyle = DashStyle.Solid; } return pen; }
/// <summary> /// Calculate the <see cref="Legend"/> rectangle (<see cref="Rect"/>), /// taking into account the number of required legend /// entries, and the legend drawing preferences. /// </summary> /// <remarks>Adjust the size of the /// <see cref="Chart.Rect"/> for the parent <see cref="GraphPane"/> to accomodate the /// space required by the legend. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <param name="tChartRect"> /// The rectangle that contains the area bounded by the axes, in pixel units. /// <seealso cref="Chart.Rect" /> /// </param> public void CalcRect(Graphics g, PaneBase pane, float scaleFactor, ref RectangleF tChartRect) { // Start with an empty rectangle _rect = Rectangle.Empty; _hStack = 1; _legendItemWidth = 1; _legendItemHeight = 0; RectangleF clientRect = pane.CalcClientRect(g, scaleFactor); // If the legend is invisible, don't do anything if (!_isVisible) { return; } int nCurve = 0; PaneList paneList = GetPaneList(pane); _tmpSize = GetMaxHeight(paneList, g, scaleFactor); float halfGap = _tmpSize / 2.0F, maxWidth = 0, tmpWidth, gapPix = _gap * _tmpSize; foreach (GraphPane tmpPane in paneList) { // Loop through each curve in the curve list // Find the maximum width of the legend labels //foreach ( CurveItem curve in tmpPane.CurveList ) //foreach ( CurveItem curve in GetIterator( tmpPane.CurveList, _isReverse ) ) int count = tmpPane.CurveList.Count; for (int i = 0; i < count; i++) { CurveItem curve = tmpPane.CurveList[_isReverse ? count - i - 1 : i]; if (curve._label._text != string.Empty && curve._label._isVisible) { // Calculate the width of the label save the max width FontSpec tmpFont = (curve._label._fontSpec != null) ? curve._label._fontSpec : this.FontSpec; tmpWidth = tmpFont.GetWidth(g, curve._label._text, scaleFactor); if (tmpWidth > maxWidth) { maxWidth = tmpWidth; } // Save the maximum symbol height for line-type curves if (curve is LineItem && ((LineItem)curve).Symbol.Size > _legendItemHeight) { _legendItemHeight = ((LineItem)curve).Symbol.Size; } nCurve++; } } if (pane is MasterPane && ((MasterPane)pane).IsUniformLegendEntries) { break; } } float widthAvail; // Is this legend horizontally stacked? if (_isHStack) { // Determine the available space for horizontal stacking switch (_position) { // Never stack if the legend is to the right or left case LegendPos.Right: case LegendPos.Left: widthAvail = 0; break; // for the top & bottom, the axis border width is available case LegendPos.Top: case LegendPos.TopCenter: case LegendPos.Bottom: case LegendPos.BottomCenter: widthAvail = tChartRect.Width; break; // for the top & bottom flush left, the panerect less margins is available case LegendPos.TopFlushLeft: case LegendPos.BottomFlushLeft: widthAvail = clientRect.Width; break; // for inside the axis area or Float, use 1/2 of the axis border width case LegendPos.InsideTopRight: case LegendPos.InsideTopLeft: case LegendPos.InsideBotRight: case LegendPos.InsideBotLeft: case LegendPos.Float: widthAvail = tChartRect.Width / 2; break; // shouldn't ever happen default: widthAvail = 0; break; } // width of one legend entry if (_isShowLegendSymbols) { _legendItemWidth = 3.0f * _tmpSize + maxWidth; } else { _legendItemWidth = 0.5f * _tmpSize + maxWidth; } // Calculate the number of columns in the legend // Normally, the legend is: // available width / ( max width of any entry + space for line&symbol ) if (maxWidth > 0) { _hStack = (int)((widthAvail - halfGap) / _legendItemWidth); } // You can never have more columns than legend entries if (_hStack > nCurve) { _hStack = nCurve; } // a saftey check if (_hStack == 0) { _hStack = 1; } } else { if (_isShowLegendSymbols) { _legendItemWidth = 3.0F * _tmpSize + maxWidth; } else { _legendItemWidth = 0.5F * _tmpSize + maxWidth; } } // legend is: // item: space line space text space // width: wid 4*wid wid maxWid wid // The symbol is centered on the line // // legend begins 3 * wid to the right of the plot rect // // The height of the legend is the actual height of the lines of text // (nCurve * hite) plus wid on top and wid on the bottom // total legend width float totLegWidth = _hStack * _legendItemWidth; // The total legend height _legendItemHeight = _legendItemHeight * (float)scaleFactor + halfGap; if (_tmpSize > _legendItemHeight) { _legendItemHeight = _tmpSize; } float totLegHeight = (float)Math.Ceiling((double)nCurve / (double)_hStack) * _legendItemHeight; RectangleF newRect = new RectangleF(); // Now calculate the legend rect based on the above determined parameters // Also, adjust the ChartRect to reflect the space for the legend if (nCurve > 0) { newRect = new RectangleF(0, 0, totLegWidth, totLegHeight); // The switch statement assigns the left and top edges, and adjusts the ChartRect // as required. The right and bottom edges are calculated at the bottom of the switch. switch (_position) { case LegendPos.Right: newRect.X = clientRect.Right - totLegWidth; newRect.Y = tChartRect.Top; tChartRect.Width -= totLegWidth + gapPix; break; case LegendPos.Top: newRect.X = tChartRect.Left; newRect.Y = clientRect.Top; tChartRect.Y += totLegHeight + gapPix; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.TopFlushLeft: newRect.X = clientRect.Left; newRect.Y = clientRect.Top; tChartRect.Y += totLegHeight + gapPix * 1.5f; tChartRect.Height -= totLegHeight + gapPix * 1.5f; break; case LegendPos.TopCenter: newRect.X = tChartRect.Left + (tChartRect.Width - totLegWidth) / 2; newRect.Y = tChartRect.Top; tChartRect.Y += totLegHeight + gapPix; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.Bottom: newRect.X = tChartRect.Left; newRect.Y = clientRect.Bottom - totLegHeight; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.BottomFlushLeft: newRect.X = clientRect.Left; newRect.Y = clientRect.Bottom - totLegHeight; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.BottomCenter: newRect.X = tChartRect.Left + (tChartRect.Width - totLegWidth) / 2; newRect.Y = clientRect.Bottom - totLegHeight; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.Left: newRect.X = clientRect.Left; newRect.Y = tChartRect.Top; tChartRect.X += totLegWidth + halfGap; tChartRect.Width -= totLegWidth + gapPix; break; case LegendPos.InsideTopRight: newRect.X = tChartRect.Right - totLegWidth; newRect.Y = tChartRect.Top; break; case LegendPos.InsideTopLeft: newRect.X = tChartRect.Left; newRect.Y = tChartRect.Top; break; case LegendPos.InsideBotRight: newRect.X = tChartRect.Right - totLegWidth; newRect.Y = tChartRect.Bottom - totLegHeight; break; case LegendPos.InsideBotLeft: newRect.X = tChartRect.Left; newRect.Y = tChartRect.Bottom - totLegHeight; break; case LegendPos.Float: newRect.Location = this.Location.TransformTopLeft(pane, totLegWidth, totLegHeight); break; } } _rect = newRect; }
/// <summary> /// Render the <see cref="Legend"/> to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphPane"/> object. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> public void Draw(Graphics g, PaneBase pane, float scaleFactor) { // if the legend is not visible, do nothing if (!_isVisible) { return; } // Fill the background with the specified color if required _fill.Draw(g, _rect); PaneList paneList = GetPaneList(pane); float halfGap = _tmpSize / 2.0F; // Check for bad data values if (_hStack <= 0) { _hStack = 1; } if (_legendItemWidth <= 0) { _legendItemWidth = 100; } if (_legendItemHeight <= 0) { _legendItemHeight = _tmpSize; } //float gap = pane.ScaledGap( scaleFactor ); int iEntry = 0; float x, y; // Get a brush for the legend label text using (SolidBrush brushB = new SolidBrush(Color.Black)) { foreach (GraphPane tmpPane in paneList) { // Loop for each curve in the CurveList collection //foreach ( CurveItem curve in tmpPane.CurveList ) int count = tmpPane.CurveList.Count; for (int i = 0; i < count; i++) { CurveItem curve = tmpPane.CurveList[_isReverse ? count - i - 1 : i]; if (curve._label._text != string.Empty && curve._label._isVisible) { // Calculate the x,y (TopLeft) location of the current // curve legend label // assuming: // charHeight/2 for the left margin, plus legendWidth for each // horizontal column // legendHeight is the line spacing, with no extra margin above x = _rect.Left + halfGap / 2.0F + (iEntry % _hStack) * _legendItemWidth; y = _rect.Top + (int)(iEntry / _hStack) * _legendItemHeight; // Draw the legend label for the current curve FontSpec tmpFont = (curve._label._fontSpec != null) ? curve._label._fontSpec : this.FontSpec; // This is required because, for long labels, the centering can affect the // position in GDI+. tmpFont.StringAlignment = StringAlignment.Near; if (_isShowLegendSymbols) { tmpFont.Draw(g, pane, curve._label._text, x + 2.5F * _tmpSize, y + _legendItemHeight / 2.0F, AlignH.Left, AlignV.Center, scaleFactor); RectangleF rect = new RectangleF(x, y + _legendItemHeight / 4.0F, 2 * _tmpSize, _legendItemHeight / 2.0F); curve.DrawLegendKey(g, tmpPane, rect, scaleFactor); } else { if (curve._label._fontSpec == null) { tmpFont.FontColor = curve.Color; } tmpFont.Draw(g, pane, curve._label._text, x + 0.0F * _tmpSize, y + _legendItemHeight / 2.0F, AlignH.Left, AlignV.Center, scaleFactor); } // maintain a curve count for positioning iEntry++; } } if (pane is MasterPane && ((MasterPane)pane).IsUniformLegendEntries) { break; } } // Draw a border around the legend if required if (iEntry > 0) { this.Border.Draw(g, pane, scaleFactor, _rect); } } }
/// <summary> /// Determines the shape type and Coords values for this GraphObj /// </summary> abstract public void GetCoords(PaneBase pane, Graphics g, float scaleFactor, out string shape, out string coords);
/// <summary> /// Determine if a mouse point is within the legend, and if so, which legend /// entry (<see cref="CurveItem"/>) is nearest. /// </summary> /// <param name="mousePt">The screen point, in pixel coordinates.</param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <param name="index">The index number of the <see cref="CurveItem"/> legend /// entry that is under the mouse point. The <see cref="CurveItem"/> object is /// accessible via <see cref="GraphPane.CurveList">CurveList[index]</see>. /// </param> /// <returns>true if the mouse point is within the <see cref="Legend"/> bounding /// box, false otherwise.</returns> /// <seealso cref="GraphPane.FindNearestObject"/> public bool FindPoint( PointF mousePt, PaneBase pane, float scaleFactor, out int index ) { index = -1; if ( _rect.Contains( mousePt ) ) { int j = (int)( ( mousePt.Y - _rect.Top ) / _legendItemHeight ); int i = (int)( ( mousePt.X - _rect.Left - _tmpSize / 2.0f ) / _legendItemWidth ); if ( i < 0 ) i = 0; if ( i >= _hStack ) i = _hStack - 1; int pos = i + j * _hStack; index = 0; PaneList paneList = GetPaneList( pane ); foreach ( GraphPane tmpPane in paneList ) { foreach ( CurveItem curve in tmpPane.CurveList ) { if ( curve._label._isVisible && curve._label._text != string.Empty ) { if ( pos == 0 ) return true; pos--; } index++; } } return true; } else return false; }
/// <summary> /// Determines the shape type and Coords values for this GraphObj /// </summary> public override void GetCoords(PaneBase pane, Graphics g, float scaleFactor, out string shape, out string coords) { // transform the x,y location from the user-defined // coordinate frame to the screen pixel location RectangleF pixRect = _location.TransformRect(pane); var matrix = new Matrix(); if (pixRect.Right == 0) pixRect.Width = 1; var angle = (float) Math.Atan((pixRect.Top - pixRect.Bottom)/ (pixRect.Left - pixRect.Right)); matrix.Rotate(angle, MatrixOrder.Prepend); // Move the coordinate system to local coordinates // of this text object (that is, at the specified // x,y location) matrix.Translate(-pixRect.Left, -pixRect.Top, MatrixOrder.Prepend); var pts = new PointF[4]; pts[0] = new PointF(0, 3); pts[1] = new PointF(pixRect.Width, 3); pts[2] = new PointF(pixRect.Width, -3); pts[3] = new PointF(0, -3); matrix.TransformPoints(pts); shape = "poly"; coords = String.Format("{0:f0},{1:f0},{2:f0},{3:f0},{4:f0},{5:f0},{6:f0},{7:f0},", pts[0].X, pts[0].Y, pts[1].X, pts[1].Y, pts[2].X, pts[2].Y, pts[3].X, pts[3].Y); }
/// <summary> /// Calculate the <see cref="Legend"/> rectangle (<see cref="Rect"/>), /// taking into account the number of required legend /// entries, and the legend drawing preferences. /// </summary> /// <remarks>Adjust the size of the /// <see cref="Chart.Rect"/> for the parent <see cref="GraphPane"/> to accomodate the /// space required by the legend. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <param name="tChartRect"> /// The rectangle that contains the area bounded by the axes, in pixel units. /// <seealso cref="Chart.Rect" /> /// </param> public void CalcRect( Graphics g, PaneBase pane, float scaleFactor, ref RectangleF tChartRect ) { // Start with an empty rectangle _rect = Rectangle.Empty; _hStack = 1; _legendItemWidth = 1; _legendItemHeight = 0; RectangleF clientRect = pane.CalcClientRect( g, scaleFactor ); // If the legend is invisible, don't do anything if ( !_isVisible ) return; int nCurve = 0; PaneList paneList = GetPaneList( pane ); _tmpSize = GetMaxHeight( paneList, g, scaleFactor ); float halfGap = _tmpSize / 2.0F, maxWidth = 0, tmpWidth, gapPix = _gap * _tmpSize; foreach ( GraphPane tmpPane in paneList ) { // Loop through each curve in the curve list // Find the maximum width of the legend labels //foreach ( CurveItem curve in tmpPane.CurveList ) //foreach ( CurveItem curve in GetIterator( tmpPane.CurveList, _isReverse ) ) int count = tmpPane.CurveList.Count; for ( int i = 0; i < count; i++ ) { CurveItem curve = tmpPane.CurveList[_isReverse ? count - i - 1 : i]; if ( curve._label._text != string.Empty && curve._label._isVisible ) { // Calculate the width of the label save the max width FontSpec tmpFont = ( curve._label._fontSpec != null ) ? curve._label._fontSpec : this.FontSpec; tmpWidth = tmpFont.GetWidth( g, curve._label._text, scaleFactor ) / 2; if ( tmpWidth > maxWidth ) maxWidth = tmpWidth; // Save the maximum symbol height for line-type curves if ( curve is LineItem && ( (LineItem)curve ).Symbol.Size > _legendItemHeight ) _legendItemHeight = ( (LineItem)curve ).Symbol.Size; nCurve++; } } if ( pane is MasterPane && ( (MasterPane)pane ).IsUniformLegendEntries ) break; } float widthAvail; // Is this legend horizontally stacked? if ( _isHStack ) { // Determine the available space for horizontal stacking switch ( _position ) { // Never stack if the legend is to the right or left case LegendPos.Right: case LegendPos.Left: widthAvail = 0; break; // for the top & bottom, the axis border width is available case LegendPos.Top: case LegendPos.TopCenter: case LegendPos.Bottom: case LegendPos.BottomCenter: widthAvail = tChartRect.Width; break; // for the top & bottom flush left, the panerect less margins is available case LegendPos.TopFlushLeft: case LegendPos.BottomFlushLeft: widthAvail = clientRect.Width; break; // for inside the axis area or Float, use 1/2 of the axis border width case LegendPos.InsideTopRight: case LegendPos.InsideTopLeft: case LegendPos.InsideBotRight: case LegendPos.InsideBotLeft: case LegendPos.Float: widthAvail = tChartRect.Width / 2; break; // shouldn't ever happen default: widthAvail = 0; break; } // width of one legend entry if ( _isShowLegendSymbols ) _legendItemWidth = 3.0f * _tmpSize + maxWidth; else _legendItemWidth = 0.5f * _tmpSize + maxWidth; // Calculate the number of columns in the legend // Normally, the legend is: // available width / ( max width of any entry + space for line&symbol ) if ( maxWidth > 0 ) _hStack = (int)( ( widthAvail - halfGap ) / _legendItemWidth ); // You can never have more columns than legend entries if ( _hStack > nCurve ) _hStack = nCurve; // a saftey check if ( _hStack == 0 ) _hStack = 1; } else { if ( _isShowLegendSymbols ) _legendItemWidth = 3.0F * _tmpSize + maxWidth; else _legendItemWidth = 0.5F * _tmpSize + maxWidth; } // legend is: // item: space line space text space // width: wid 4*wid wid maxWid wid // The symbol is centered on the line // // legend begins 3 * wid to the right of the plot rect // // The height of the legend is the actual height of the lines of text // (nCurve * hite) plus wid on top and wid on the bottom // total legend width float totLegWidth = _hStack * _legendItemWidth; // The total legend height _legendItemHeight = _legendItemHeight * (float)scaleFactor + halfGap; if ( _tmpSize > _legendItemHeight ) _legendItemHeight = _tmpSize; float totLegHeight = (float)Math.Ceiling( (double)nCurve / (double)_hStack ) * _legendItemHeight; RectangleF newRect = new RectangleF(); // Now calculate the legend rect based on the above determined parameters // Also, adjust the ChartRect to reflect the space for the legend if ( nCurve > 0 ) { newRect = new RectangleF( 0, 0, totLegWidth, totLegHeight ); // The switch statement assigns the left and top edges, and adjusts the ChartRect // as required. The right and bottom edges are calculated at the bottom of the switch. switch ( _position ) { case LegendPos.Right: newRect.X = clientRect.Right - totLegWidth; newRect.Y = tChartRect.Top; tChartRect.Width -= totLegWidth + gapPix; break; case LegendPos.Top: newRect.X = tChartRect.Left; newRect.Y = clientRect.Top; tChartRect.Y += totLegHeight + gapPix; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.TopFlushLeft: newRect.X = clientRect.Left; newRect.Y = clientRect.Top; tChartRect.Y += totLegHeight + gapPix * 1.5f; tChartRect.Height -= totLegHeight + gapPix * 1.5f; break; case LegendPos.TopCenter: newRect.X = tChartRect.Left + ( tChartRect.Width - totLegWidth ) / 2; newRect.Y = tChartRect.Top; tChartRect.Y += totLegHeight + gapPix; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.Bottom: newRect.X = tChartRect.Left; newRect.Y = clientRect.Bottom - totLegHeight; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.BottomFlushLeft: newRect.X = clientRect.Left; newRect.Y = clientRect.Bottom - totLegHeight; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.BottomCenter: newRect.X = tChartRect.Left + ( tChartRect.Width - totLegWidth ) / 2; newRect.Y = clientRect.Bottom - totLegHeight; tChartRect.Height -= totLegHeight + gapPix; break; case LegendPos.Left: newRect.X = clientRect.Left; newRect.Y = tChartRect.Top; tChartRect.X += totLegWidth + halfGap; tChartRect.Width -= totLegWidth + gapPix; break; case LegendPos.InsideTopRight: newRect.X = tChartRect.Right - totLegWidth; newRect.Y = tChartRect.Top; break; case LegendPos.InsideTopLeft: newRect.X = tChartRect.Left; newRect.Y = tChartRect.Top; break; case LegendPos.InsideBotRight: newRect.X = tChartRect.Right - totLegWidth; newRect.Y = tChartRect.Bottom - totLegHeight; break; case LegendPos.InsideBotLeft: newRect.X = tChartRect.Left; newRect.Y = tChartRect.Bottom - totLegHeight; break; case LegendPos.Float: newRect.Location = this.Location.TransformTopLeft( pane, totLegWidth, totLegHeight ); break; } } _rect = newRect; }
/// <summary> /// Determine if the specified screen point lies inside the bounding box of this /// <see cref="LineObj"/>. /// </summary> /// <remarks>The bounding box is calculated assuming a distance /// of <see cref="GraphPane.Default.NearestTol"/> pixels around the arrow segment. /// </remarks> /// <param name="pt">The screen point, in pixels</param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <returns>true if the point lies in the bounding box, false otherwise</returns> public override bool PointInBox(PointF pt, PaneBase pane, Graphics g, float scaleFactor) { if (! base.PointInBox(pt, pane, g, scaleFactor)) return false; // transform the x,y location from the user-defined // coordinate frame to the screen pixel location PointF pix = _location.TransformTopLeft(pane); PointF pix2 = _location.TransformBottomRight(pane); using (var pen = new Pen(Color.Black, (float) GraphPane.Default.NearestTol*2.0F)) { using (var path = new GraphicsPath()) { path.AddLine(pix, pix2); return path.IsOutlineVisible(pt, pen); } } }
/// <summary> /// Create a <see cref="Pen" /> object based on the properties of this /// <see cref="LineBase" />. /// </summary> /// <param name="pane">The owner <see cref="GraphPane" /> of this /// <see cref="LineBase" />. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <returns>A <see cref="Pen" /> object with the properties of this <see cref="LineBase" /> /// </returns> public Pen GetPen( PaneBase pane, float scaleFactor ) { return GetPen( pane, scaleFactor, null ); }
/// <summary> /// Render the specified <paramref name="text"/> to the specifed /// <see cref="Graphics"/> device. The text, border, and fill options /// will be rendered as required. /// </summary> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="text">A string value containing the text to be /// displayed. This can be multiple lines, separated by newline ('\n') /// characters</param> /// <param name="x">The X location to display the text, in screen /// coordinates, relative to the horizontal (<see cref="AlignH"/>) /// alignment parameter <paramref name="alignH"/></param> /// <param name="y">The Y location to display the text, in screen /// coordinates, relative to the vertical (<see cref="AlignV"/> /// alignment parameter <paramref name="alignV"/></param> /// <param name="alignH">A horizontal alignment parameter specified /// using the <see cref="AlignH"/> enum type</param> /// <param name="alignV">A vertical alignment parameter specified /// using the <see cref="AlignV"/> enum type</param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> public void Draw( Graphics g, PaneBase pane, string text, float x, float y, AlignH alignH, AlignV alignV, float scaleFactor ) { this.Draw( g, pane, text, x, y, alignH, alignV, scaleFactor, new SizeF() ); }
/// <summary> /// Render this object to the specified <see cref="Graphics"/> device /// This method is normally only called by the Draw method /// of the parent <see cref="GraphObjList"/> collection object. /// </summary> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> public override void Draw(Graphics g, PaneBase pane, float scaleFactor) { if (_image != null) { // Convert the rectangle coordinates from the user coordinate system // to the screen coordinate system RectangleF tmpRect = _location.TransformRect(pane); if (_isScaled) g.DrawImage(_image, tmpRect); else { Region clip = g.Clip; g.SetClip(tmpRect); g.DrawImageUnscaled(_image, Rectangle.Round(tmpRect)); g.SetClip(clip, CombineMode.Replace); //g.DrawImageUnscaledAndClipped( image, Rectangle.Round( tmpRect ) ); } } }
/// <summary> /// Render the specified <paramref name="text"/> to the specifed /// <see cref="Graphics"/> device. The text, border, and fill options /// will be rendered as required. /// </summary> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="text">A string value containing the text to be /// displayed. This can be multiple lines, separated by newline ('\n') /// characters</param> /// <param name="x">The X location to display the text, in screen /// coordinates, relative to the horizontal (<see cref="AlignH"/>) /// alignment parameter <paramref name="alignH"/></param> /// <param name="y">The Y location to display the text, in screen /// coordinates, relative to the vertical (<see cref="AlignV"/> /// alignment parameter <paramref name="alignV"/></param> /// <param name="alignH">A horizontal alignment parameter specified /// using the <see cref="AlignH"/> enum type</param> /// <param name="alignV">A vertical alignment parameter specified /// using the <see cref="AlignV"/> enum type</param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <param name="layoutArea">The limiting area (<see cref="SizeF"/>) into which the text /// must fit. The actual rectangle may be smaller than this, but the text will be wrapped /// to accomodate the area.</param> public void Draw( Graphics g, PaneBase pane, string text, float x, float y, AlignH alignH, AlignV alignV, float scaleFactor, SizeF layoutArea ) { // make sure the font size is properly scaled //Remake( scaleFactor, this.Size, ref this.scaledSize, ref this.font ); SmoothingMode sModeSave = g.SmoothingMode; TextRenderingHint sHintSave = g.TextRenderingHint; if ( _isAntiAlias ) { g.SmoothingMode = SmoothingMode.HighQuality; g.TextRenderingHint = TextRenderingHint.AntiAlias; } SizeF sizeF; if ( layoutArea.IsEmpty ) sizeF = MeasureString( g, text, scaleFactor ); else sizeF = MeasureString( g, text, scaleFactor, layoutArea ); // Save the old transform matrix for later restoration Matrix saveMatrix = g.Transform; g.Transform = SetupMatrix( g.Transform, x, y, sizeF, alignH, alignV, _angle ); // Create a rectangle representing the border around the // text. Note that, while the text is drawn based on the // TopCenter position, the rectangle is drawn based on // the TopLeft position. Therefore, move the rectangle // width/2 to the left to align it properly RectangleF rectF = new RectangleF( -sizeF.Width / 2.0F, 0.0F, sizeF.Width, sizeF.Height ); // If the background is to be filled, fill it _fill.Draw( g, rectF ); // Draw the border around the text if required _border.Draw( g, pane, scaleFactor, rectF ); // make a center justified StringFormat alignment // for drawing the text StringFormat strFormat = new StringFormat(); strFormat.Alignment = _stringAlignment; // if ( this.stringAlignment == StringAlignment.Far ) // g.TranslateTransform( sizeF.Width / 2.0F, 0F, MatrixOrder.Prepend ); // else if ( this.stringAlignment == StringAlignment.Near ) // g.TranslateTransform( -sizeF.Width / 2.0F, 0F, MatrixOrder.Prepend ); // Draw the drop shadow text. Note that the coordinate system // is set up such that 0,0 is at the location where the // CenterTop of the text needs to be. if ( _isDropShadow ) { float xShift = (float)( Math.Cos( _dropShadowAngle ) * _dropShadowOffset * _font.Height ); float yShift = (float)( Math.Sin( _dropShadowAngle ) * _dropShadowOffset * _font.Height ); RectangleF rectD = rectF; rectD.Offset( xShift, yShift ); // make a solid brush for rendering the font itself using ( SolidBrush brushD = new SolidBrush( _dropShadowColor ) ) g.DrawString( text, _font, brushD, rectD, strFormat ); } // make a solid brush for rendering the font itself using ( SolidBrush brush = new SolidBrush( _fontColor ) ) { // Draw the actual text. Note that the coordinate system // is set up such that 0,0 is at the location where the // CenterTop of the text needs to be. //RectangleF layoutArea = new RectangleF( 0.0F, 0.0F, sizeF.Width, sizeF.Height ); g.DrawString( text, _font, brush, rectF, strFormat ); //System.Diagnostics.Trace.WriteLine(string.Format("draw {0} font size {1}", // text, _font.Size)); } // Restore the transform matrix back to original g.Transform = saveMatrix; g.SmoothingMode = sModeSave; g.TextRenderingHint = sHintSave; }
/// <summary> /// Determine if the specified screen point lies inside the bounding box of this /// <see cref="BoxObj"/>. /// </summary> /// <param name="pt">The screen point, in pixels</param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <returns>true if the point lies in the bounding box, false otherwise</returns> override public bool PointInBox( PointF pt, PaneBase pane, Graphics g, float scaleFactor ) { if ( ! base.PointInBox(pt, pane, g, scaleFactor ) ) return false; // transform the x,y location from the user-defined // coordinate frame to the screen pixel location RectangleF pixRect = _location.TransformRect( pane ); return pixRect.Contains( pt ); }
/// <summary> /// Render this object to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphObjList"/> collection object. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> override public void Draw( Graphics g, PaneBase pane, float scaleFactor ) { if ( _points != null && _points.Length > 1 ) { using ( GraphicsPath path = MakePath( pane ) ) { // Fill or draw the symbol as required if ( _fill.IsVisible ) { using ( Brush brush = this.Fill.MakeBrush( path.GetBounds() ) ) g.FillPath( brush, path ); } if ( _border.IsVisible ) { using ( Pen pen = _border.GetPen( pane, scaleFactor ) ) g.DrawPath( pen, path ); } } } }
/// <summary> /// Render this <see cref="TextObj"/> object to the specified <see cref="Graphics"/> device /// This method is normally only called by the Draw method /// of the parent <see cref="GraphObjList"/> collection object. /// </summary> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> public override void Draw( Graphics g, PaneBase pane, float scaleFactor ) { // transform the x,y location from the user-defined // coordinate frame to the screen pixel location PointF pix = _location.Transform( pane ); // Draw the text on the screen, including any frame and background // fill elements if ( pix.X > -100000 && pix.X < 100000 && pix.Y > -100000 && pix.Y < 100000 ) { //if ( this.layoutSize.IsEmpty ) // this.FontSpec.Draw( g, pane.IsPenWidthScaled, this.text, pix.X, pix.Y, // this.location.AlignH, this.location.AlignV, scaleFactor ); //else this.FontSpec.Draw( g, pane, _text, pix.X, pix.Y, _location.AlignH, _location.AlignV, scaleFactor, _layoutArea ); } }
internal GraphicsPath MakePath( PaneBase pane ) { GraphicsPath path = new GraphicsPath(); bool first = true; PointF lastPt = new PointF(); foreach( PointD pt in _points ) { // Convert the coordinates from the user coordinate system // to the screen coordinate system // Offset the points by the location value PointF pixPt = Location.Transform( pane, pt.X + _location.X, pt.Y + _location.Y, _location.CoordinateFrame ); if ( Math.Abs( pixPt.X ) < 100000 && Math.Abs( pixPt.Y ) < 100000 ) { if ( first ) first = false; else path.AddLine( lastPt, pixPt ); lastPt = pixPt; } } if ( _isClosedFigure ) path.CloseFigure(); return path; }
/// <summary> /// Determine if the specified screen point lies inside the bounding box of this /// <see cref="TextObj"/>. This method takes into account rotation and alignment /// parameters of the text, as specified in the <see cref="FontSpec"/>. /// </summary> /// <param name="pt">The screen point, in pixels</param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <returns>true if the point lies in the bounding box, false otherwise</returns> public override bool PointInBox( PointF pt, PaneBase pane, Graphics g, float scaleFactor ) { if ( ! base.PointInBox(pt, pane, g, scaleFactor ) ) return false; // transform the x,y location from the user-defined // coordinate frame to the screen pixel location PointF pix = _location.Transform( pane ); return _fontSpec.PointInBox( pt, g, _text, pix.X, pix.Y, _location.AlignH, _location.AlignV, scaleFactor, this.LayoutArea ); }
/// <summary> /// Determine if the specified screen point lies inside the bounding box of this /// <see cref="PolyObj"/>. /// </summary> /// <param name="pt">The screen point, in pixels</param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <returns>true if the point lies in the bounding box, false otherwise</returns> override public bool PointInBox( PointF pt, PaneBase pane, Graphics g, float scaleFactor ) { if ( _points != null && _points.Length > 1 ) { if ( ! base.PointInBox(pt, pane, g, scaleFactor ) ) return false; using ( GraphicsPath path = MakePath( pane ) ) return path.IsVisible( pt ); } else return false; }
/// <summary> /// Determines the shape type and Coords values for this GraphObj /// </summary> public abstract void GetCoords( PaneBase pane, Graphics g, float scaleFactor, out string shape, out string coords );
/// <summary> /// The Copy Constructor /// </summary> /// <param name="rhs">The <see cref="PaneBase"/> object from which to copy</param> public PaneBase( PaneBase rhs ) { // copy over all the value types _isFontsScaled = rhs._isFontsScaled; _isPenWidthScaled = rhs._isPenWidthScaled; _titleGap = rhs._titleGap; _baseDimension = rhs._baseDimension; _margin = rhs._margin.Clone(); _rect = rhs._rect; // Copy the reference types by cloning _fill = rhs._fill.Clone(); _border = rhs._border.Clone(); _title = rhs._title.Clone(); _legend = rhs.Legend.Clone(); _title = rhs._title.Clone(); _graphObjList = rhs._graphObjList.Clone(); if ( rhs._tag is ICloneable ) _tag = ((ICloneable) rhs._tag).Clone(); else _tag = rhs._tag; }
/// <summary> /// Render the <see cref="Legend"/> to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphPane"/> object. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> public void Draw( Graphics g, PaneBase pane, float scaleFactor ) { // if the legend is not visible, do nothing if ( !_isVisible ) return; // Fill the background with the specified color if required _fill.Draw( g, _rect ); PaneList paneList = GetPaneList( pane ); float halfGap = _tmpSize / 2.0F; // Check for bad data values if ( _hStack <= 0 ) _hStack = 1; if ( _legendItemWidth <= 0 ) _legendItemWidth = 100; if ( _legendItemHeight <= 0 ) _legendItemHeight = _tmpSize; //float gap = pane.ScaledGap( scaleFactor ); int iEntry = 0; float x, y; // Get a brush for the legend label text using ( SolidBrush brushB = new SolidBrush( Color.Black ) ) { foreach ( GraphPane tmpPane in paneList ) { // Loop for each curve in the CurveList collection //foreach ( CurveItem curve in tmpPane.CurveList ) int count = tmpPane.CurveList.Count; for ( int i = 0; i < count; i++ ) { CurveItem curve = tmpPane.CurveList[_isReverse ? count - i - 1 : i]; if ( curve._label._text != "" && curve._label._isVisible ) { // Calculate the x,y (TopLeft) location of the current // curve legend label // assuming: // charHeight/2 for the left margin, plus legendWidth for each // horizontal column // legendHeight is the line spacing, with no extra margin above x = _rect.Left + halfGap / 2.0F + ( iEntry % _hStack ) * _legendItemWidth; y = _rect.Top + (int)( iEntry / _hStack ) * _legendItemHeight; // Draw the legend label for the current curve FontSpec tmpFont = ( curve._label._fontSpec != null ) ? curve._label._fontSpec : this.FontSpec; // This is required because, for long labels, the centering can affect the // position in GDI+. tmpFont.StringAlignment = StringAlignment.Near; if ( _isShowLegendSymbols ) { tmpFont.Draw( g, pane, curve._label._text, x + 2.5F * _tmpSize, y + _legendItemHeight / 2.0F, AlignH.Left, AlignV.Center, scaleFactor ); RectangleF rect = new RectangleF( x, y + _legendItemHeight / 4.0F, 2 * _tmpSize, _legendItemHeight / 2.0F ); curve.DrawLegendKey( g, tmpPane, rect, scaleFactor ); } else { if ( curve._label._fontSpec == null ) tmpFont.FontColor = curve.Color; tmpFont.Draw(g, pane, curve._label._text, x + 0.0F * _tmpSize, y + _legendItemHeight / 2.0F, AlignH.Left, AlignV.Center, scaleFactor); } // maintain a curve count for positioning iEntry++; } } if ( pane is MasterPane && ( (MasterPane)pane ).IsUniformLegendEntries ) break; } // Draw a border around the legend if required if ( iEntry > 0 ) this.Border.Draw( g, pane, scaleFactor, _rect ); } }
/// <summary> /// Render this object to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphObjList"/> collection object. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> public override void Draw( Graphics g, PaneBase pane, float scaleFactor ) { // Convert the arrow coordinates from the user coordinate system // to the screen coordinate system RectangleF pixRect = this.Location.TransformRect( pane ); if ( Math.Abs( pixRect.Left ) < 100000 && Math.Abs( pixRect.Top ) < 100000 && Math.Abs( pixRect.Right ) < 100000 && Math.Abs( pixRect.Bottom ) < 100000 ) { if ( _fill.IsVisible ) using ( Brush brush = _fill.MakeBrush( pixRect ) ) g.FillEllipse( brush, pixRect ); if ( _border.IsVisible ) using ( Pen pen = _border.GetPen( pane, scaleFactor ) ) g.DrawEllipse( pen, pixRect ); } }
private PaneList GetPaneList( PaneBase pane ) { // For a single GraphPane, create a PaneList to contain it // Otherwise, just use the paneList from the MasterPane PaneList paneList; if ( pane is GraphPane ) { paneList = new PaneList(); paneList.Add( (GraphPane)pane ); } else paneList = ( (MasterPane)pane ).PaneList; return paneList; }
/// <summary> /// Determine if the specified screen point lies inside the bounding box of this /// <see cref="BoxObj"/>. /// </summary> /// <param name="pt">The screen point, in pixels</param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <returns>true if the point lies in the bounding box, false otherwise</returns> public override bool PointInBox( PointF pt, PaneBase pane, Graphics g, float scaleFactor ) { if ( ! base.PointInBox(pt, pane, g, scaleFactor ) ) return false; // transform the x,y location from the user-defined // coordinate frame to the screen pixel location RectangleF pixRect = _location.TransformRect( pane ); using ( GraphicsPath path = new GraphicsPath() ) { path.AddEllipse( pixRect ); return path.IsVisible( pt ); } }
/* /// <summary> /// Create a new <see cref="Pen"/> object from the properties of this /// <see cref="Border"/> object. /// </summary> /// <param name="isPenWidthScaled"> /// Set to true to have the <see cref="Border"/> pen width scaled with the /// scaleFactor. /// </param> /// <param name="scaleFactor"> /// The scaling factor for the features of the graph based on the <see cref="PaneBase.BaseDimension"/>. This /// scaling factor is calculated by the <see cref="PaneBase.CalcScaleFactor"/> method. The scale factor /// represents a linear multiple to be applied to font sizes, symbol sizes, etc. /// </param> /// <returns>A <see cref="Pen"/> object with the proper color and pen width.</returns> public Pen MakePen( bool isPenWidthScaled, float scaleFactor ) { float scaledPenWidth = _width; if ( isPenWidthScaled ) scaledPenWidth = (float)(_width * scaleFactor); return new Pen( _color, scaledPenWidth ); } */ /// <summary> /// Draw the specified Border (<see cref="RectangleF"/>) using the properties of /// this <see cref="Border"/> object. /// </summary> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor for the features of the graph based on the <see cref="PaneBase.BaseDimension"/>. This /// scaling factor is calculated by the <see cref="PaneBase.CalcScaleFactor"/> method. The scale factor /// represents a linear multiple to be applied to font sizes, symbol sizes, etc. /// </param> /// <param name="rect">A <see cref="RectangleF"/> struct to be drawn.</param> public void Draw( IGraphics g, PaneBase pane, float scaleFactor, RectangleF rect ) { // Need to use the RectangleF props since rounding it can cause the axisFrame to // not line up properly with the last tic mark if ( _isVisible ) { RectangleF tRect = rect; float scaledInflate = (float) ( _inflateFactor * scaleFactor ); tRect.Inflate( scaledInflate, scaledInflate ); using ( Pen pen = GetPen( pane, scaleFactor) ) g.DrawRectangle( pen, tRect.X, tRect.Y, tRect.Width, tRect.Height ); } }
/// <summary> /// Render this object to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphObjList"/> collection object. /// </remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> override public void Draw(Graphics g, PaneBase pane, float scaleFactor) { // Convert the arrow coordinates from the user coordinate system // to the screen coordinate system PointF pix1 = this.Location.TransformTopLeft(pane); PointF pix2 = this.Location.TransformBottomRight(pane); if (pix1.X > -10000 && pix1.X < 100000 && pix1.Y > -100000 && pix1.Y < 100000 && pix2.X > -10000 && pix2.X < 100000 && pix2.Y > -100000 && pix2.Y < 100000) { // get a scaled size for the arrowhead float scaledSize = (float)(_size * scaleFactor); // calculate the length and the angle of the arrow "vector" double dy = pix2.Y - pix1.Y; double dx = pix2.X - pix1.X; float angle = (float)Math.Atan2(dy, dx) * 180.0F / (float)Math.PI; float length = (float)Math.Sqrt(dx * dx + dy * dy); // Save the old transform matrix Matrix transform = g.Transform; // Move the coordinate system so it is located at the starting point // of this arrow g.TranslateTransform(pix1.X, pix1.Y); // Rotate the coordinate system according to the angle of this arrow // about the starting point g.RotateTransform(angle); // get a pen according to this arrow properties using (Pen pen = _line.GetPen(pane, scaleFactor)) //new Pen( _color, pane.ScaledPenWidth( _penWidth, scaleFactor ) ) ) { //pen.DashStyle = _style; // Only show the arrowhead if required if (_isArrowHead) { if (_isLineSegment) { // Draw the line segment for this arrow g.DrawLine(pen, 0, 0, length - scaledSize + 1, 0); } // Create a polygon representing the arrowhead based on the scaled // size PointF[] polyPt = new PointF[4]; float hsize = scaledSize / 3.0F; polyPt[0].X = length; polyPt[0].Y = 0; polyPt[1].X = length - scaledSize; polyPt[1].Y = hsize; polyPt[2].X = length - scaledSize; polyPt[2].Y = -hsize; polyPt[3] = polyPt[0]; using (SolidBrush brush = new SolidBrush(_line._color)) // render the arrowhead g.FillPolygon(brush, polyPt); } else { g.DrawLine(pen, 0, 0, length, 0); } } // Restore the transform matrix back to its original state g.Transform = transform; } }