/// <summary> /// The Copy Constructor /// </summary> /// <param name="rhs">The <see cref="PaneList"/> object from which to copy</param> public PaneList(PaneList rhs) { foreach (GraphPane item in rhs) { this.Add(item.Clone()); } }
private float GetMaxHeight(PaneList paneList, Graphics g, float scaleFactor) { scaleFactor = Math.Min(scaleFactor, 1F * (g.DpiX / 72.0f)); // Set up some scaled dimensions for calculating sizes and locations float charHeight = this.FontSpec.GetHeight(scaleFactor); // Find the largest charHeight, just in case the curves have individual fonts defined foreach (GraphPane tmpPane in paneList) { foreach (CurveItem curve in tmpPane.CurveList) { if (curve._label._text != string.Empty && curve._label._isVisible && curve._label._fontSpec != null) { float tmpHeight = curve._label._fontSpec.GetHeight(scaleFactor); if (tmpHeight > charHeight) { charHeight = tmpHeight; } } } } return(charHeight); }
/// <summary> /// The Copy Constructor /// </summary> /// <param name="rhs">The <see cref="PaneList"/> object from which to copy</param> public PaneList( PaneList rhs ) { foreach ( GraphPane item in rhs ) { this.Add( item.Clone() ); } }
private float GetMaxHeight(PaneList paneList, Graphics g, float scaleFactor) { // Set up some scaled dimensions for calculating sizes and locations float defaultCharHeight = this.FontSpec.GetHeight(scaleFactor); float maxCharHeight = defaultCharHeight; // Find the largest charHeight, just in case the curves have individual fonts defined foreach (GraphPane tmpPane in paneList) { foreach (CurveItem curve in tmpPane.CurveList) { if (curve._label._text != string.Empty && curve._label._isVisible) { float tmpHeight = defaultCharHeight; if (curve._label._fontSpec != null) { tmpHeight = curve._label._fontSpec.GetHeight(scaleFactor); } // Account for multiline legend entries tmpHeight *= curve._label._text.Split('\n').Length; if (tmpHeight > maxCharHeight) { maxCharHeight = tmpHeight; } } } } return(maxCharHeight); }
/// <summary> /// The Copy Constructor /// </summary> /// <param name="rhs">The <see cref="MasterPane"/> object from which to copy</param> public MasterPane(MasterPane rhs) : base(rhs) { this.paneLayout = rhs.paneLayout; this.innerPaneGap = rhs.innerPaneGap; this.rows = rhs.rows; this.columns = rhs.rows; this.isColumnSpecified = rhs.isColumnSpecified; this.countList = rhs.countList; this.hasUniformLegendEntries = rhs.hasUniformLegendEntries; this.paneList = (PaneList)rhs.paneList.Clone(); }
/// <summary> /// Default constructor for the class. Specifies the <see cref="PaneBase.Title"/> of /// the <see cref="MasterPane"/>, and the size of the <see cref="PaneBase.PaneRect"/>. /// </summary> public MasterPane(string title, RectangleF paneRect) : base(title, paneRect) { this.paneLayout = Default.PaneLayout; this.innerPaneGap = Default.InnerPaneGap; this.rows = -1; this.columns = -1; this.isColumnSpecified = false; this.countList = null; this.hasUniformLegendEntries = Default.hasUniformLegendEntries; this.paneList = new PaneList(); this.legend.IsVisible = Default.IsShowLegend; }
/// <summary> /// Default constructor for the class. Specifies the <see cref="PaneBase.Title"/> of /// the <see cref="MasterPane"/>, and the size of the <see cref="PaneBase.Rect"/>. /// </summary> public MasterPane(string title, RectangleF paneRect) : base(title, paneRect) { _innerPaneGap = Default.InnerPaneGap; //_paneLayoutMgr = new PaneLayoutMgr(); _isUniformLegendEntries = Default.IsUniformLegendEntries; _isCommonScaleFactor = Default.IsCommonScaleFactor; _paneList = new PaneList(); _legend.IsVisible = Default.IsShowLegend; InitLayout(); }
/// <summary> /// Constructor for deserializing objects /// </summary> /// <param name="info">A <see cref="SerializationInfo"/> instance that defines the serialized data /// </param> /// <param name="context">A <see cref="StreamingContext"/> instance that contains the serialized data /// </param> protected MasterPane(SerializationInfo info, StreamingContext context) : base(info, context) { // The schema value is just a file version parameter. You can use it to make future versions // backwards compatible as new member variables are added to classes int sch = info.GetInt32("schema2"); this.paneList = (PaneList)info.GetValue("paneList", typeof(PaneList)); this.paneLayout = (PaneLayout)info.GetValue("paneLayout", typeof(PaneLayout)); this.innerPaneGap = info.GetSingle("innerPaneGap"); this.rows = info.GetInt32("rows"); this.columns = info.GetInt32("columns"); this.isColumnSpecified = info.GetBoolean("isColumnSpecified"); this.countList = (int[])info.GetValue("countList", typeof(int[])); this.hasUniformLegendEntries = info.GetBoolean("hasUniformLegendEntries"); }
/// <summary> /// The Copy Constructor - Make a deep-copy clone of this class instance. /// </summary> /// <param name="rhs">The <see cref="MasterPane"/> object from which to copy</param> public MasterPane(MasterPane rhs) : base(rhs) { // copy all the value types //_paneLayoutMgr = rhs._paneLayoutMgr.Clone(); _innerPaneGap = rhs._innerPaneGap; _isUniformLegendEntries = rhs._isUniformLegendEntries; _isCommonScaleFactor = rhs._isCommonScaleFactor; // Then, fill in all the reference types with deep copies _paneList = rhs._paneList.Clone(); _paneLayout = rhs._paneLayout; _countList = rhs._countList; _isColumnSpecified = rhs._isColumnSpecified; _prop = rhs._prop; }
/// <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) { scaleFactor = Math.Min(scaleFactor, 1F * (pane.m_Dpi / 72.0f)); 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> /// 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 (this.rect.Contains(mousePt)) { float charHeight = this.FontSpec.GetHeight(scaleFactor), halfCharHeight = charHeight / 2.0F; int j = (int)((mousePt.Y - this.rect.Top) / charHeight); int i = (int)((mousePt.X - this.rect.Left - halfCharHeight) / this.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.IsLegendLabelVisible && curve.Label != "") { if (pos == 0) { return(true); } pos--; } index++; } } return(true); } else { return(false); } }
/// <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)) { return(false); } 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 (var tmpPane in paneList.Where(p => p is GraphPane).Cast <GraphPane>()) { foreach (CurveItem curve in tmpPane.CurveList) { if (curve.Label.IsVisible && curve.Label.Text != string.Empty) { if (pos == 0) { return(true); } pos--; } index++; } } return(true); }
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> /// Constructor for deserializing objects /// </summary> /// <param name="info">A <see cref="SerializationInfo"/> instance that defines the serialized data /// </param> /// <param name="context">A <see cref="StreamingContext"/> instance that contains the serialized data /// </param> protected MasterPane(SerializationInfo info, StreamingContext context) : base(info, context) { // The schema value is just a file version parameter. You can use it to make future versions // backwards compatible as new member variables are added to classes int sch = info.GetInt32("schema2"); _paneList = (PaneList)info.GetValue("paneList", typeof(PaneList)); //_paneLayoutMgr = (PaneLayoutMgr) info.GetValue( "paneLayoutMgr", typeof(PaneLayoutMgr) ); _innerPaneGap = info.GetSingle("innerPaneGap"); _isUniformLegendEntries = info.GetBoolean("isUniformLegendEntries"); _isCommonScaleFactor = info.GetBoolean("isCommonScaleFactor"); _paneLayout = (PaneLayout)info.GetValue("paneLayout", typeof(PaneLayout)); _countList = (int[])info.GetValue("countList", typeof(int[])); _isColumnSpecified = info.GetBoolean("isColumnSpecified"); _prop = (float[])info.GetValue("prop", typeof(float[])); }
private float GetMaxHeight(PaneList paneList, Graphics g, float scaleFactor) { // Set up some scaled dimensions for calculating sizes and locations float charHeight = this.FontSpec.GetHeight(scaleFactor); // Find the largest charHeight, just in case the curves have individual fonts defined foreach (GraphPane tmpPane in paneList) { foreach (CurveItem curve in tmpPane.CurveList) { if (curve.Label != "" && curve.IsLegendLabelVisible && curve.FontSpec != null) { float tmpHeight = curve.FontSpec.GetHeight(scaleFactor); if (tmpHeight > charHeight) { charHeight = tmpHeight; } } } } return(charHeight); }
/// <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 (_numberOfColumns <= 0) { _numberOfColumns = 1; } if (_legendItemWidth <= 0) { _legendItemWidth = 100; } if (_legendItemHeight <= 0) { _legendItemHeight = _tmpSize; } //float gap = pane.ScaledGap( scaleFactor ); int iEntry = 0; // 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]; float x = _rect.Left + halfGap / 2.0F + (iEntry % _numberOfColumns) * (_legendItemWidth); float y = _rect.Top + (int)(iEntry / _numberOfColumns) * _legendItemHeight; float xEnd = DrawLabel(curve.Label, curve, g, pane, scaleFactor, tmpPane, _isShowLegendSymbols, x, y); x = xEnd; DrawLabel(curve.SecondaryLabel, curve, g, pane, scaleFactor, tmpPane, false, x, y); iEntry += 1; } 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 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 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 (!this.isVisible) { return; } // Fill the background with the specified color if required this.fill.Draw(g, this.rect); // Set up some scaled dimensions for calculating sizes and locations float charHeight = this.FontSpec.GetHeight(scaleFactor), halfCharHeight = charHeight / 2.0F; float charWidth = this.FontSpec.GetWidth(g, scaleFactor); // Check for bad data values if (this.hStack <= 0) { this.hStack = 1; } if (this.legendItemWidth <= 0) { this.legendItemWidth = 100; } if (this.legendItemHeight <= 0) { this.legendItemHeight = charHeight; } //float gap = pane.ScaledGap( scaleFactor ); int iEntry = 0; float x, y; // Get a brush for the legend label text SolidBrush brushB = new SolidBrush(Color.Black); PaneList paneList = GetPaneList(pane); foreach (GraphPane tmpPane in paneList) { // Loop for each curve in the CurveList collection foreach (CurveItem curve in tmpPane.CurveList) { if (curve.Label != "") { // 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 = this.rect.Left + halfCharHeight / 2.0F + (iEntry % hStack) * this.legendItemWidth; y = this.rect.Top + (int)(iEntry / hStack) * this.legendItemHeight; // Draw the legend label for the current curve this.FontSpec.Draw(g, pane.IsPenWidthScaled, curve.Label, x + 2.5F * charHeight, y + this.legendItemHeight / 2.0F, AlignH.Left, AlignV.Center, scaleFactor); RectangleF rect = new RectangleF(x, y + this.legendItemHeight / 4.0F, 2 * charHeight, this.legendItemHeight / 2.0F); curve.DrawLegendKey(g, tmpPane, rect, scaleFactor); // maintain a curve count for positioning iEntry++; } } if (pane is MasterPane && ((MasterPane)pane).HasUniformLegendEntries) { break; } } // Draw a border around the legend if required if (iEntry > 0) { this.Border.Draw(g, pane.IsPenWidthScaled, scaleFactor, this.rect); } }
/// <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; _numberOfColumns = 1; _legendItemWidth = 1; _legendItemHeight = 0; RectangleF clientRect = pane.CalcClientRect(g, scaleFactor); // If the legend is invisible, don't do anything if (!_isVisible) { return; } int numberOfCurvesToDraw = 0; PaneList paneList = GetPaneList(pane); _tmpSize = GetMaxHeight(paneList, g, scaleFactor); float halfGap = _tmpSize / 2.0F, maxWidth = 0, tmpWidth = 0, gapPix = _gap * _tmpSize; bool showingSecondaryLabel = false; 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]; bool atLeastOneLabelDrawn = false; 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; } atLeastOneLabelDrawn = true; } if (curve.SecondaryLabel._text != string.Empty && curve.SecondaryLabel._isVisible) { // Calculate the width of the label save the max width FontSpec tmpFont = (curve.SecondaryLabel._fontSpec != null) ? curve.SecondaryLabel._fontSpec : this.FontSpec; tmpWidth = tmpFont.GetWidth(g, curve.SecondaryLabel._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; } atLeastOneLabelDrawn = true; showingSecondaryLabel = true; } if (atLeastOneLabelDrawn) { ++numberOfCurvesToDraw; } } 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) { if (showingSecondaryLabel) { _legendItemWidth = 3.0f * _tmpSize + maxWidth * 1.6f; } else { _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) { _numberOfColumns = (int)((widthAvail - halfGap) / _legendItemWidth); } // You can never have more columns than legend entries if (_numberOfColumns > numberOfCurvesToDraw) { _numberOfColumns = numberOfCurvesToDraw; } // a saftey check if (_numberOfColumns == 0) { _numberOfColumns = 1; } } else { if (_isShowLegendSymbols) { _legendItemWidth = 4.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 = _numberOfColumns * _legendItemWidth; // The total legend height _legendItemHeight = _legendItemHeight * (float)scaleFactor + halfGap; if (_tmpSize > _legendItemHeight) { _legendItemHeight = _tmpSize; } float totLegHeight = (float)Math.Ceiling((double)numberOfCurvesToDraw / (double)_numberOfColumns) * _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 (numberOfCurvesToDraw > 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; }
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> /// The Copy Constructor - Make a deep-copy clone of this class instance. /// </summary> /// <param name="rhs">The <see cref="MasterPane"/> object from which to copy</param> public MasterPane( MasterPane rhs ) : base(rhs) { // copy all the value types //_paneLayoutMgr = rhs._paneLayoutMgr.Clone(); _innerPaneGap = rhs._innerPaneGap; _isUniformLegendEntries = rhs._isUniformLegendEntries; _isCommonScaleFactor = rhs._isCommonScaleFactor; // Then, fill in all the reference types with deep copies _paneList = rhs._paneList.Clone(); _paneLayout = rhs._paneLayout; _countList = rhs._countList; _isColumnSpecified = rhs._isColumnSpecified; _prop = rhs._prop; }
private float GetMaxHeight( PaneList paneList, Graphics g, float scaleFactor ) { // Set up some scaled dimensions for calculating sizes and locations float defaultCharHeight = this.FontSpec.GetHeight( scaleFactor ); float maxCharHeight = defaultCharHeight; // Find the largest charHeight, just in case the curves have individual fonts defined foreach ( GraphPane tmpPane in paneList ) { foreach ( CurveItem curve in tmpPane.CurveList ) { if ( curve._label._text != string.Empty && curve._label._isVisible ) { float tmpHeight = defaultCharHeight; if ( curve._label._fontSpec != null ) tmpHeight = curve._label._fontSpec.GetHeight( scaleFactor ); // Account for multiline legend entries tmpHeight *= curve._label._text.Split( '\n' ).Length; if ( tmpHeight > maxCharHeight ) maxCharHeight = tmpHeight; } } } return maxCharHeight; }
/// <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="GraphPane.AxisRect"/> 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="tAxisRect"> /// The rectangle that contains the area bounded by the axes, in pixel units. /// <seealso cref="GraphPane.AxisRect">AxisRect</seealso> /// </param> public void CalcRect(Graphics g, PaneBase pane, float scaleFactor, ref RectangleF tAxisRect) { // Start with an empty rectangle this.rect = Rectangle.Empty; this.hStack = 1; this.legendItemWidth = 1; this.legendItemHeight = 0; // If the legend is invisible, don't do anything if (!this.isVisible) { return; } int nCurve = 0; float charHeight = this.FontSpec.GetHeight(scaleFactor), halfCharHeight = charHeight / 2.0F, charWidth = this.FontSpec.GetWidth(g, scaleFactor), maxWidth = 0, tmpWidth; PaneList paneList = GetPaneList(pane); 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) { if (curve.Label != "" && curve.IsLegendLabelVisible) { // Calculate the width of the label save the max width tmpWidth = this.FontSpec.GetWidth(g, curve.Label, scaleFactor); if (tmpWidth > maxWidth) { maxWidth = tmpWidth; } // Save the maximum symbol height for line-type curves if (curve is LineItem && ((LineItem)curve).Symbol.Size > this.legendItemHeight) { this.legendItemHeight = ((LineItem)curve).Symbol.Size; } nCurve++; } } if (pane is MasterPane && ((MasterPane)pane).HasUniformLegendEntries) { break; } } float widthAvail; // Is this legend horizontally stacked? if (this.isHStack) { // Determine the available space for horizontal stacking switch (this.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 = tAxisRect.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 = tAxisRect.Width / 2; break; // shouldn't ever happen default: widthAvail = 0; break; } // width of one legend entry this.legendItemWidth = 3 * charHeight + 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) { this.hStack = (int)((widthAvail - halfCharHeight) / this.legendItemWidth); } // You can never have more columns than legend entries if (this.hStack > nCurve) { this.hStack = nCurve; } // a saftey check if (this.hStack == 0) { this.hStack = 1; } } else { this.legendItemWidth = 3.5F * charHeight + 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 = this.hStack * this.legendItemWidth; // The total legend height this.legendItemHeight = this.legendItemHeight * (float)scaleFactor + halfCharHeight; if (charHeight > this.legendItemHeight) { this.legendItemHeight = charHeight; } float totLegHeight = (float)Math.Ceiling((double)nCurve / (double)hStack) * this.legendItemHeight; RectangleF newRect = new RectangleF(); // Now calculate the legend rect based on the above determined parameters // Also, adjust the axisRect 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 axisRect // as required. The right and bottom edges are calculated at the bottom of the switch. switch (this.position) { case LegendPos.Right: newRect.X = pane.PaneRect.Right - totLegWidth - pane.MarginRight * (float)scaleFactor; newRect.Y = tAxisRect.Top; tAxisRect.Width -= totLegWidth + halfCharHeight; break; case LegendPos.Top: newRect.X = tAxisRect.Left; newRect.Y = tAxisRect.Top; tAxisRect.Y += totLegHeight + halfCharHeight; tAxisRect.Height -= totLegHeight + halfCharHeight; break; case LegendPos.TopCenter: newRect.X = tAxisRect.Left + (tAxisRect.Width - totLegWidth) / 2; newRect.Y = tAxisRect.Top; tAxisRect.Y += totLegHeight + halfCharHeight; tAxisRect.Height -= totLegHeight + halfCharHeight; break; case LegendPos.Bottom: newRect.X = tAxisRect.Left + (tAxisRect.Width - totLegWidth) / 2; newRect.Y = pane.PaneRect.Bottom - totLegHeight - pane.MarginBottom * (float)scaleFactor; tAxisRect.Height -= totLegHeight + halfCharHeight; break; case LegendPos.BottomCenter: newRect.X = tAxisRect.Left + (tAxisRect.Width - totLegWidth) / 2; newRect.Y = tAxisRect.Bottom; tAxisRect.Height -= totLegHeight + halfCharHeight; break; case LegendPos.Left: newRect.X = pane.PaneRect.Left + pane.MarginLeft * (float)scaleFactor; newRect.Y = tAxisRect.Top; tAxisRect.X += totLegWidth + halfCharHeight; tAxisRect.Width -= totLegWidth + halfCharHeight; break; case LegendPos.InsideTopRight: newRect.X = tAxisRect.Right - totLegWidth; newRect.Y = tAxisRect.Top; break; case LegendPos.InsideTopLeft: newRect.X = tAxisRect.Left; newRect.Y = tAxisRect.Top; break; case LegendPos.InsideBotRight: newRect.X = tAxisRect.Right - totLegWidth; newRect.Y = tAxisRect.Bottom - totLegHeight; break; case LegendPos.InsideBotLeft: newRect.X = tAxisRect.Left; newRect.Y = tAxisRect.Bottom - totLegHeight; break; case LegendPos.Float: newRect.Location = this.Location.TransformTopLeft(pane, totLegWidth, totLegHeight); break; } } this.rect = newRect; }
/// <summary> /// Default constructor for the class. Specifies the <see cref="PaneBase.Title"/> of /// the <see cref="MasterPane"/>, and the size of the <see cref="PaneBase.Rect"/>. /// </summary> public MasterPane( string title, RectangleF paneRect ) : base(title, paneRect) { _innerPaneGap = Default.InnerPaneGap; //_paneLayoutMgr = new PaneLayoutMgr(); _isUniformLegendEntries = Default.IsUniformLegendEntries ; _isCommonScaleFactor = Default.IsCommonScaleFactor; _paneList = new PaneList(); _legend.IsVisible = Default.IsShowLegend; InitLayout(); }
private float GetMaxHeight(PaneList paneList, Graphics g, float scaleFactor) { // Set up some scaled dimensions for calculating sizes and locations float charHeight = FontSpec.GetHeight(scaleFactor); // Find the largest charHeight, just in case the curves have individual fonts defined foreach (GraphPane tmpPane in paneList) { foreach (CurveItem curve in tmpPane.CurveList) { if (curve._label._text != string.Empty && curve._label._isVisible && curve._label._fontSpec != null) { float tmpHeight = curve._label._fontSpec.GetHeight(scaleFactor); if (tmpHeight > charHeight) charHeight = tmpHeight; } } } return charHeight; }
/// <summary> /// Constructor for deserializing objects /// </summary> /// <param name="info">A <see cref="SerializationInfo"/> instance that defines the serialized data /// </param> /// <param name="context">A <see cref="StreamingContext"/> instance that contains the serialized data /// </param> protected MasterPane( SerializationInfo info, StreamingContext context ) : base(info, context) { // The schema value is just a file version parameter. You can use it to make future versions // backwards compatible as new member variables are added to classes int sch = info.GetInt32( "schema2" ); _paneList = (PaneList) info.GetValue( "paneList", typeof(PaneList) ); //_paneLayoutMgr = (PaneLayoutMgr) info.GetValue( "paneLayoutMgr", typeof(PaneLayoutMgr) ); _innerPaneGap = info.GetSingle( "innerPaneGap" ); _isUniformLegendEntries = info.GetBoolean( "isUniformLegendEntries" ); _isCommonScaleFactor = info.GetBoolean( "isCommonScaleFactor" ); _paneLayout = (PaneLayout)info.GetValue( "paneLayout", typeof( PaneLayout ) ); _countList = (int[])info.GetValue( "countList", typeof( int[] ) ); _isColumnSpecified = info.GetBoolean( "isColumnSpecified" ); _prop = (float[])info.GetValue( "prop", typeof( float[] ) ); }
/// <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) { scaleFactor = Math.Min(scaleFactor, 1F * (g.DpiX / 72.0f)); // if the legend is not visible, do nothing if (!_isVisible) { return; } Region oldClip = g.Clip; RectangleF clipRect = new RectangleF(_rect.X, _rect.Y, _rect.Width, _rect.Height); clipRect.Inflate(1, 1); g.SetClip(clipRect); // 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 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) { 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; tmpFont.Draw(g, pane.IsPenWidthScaled, 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); // maintain a curve count for positioning iEntry++; } } if (pane is MasterPane && ((MasterPane)pane).IsUniformLegendEntries) { break; } } clipRect.Inflate(2, 2); g.SetClip(clipRect); clipRect.Inflate(-1, -1); // Draw a border around the legend if required if (iEntry > 0) { this.Border.Draw(g, pane.IsPenWidthScaled, scaleFactor, clipRect); } g.SetClip(oldClip, System.Drawing.Drawing2D.CombineMode.Replace); }