public static ScaleFont ( |
||
initial | The font to scale. | |
scale | double | Scale by this factor. |
return |
/// <summary> /// Draw The legend /// </summary> /// <param name="g">The graphics surface on which to draw</param> /// <param name="position">The position of the top left of the axis.</param> /// <param name="plots">Array of plot objects to appear in the legend.</param> /// <param name="scale">if the legend is set to scale, the amount to scale by.</param> /// <returns>bounding box</returns> public Rectangle Draw(Graphics g, Point position, ArrayList plots, float scale) { // first of all determine the Font to use in the legend. Font textFont; if (this.AutoScaleText) { textFont = Utils.ScaleFont(this.font_, scale); } else { textFont = this.font_; } // determine max width and max height of label strings and // count the labels. int labelCount = 0; int maxHt = 0; int maxWd = 0; int unnamedCount = 0; for (int i = 0; i < plots.Count; ++i) { if (!(plots[i] is IPlot)) { continue; } IPlot p = (IPlot)plots[i]; if (!p.ShowInLegend) { continue; } string label = p.Label; if (label == "") { unnamedCount += 1; label = "Series " + unnamedCount.ToString(); } SizeF labelSize = g.MeasureString(label, textFont); if (labelSize.Height > maxHt) { maxHt = (int)labelSize.Height; } if (labelSize.Width > maxWd) { maxWd = (int)labelSize.Width; } ++labelCount; } bool extendingHorizontally = numberItemsHorizontally_ == -1; bool extendingVertically = numberItemsVertically_ == -1; // determine width in legend items count units. int widthInItemCount = 0; if (extendingVertically) { if (labelCount >= numberItemsHorizontally_) { widthInItemCount = numberItemsHorizontally_; } else { widthInItemCount = labelCount; } } else if (extendingHorizontally) { widthInItemCount = labelCount / numberItemsVertically_; if (labelCount % numberItemsVertically_ != 0) { widthInItemCount += 1; } } else { throw new NPlotException("logic error in legend base"); } // determine height of legend in items count units. int heightInItemCount = 0; if (extendingHorizontally) { if (labelCount >= numberItemsVertically_) { heightInItemCount = numberItemsVertically_; } else { heightInItemCount = labelCount; } } else // extendingVertically { heightInItemCount = labelCount / numberItemsHorizontally_; if (labelCount % numberItemsHorizontally_ != 0) { heightInItemCount += 1; } } int lineLength = 20; int hSpacing = (int)(5.0f * scale); int vSpacing = (int)(3.0f * scale); int boxWidth = (int)((float)widthInItemCount * (lineLength + maxWd + hSpacing * 2.0f) + hSpacing); int boxHeight = (int)((float)heightInItemCount * (maxHt + vSpacing) + vSpacing); int totalWidth = boxWidth; int totalHeight = boxHeight; // draw box around the legend. if (this.BorderStyle == BorderType.Line) { g.FillRectangle(new SolidBrush(this.bgColor_), position.X, position.Y, boxWidth, boxHeight); g.DrawRectangle(new Pen(this.borderColor_), position.X, position.Y, boxWidth, boxHeight); } else if (this.BorderStyle == BorderType.Shadow) { int offset = (int)(4.0f * scale); g.FillRectangle(new SolidBrush(Color.FromArgb(128, Color.Gray)), position.X + offset, position.Y + offset, boxWidth, boxHeight); g.FillRectangle(new SolidBrush(this.bgColor_), position.X, position.Y, boxWidth, boxHeight); g.DrawRectangle(new Pen(this.borderColor_), position.X, position.Y, boxWidth, boxHeight); totalWidth += offset; totalHeight += offset; } /* * else if ( this.BorderStyle == BorderType.Curved ) * { * // TODO. make this nice. * } */ else { // do nothing. } // now draw entries in box.. labelCount = 0; unnamedCount = 0; int plotCount = -1; for (int i = 0; i < plots.Count; ++i) { if (!(plots[i] is IPlot)) { continue; } IPlot p = (IPlot)plots[i]; if (!p.ShowInLegend) { continue; } plotCount += 1; int xpos, ypos; if (extendingVertically) { xpos = plotCount % numberItemsHorizontally_; ypos = plotCount / numberItemsHorizontally_; } else { xpos = plotCount / numberItemsVertically_; ypos = plotCount % numberItemsVertically_; } int lineXPos = (int)(position.X + hSpacing + xpos * (lineLength + maxWd + hSpacing * 2.0f)); int lineYPos = (int)(position.Y + vSpacing + ypos * (vSpacing + maxHt)); p.DrawInLegend(g, new Rectangle(lineXPos, lineYPos, lineLength, maxHt)); int textXPos = lineXPos + hSpacing + lineLength; int textYPos = lineYPos; string label = p.Label; if (label == "") { unnamedCount += 1; label = "Series " + unnamedCount.ToString(); } g.DrawString(label, textFont, new SolidBrush(this.textColor_), textXPos, textYPos); ++labelCount; } return(new Rectangle(position.X, position.Y, totalWidth, totalHeight)); }
private void DeterminePhysicalAxesToDraw(Rectangle bounds, Axis xAxis1, Axis xAxis2, Axis yAxis1, Axis yAxis2, out PhysicalAxis pXAxis1, out PhysicalAxis pXAxis2, out PhysicalAxis pYAxis1, out PhysicalAxis pYAxis2) { System.Drawing.Rectangle cb = bounds; pXAxis1 = new PhysicalAxis(xAxis1, new Point(cb.Left, cb.Bottom), new Point(cb.Right, cb.Bottom)); pYAxis1 = new PhysicalAxis(yAxis1, new Point(cb.Left, cb.Bottom), new Point(cb.Left, cb.Top)); pXAxis2 = new PhysicalAxis(xAxis2, new Point(cb.Left, cb.Top), new Point(cb.Right, cb.Top)); pYAxis2 = new PhysicalAxis(yAxis2, new Point(cb.Right, cb.Bottom), new Point(cb.Right, cb.Top)); int bottomIndent = padding_; if (!pXAxis1.Axis.Hidden) { // evaluate its bounding box Rectangle bb = pXAxis1.GetBoundingBox(); // finally determine its indentation from the bottom bottomIndent = bottomIndent + bb.Bottom - cb.Bottom; } int leftIndent = padding_; if (!pYAxis1.Axis.Hidden) { // evaluate its bounding box Rectangle bb = pYAxis1.GetBoundingBox(); // finally determine its indentation from the left leftIndent = leftIndent - bb.Left + cb.Left; } int topIndent = padding_; float scale = DetermineScaleFactor(bounds.Width, bounds.Height); int titleHeight; if (AutoScaleTitle) { titleHeight = Utils.ScaleFont(titleFont_, scale).Height; } else { titleHeight = titleFont_.Height; } //count number of new lines in title. int nlCount = 0; for (int i = 0; i < title_.Length; ++i) { if (title_[i] == '\n') { nlCount += 1; } } titleHeight = (int)(((float)nlCount * 0.75 + 1.0f) * (float)titleHeight); if (!pXAxis2.Axis.Hidden) { // evaluate its bounding box Rectangle bb = pXAxis2.GetBoundingBox(); topIndent = topIndent - bb.Top + cb.Top; // finally determine its indentation from the top // correct top indendation to take into account plot title if (title_ != "") { topIndent += (int)(titleHeight * 1.3f); } } int rightIndent = padding_; if (!pYAxis2.Axis.Hidden) { // evaluate its bounding box Rectangle bb = pYAxis2.GetBoundingBox(); // finally determine its indentation from the right rightIndent = (int)(rightIndent + bb.Right - cb.Right); } // now we have all the default calculated positions and we can proceed to // "move" the axes to their right places // primary axes (bottom, left) pXAxis1.PhysicalMin = new Point(cb.Left + leftIndent, cb.Bottom - bottomIndent); pXAxis1.PhysicalMax = new Point(cb.Right - rightIndent, cb.Bottom - bottomIndent); pYAxis1.PhysicalMin = new Point(cb.Left + leftIndent, cb.Bottom - bottomIndent); pYAxis1.PhysicalMax = new Point(cb.Left + leftIndent, cb.Top + topIndent); // secondary axes (top, right) pXAxis2.PhysicalMin = new Point(cb.Left + leftIndent, cb.Top + topIndent); pXAxis2.PhysicalMax = new Point(cb.Right - rightIndent, cb.Top + topIndent); pYAxis2.PhysicalMin = new Point(cb.Right - rightIndent, cb.Bottom - bottomIndent); pYAxis2.PhysicalMax = new Point(cb.Right - rightIndent, cb.Top + topIndent); }
/// <summary> /// Draw the the PlotSurface2D and all contents [axes, drawables, and legend] on the /// supplied graphics surface. /// </summary> /// <param name="g">The graphics surface on which to draw.</param> /// <param name="bounds">A bounding box on this surface that denotes the area on the /// surface to confine drawing to.</param> public void Draw(Graphics g, Rectangle bounds) { // determine font sizes and tick scale factor. float scale = DetermineScaleFactor(bounds.Width, bounds.Height); // if there is nothing to plot, return. if (drawables_.Count == 0) { // draw title float x_center = (bounds.Left + bounds.Right) / 2.0f; float y_center = (bounds.Top + bounds.Bottom) / 2.0f; Font scaled_font; if (AutoScaleTitle) { scaled_font = Utils.ScaleFont(titleFont_, scale); } else { scaled_font = titleFont_; } g.DrawString(title_, scaled_font, titleBrush_, new PointF(x_center, y_center), titleDrawFormat_); return; } // determine the [non physical] axes to draw based on the axis properties set. Axis xAxis1 = null; Axis xAxis2 = null; Axis yAxis1 = null; Axis yAxis2 = null; DetermineAxesToDraw(out xAxis1, out xAxis2, out yAxis1, out yAxis2); // apply scale factor to axes as desired. if (xAxis1.AutoScaleTicks) { xAxis1.TickScale = scale; } if (xAxis1.AutoScaleText) { xAxis1.FontScale = scale; } if (yAxis1.AutoScaleTicks) { yAxis1.TickScale = scale; } if (yAxis1.AutoScaleText) { yAxis1.FontScale = scale; } if (xAxis2.AutoScaleTicks) { xAxis2.TickScale = scale; } if (xAxis2.AutoScaleText) { xAxis2.FontScale = scale; } if (yAxis2.AutoScaleTicks) { yAxis2.TickScale = scale; } if (yAxis2.AutoScaleText) { yAxis2.FontScale = scale; } // determine the default physical positioning of those axes. PhysicalAxis pXAxis1 = null; PhysicalAxis pYAxis1 = null; PhysicalAxis pXAxis2 = null; PhysicalAxis pYAxis2 = null; DeterminePhysicalAxesToDraw( bounds, xAxis1, xAxis2, yAxis1, yAxis2, out pXAxis1, out pXAxis2, out pYAxis1, out pYAxis2); float oldXAxis2Height = pXAxis2.PhysicalMin.Y; // Apply axes constraints for (int i = 0; i < axesConstraints_.Count; ++i) { ((AxesConstraint)axesConstraints_[i]).ApplyConstraint( pXAxis1, pYAxis1, pXAxis2, pYAxis2); } ///////////////////////////////////////////////////////////////////////// // draw legend if have one. // Note: this will update axes if necessary. Point legendPosition = new Point(0, 0); if (legend_ != null) { legend_.UpdateAxesPositions( pXAxis1, pYAxis1, pXAxis2, pYAxis2, drawables_, scale, padding_, bounds, out legendPosition); } float newXAxis2Height = pXAxis2.PhysicalMin.Y; float titleExtraOffset = oldXAxis2Height - newXAxis2Height; // now we are ready to define the bounding box for the plot area (to use in clipping // operations. plotAreaBoundingBoxCache_ = new Rectangle( Math.Min(pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMax.X), Math.Min(pYAxis1.PhysicalMax.Y, pYAxis1.PhysicalMin.Y), Math.Abs(pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X + 1), Math.Abs(pYAxis1.PhysicalMin.Y - pYAxis1.PhysicalMax.Y + 1) ); bbXAxis1Cache_ = pXAxis1.GetBoundingBox(); bbXAxis2Cache_ = pXAxis2.GetBoundingBox(); bbYAxis1Cache_ = pYAxis1.GetBoundingBox(); bbYAxis2Cache_ = pYAxis2.GetBoundingBox(); // Fill in the background. if (plotBackColor_ != null) { g.FillRectangle( new System.Drawing.SolidBrush((Color)plotBackColor_), (Rectangle)plotAreaBoundingBoxCache_); } else if (plotBackBrush_ != null) { g.FillRectangle( plotBackBrush_.Get((Rectangle)plotAreaBoundingBoxCache_), (Rectangle)plotAreaBoundingBoxCache_); } else if (plotBackImage_ != null) { g.DrawImage( Utils.TiledImage(plotBackImage_, new Size( ((Rectangle)plotAreaBoundingBoxCache_).Width, ((Rectangle)plotAreaBoundingBoxCache_).Height)), (Rectangle)plotAreaBoundingBoxCache_); } // draw title float xt = (pXAxis2.PhysicalMax.X + pXAxis2.PhysicalMin.X) / 2.0f; float yt = bounds.Top + padding_ - titleExtraOffset; Font scaledFont; if (AutoScaleTitle) { scaledFont = Utils.ScaleFont(titleFont_, scale); } else { scaledFont = titleFont_; } g.DrawString(title_, scaledFont, titleBrush_, new PointF(xt, yt), titleDrawFormat_); //count number of new lines in title. int nlCount = 0; for (int i = 0; i < title_.Length; ++i) { if (title_[i] == '\n') { nlCount += 1; } } SizeF s = g.MeasureString(title_, scaledFont); bbTitleCache_ = new Rectangle((int)(xt - s.Width / 2), (int)(yt), (int)(s.Width), (int)(s.Height) * (nlCount + 1)); // draw drawables.. System.Drawing.Drawing2D.SmoothingMode smoothSave = g.SmoothingMode; g.SmoothingMode = smoothingMode_; bool legendDrawn = false; for (int i_o = 0; i_o < ordering_.Count; ++i_o) { int i = (int)ordering_.GetByIndex(i_o); double zOrder = (double)ordering_.GetKey(i_o); if (zOrder > legendZOrder_) { // draw legend. if (!legendDrawn && legend_ != null) { legend_.Draw(g, legendPosition, drawables_, scale); legendDrawn = true; } } IDrawable drawable = (IDrawable)drawables_[i]; XAxisPosition xap = (XAxisPosition)xAxisPositions_[i]; YAxisPosition yap = (YAxisPosition)yAxisPositions_[i]; PhysicalAxis drawXAxis; PhysicalAxis drawYAxis; if (xap == XAxisPosition.Bottom) { drawXAxis = pXAxis1; } else { drawXAxis = pXAxis2; } if (yap == YAxisPosition.Left) { drawYAxis = pYAxis1; } else { drawYAxis = pYAxis2; } // set the clipping region.. (necessary for zoom) g.Clip = new Region((Rectangle)plotAreaBoundingBoxCache_); // plot. drawable.Draw(g, drawXAxis, drawYAxis); // reset it.. g.ResetClip(); } if (!legendDrawn && legend_ != null) { legend_.Draw(g, legendPosition, drawables_, scale); } // cache the physical axes we used on this draw; pXAxis1Cache_ = pXAxis1; pYAxis1Cache_ = pYAxis1; pXAxis2Cache_ = pXAxis2; pYAxis2Cache_ = pYAxis2; g.SmoothingMode = smoothSave; // now draw axes. Rectangle axisBounds; pXAxis1.Draw(g, out axisBounds); pXAxis2.Draw(g, out axisBounds); pYAxis1.Draw(g, out axisBounds); pYAxis2.Draw(g, out axisBounds); #if DEBUG_BOUNDING_BOXES g.DrawRectangle(new Pen(Color.Orange), (Rectangle)bbXAxis1Cache_); g.DrawRectangle(new Pen(Color.Orange), (Rectangle)bbXAxis2Cache_); g.DrawRectangle(new Pen(Color.Orange), (Rectangle)bbYAxis1Cache_); g.DrawRectangle(new Pen(Color.Orange), (Rectangle)bbYAxis2Cache_); g.DrawRectangle(new Pen(Color.Red, 5.0F), (Rectangle)plotAreaBoundingBoxCache_); //if(this.ShowLegend)g.DrawRectangle( new Pen(Color.Chocolate, 3.0F), (Rectangle) bbLegendCache_); g.DrawRectangle(new Pen(Color.DeepPink, 2.0F), (Rectangle)bbTitleCache_); #endif }
/// <summary> /// Draw the the PlotSurface2D and all contents [axes, drawables] on the /// supplied graphics surface. /// </summary> /// <param name="g">The graphics surface on which to draw.</param> /// <param name="bounds">A bounding box on this surface that denotes the area on the /// surface to confine drawing to.</param> public void Draw(Graphics g, Rectangle bounds) { // determine font sizes and tick scale factor. float scale = DetermineScaleFactor(bounds.Width, bounds.Height); // if there is nothing to plot, return. if (m_drawables.Count == 0) { // draw title float x_center = (bounds.Left + bounds.Right) / 2.0f; float y_center = (bounds.Top + bounds.Bottom) / 2.0f; Font scaled_font; if (AutoScaleTitle) { scaled_font = Utils.ScaleFont(m_titleFont, scale); } else { scaled_font = m_titleFont; } g.DrawString(m_title, scaled_font, this.m_titleBrush, new PointF(x_center, y_center), m_titleDrawFormat); return; } Stopwatch sw = StepTimer.Start("Determine Axis"); // determine the [non physical] axes to draw based on the axis properties set. Axis xAxis1, xAxis2, yAxis1, yAxis2; DetermineAxesToDraw(out xAxis1, out xAxis2, out yAxis1, out yAxis2); // apply scale factor to axes as desired. if (xAxis1.AutoScaleTicks) { xAxis1.TickScale = scale; } if (xAxis1.AutoScaleText) { xAxis1.FontScale = scale; } if (yAxis1.AutoScaleTicks) { yAxis1.TickScale = scale; } if (yAxis1.AutoScaleText) { yAxis1.FontScale = scale; } if (xAxis2.AutoScaleTicks) { xAxis2.TickScale = scale; } if (xAxis2.AutoScaleText) { xAxis2.FontScale = scale; } if (yAxis2.AutoScaleTicks) { yAxis2.TickScale = scale; } if (yAxis2.AutoScaleText) { yAxis2.FontScale = scale; } // determine the default physical positioning of those axes. PhysicalAxis pXAxis1, pYAxis1, pXAxis2, pYAxis2; DeterminePhysicalAxesToDraw(bounds, xAxis1, xAxis2, yAxis1, yAxis2, out pXAxis1, out pXAxis2, out pYAxis1, out pYAxis2); StepTimer.Stop(sw); float oldXAxis2Height = pXAxis2.PhysicalMin.Y; // Apply axes constraints for (int i = 0; i < m_axesConstraints.Count; ++i) { (m_axesConstraints[i]).ApplyConstraint(pXAxis1, pYAxis1, pXAxis2, pYAxis2); } float newXAxis2Height = pXAxis2.PhysicalMin.Y; float titleExtraOffset = oldXAxis2Height - newXAxis2Height; sw = StepTimer.Start("Draw Axis"); // now we are ready to define the bounding box for the plot area (to use in clipping // operations. m_plotAreaBoundingBoxCache = new Rectangle( Math.Min(pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMax.X), Math.Min(pYAxis1.PhysicalMax.Y, pYAxis1.PhysicalMin.Y), Math.Abs(pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X + 1), Math.Abs(pYAxis1.PhysicalMin.Y - pYAxis1.PhysicalMax.Y + 1) ); m_bbXAxis1Cache = pXAxis1.GetBoundingBox(); m_bbXAxis2Cache = pXAxis2.GetBoundingBox(); m_bbYAxis1Cache = pYAxis1.GetBoundingBox(); m_bbYAxis2Cache = pYAxis2.GetBoundingBox(); // Fill in the background. g.FillRectangle(new SolidBrush(m_plotBackColor), m_plotAreaBoundingBoxCache); // draw title float xt = (pXAxis2.PhysicalMax.X + pXAxis2.PhysicalMin.X) / 2.0f; float yt = bounds.Top + m_padding - titleExtraOffset; Font scaledFont; if (AutoScaleTitle) { scaledFont = Utils.ScaleFont(m_titleFont, scale); } else { scaledFont = m_titleFont; } g.DrawString(m_title, scaledFont, m_titleBrush, new PointF(xt, yt), m_titleDrawFormat); //count number of new lines in title. int nlCount = 0; for (int i = 0; i < m_title.Length; ++i) { if (m_title[i] == '\n') { nlCount += 1; } } SizeF s = g.MeasureString(m_title, scaledFont); m_bbTitleCache = new Rectangle((int)(xt - s.Width / 2), (int)(yt), (int)(s.Width), (int)(s.Height) * (nlCount + 1)); StepTimer.Stop(sw); //sw = StepTimer.Start("Draw IDrawables"); // draw drawables.. SmoothingMode smoothSave = g.SmoothingMode; g.SmoothingMode = m_smoothingMode; for (int i_o = 0; i_o < m_ordering.Count; ++i_o) { int i = m_ordering.Values[i_o]; IDrawable drawable = m_drawables[i]; PhysicalAxis drawXAxis; PhysicalAxis drawYAxis; drawXAxis = pXAxis1; drawYAxis = pYAxis1; // set the clipping region.. (necessary for zoom) g.Clip = new Region(m_plotAreaBoundingBoxCache); // plot. drawable.Draw(g, drawXAxis, drawYAxis); // reset it.. g.ResetClip(); } //StepTimer.Stop(sw); // cache the physical axes we used on this draw; m_pXAxis1Cache = pXAxis1; m_pYAxis1Cache = pYAxis1; m_pXAxis2Cache = pXAxis2; m_pYAxis2Cache = pYAxis2; g.SmoothingMode = smoothSave; sw = StepTimer.Start("Draw Axis Final"); // now draw axes. Rectangle axisBounds; pXAxis1.Draw(g, out axisBounds); pXAxis2.Draw(g, out axisBounds); pYAxis1.Draw(g, out axisBounds); pYAxis2.Draw(g, out axisBounds); StepTimer.Stop(sw); }