/// <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 (this.AutoScaleTitle) { scaled_font = Utils.ScaleFont(titleFont_, scale); } else { scaled_font = titleFont_; } g.DrawString(title_, scaled_font, this.titleBrush_, x_center, y_center); 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; this.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; this.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 (this.legend_ != null) { legend_.UpdateAxesPositions( pXAxis1, pYAxis1, pXAxis2, pYAxis2, this.drawables_, scale, this.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 (this.plotBackColor_ != null) { g.FillRectangle( new System.Drawing.SolidBrush((Color)this.plotBackColor_), (Rectangle)plotAreaBoundingBoxCache_); } else if (this.plotBackBrush_ != null) { g.FillRectangle( this.plotBackBrush_.Get((Rectangle)plotAreaBoundingBoxCache_), (Rectangle)plotAreaBoundingBoxCache_); } else if (this.plotBackImage_ != null) { Image image = Utils.TiledImage(this.plotBackImage_, new Size(((Rectangle)plotAreaBoundingBoxCache_).Width, ((Rectangle)plotAreaBoundingBoxCache_).Height)); //g.DrawImage( Utils.TiledImage( this.plotBackImage_ , new Size( ((Rectangle)plotAreaBoundingBoxCache_).Width,((Rectangle)plotAreaBoundingBoxCache_).Height ) ), (Rectangle)plotAreaBoundingBoxCache_ ); g.DrawImage(image, (Rectangle)plotAreaBoundingBoxCache_, (Rectangle)plotAreaBoundingBoxCache_, GraphicsUnit.Pixel); } // draw title float xt = (pXAxis2.PhysicalMax.X + pXAxis2.PhysicalMin.X) / 2.0f; float yt = bounds.Top + this.padding_ - titleExtraOffset; Font scaledFont; if (this.AutoScaleTitle) { scaledFont = Utils.ScaleFont(titleFont_, scale); } else { scaledFont = titleFont_; } g.DrawString(title_, scaledFont, this.titleBrush_, xt, yt); //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)); 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 > this.legendZOrder_) { // draw legend. if (!legendDrawn && this.legend_ != null) { legend_.Draw(g, legendPosition, this.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 && this.legend_ != null) { legend_.Draw(g, legendPosition, this.drawables_, scale); } // cache the physical axes we used on this draw; this.pXAxis1Cache_ = pXAxis1; this.pYAxis1Cache_ = pYAxis1; this.pXAxis2Cache_ = pXAxis2; this.pYAxis2Cache_ = pYAxis2; // 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*/ }
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 = this.DetermineScaleFactor( bounds.Width, bounds.Height ); int titleHeight; Graphics g = Graphics.FromImage(new System.Drawing.Bitmap(20, 20)); SizeF size = g.MeasureString("Ðì", titleFont_); if (this.AutoScaleTitle) { titleHeight = (int)size.Height; } else { titleHeight = (int)size.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 ); }
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 = this.DetermineScaleFactor(bounds.Width, bounds.Height); int titleHeight; Graphics g = Graphics.FromImage(new System.Drawing.Bitmap(20, 20)); SizeF size = g.MeasureString("Ðì", titleFont_); if (this.AutoScaleTitle) { titleHeight = (int)size.Height; } else { titleHeight = (int)size.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); }