/// <summary> /// Draws the step plot on a GDI+ surface against the provided x and y axes. /// </summary> /// <param name="g">The GDI+ surface on which to draw.</param> /// <param name="xAxis">The X-Axis to draw against.</param> /// <param name="yAxis">The Y-Axis to draw against.</param> public virtual void Draw(Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis) { SequenceAdapter data = new SequenceAdapter(this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData); double leftCutoff = xAxis.PhysicalToWorld(xAxis.PhysicalMin, false); double rightCutoff = xAxis.PhysicalToWorld(xAxis.PhysicalMax, false); for (int i = 0; i < data.Count; ++i) { PointD p1 = data[i]; if (Double.IsNaN(p1.X) || Double.IsNaN(p1.Y)) { continue; } PointD p2; PointD p3; if (i + 1 != data.Count) { p2 = data[i + 1]; if (Double.IsNaN(p2.X) || Double.IsNaN(p2.Y)) { continue; } p2.Y = p1.Y; p3 = data[i + 1]; } else { // Check that we are not dealing with a DataSource of 1 point. // This check is done here so it is only checked on the end // condition and not for every point in the DataSource. if (data.Count > 1) { p2 = data[i - 1]; } else { // TODO: Once log4net is set up post a message to the user that a step-plot of 1 really does not make any sense. p2 = p1; } double offset = p1.X - p2.X; p2.X = p1.X + offset; p2.Y = p1.Y; p3 = p2; } if (this.center_) { double offset = (p2.X - p1.X) / 2.0f; p1.X -= offset; p2.X -= offset; p3.X -= offset; } PointF xPos1 = xAxis.WorldToPhysical(p1.X, false); PointF yPos1 = yAxis.WorldToPhysical(p1.Y, false); PointF xPos2 = xAxis.WorldToPhysical(p2.X, false); PointF yPos2 = yAxis.WorldToPhysical(p2.Y, false); PointF xPos3 = xAxis.WorldToPhysical(p3.X, false); PointF yPos3 = yAxis.WorldToPhysical(p3.Y, false); // do horizontal clipping here, to speed up if ((p1.X < leftCutoff || p1.X > rightCutoff) && (p2.X < leftCutoff || p2.X > rightCutoff) && (p3.X < leftCutoff || p3.X > rightCutoff)) { continue; } if (!this.hideHorizontalSegments_) { if (scale_ != 1.0f) { float middle = (xPos2.X + xPos1.X) / 2.0f; float width = xPos2.X - xPos1.X; width *= this.scale_; g.DrawLine(Pen, (int)(middle - width / 2.0f), yPos1.Y, (int)(middle + width / 2.0f), yPos2.Y); } else { g.DrawLine(Pen, xPos1.X, yPos1.Y, xPos2.X, yPos2.Y); } } if (!this.hideVerticalSegments_) { g.DrawLine(Pen, xPos2.X, yPos2.Y, xPos3.X, yPos3.Y); } } }
/// <summary> /// Transforms the given world point to physical coordinates /// </summary> /// <param name="worldPoint">the world point to transform</param> /// <returns>the corresponding physical point</returns> public PointF Transform(PointD worldPoint) { return(new PointF( xAxis_.WorldToPhysical(worldPoint.X, false).X, yAxis_.WorldToPhysical(worldPoint.Y, false).Y)); }
/// <summary> /// Constructor /// </summary> /// <param name="position">The position the arrow points to.</param> /// <param name="angle">angle of arrow with respect to x axis.</param> public ArrowItem(PointD position, double angle) { to_ = position; angle_ = -angle; Init(); }
/// <summary> /// Default constructor : /// text = "" /// angle = 45 degrees anticlockwise from horizontal. /// </summary> /// <param name="position">The position the arrow points to.</param> public ArrowItem(PointD position) { to_ = position; Init(); }
/// <summary> /// Constructor /// </summary> /// <param name="position">The position the text starts.</param> /// <param name="text">The text.</param> public TextItem(PointD position, string text) { start_ = position; text_ = text; Init(); }
/// <summary> /// Renders the histogram. /// </summary> /// <param name="g">The Graphics surface on which to draw</param> /// <param name="xAxis">The X-Axis to draw against.</param> /// <param name="yAxis">The Y-Axis to draw against.</param> public void Draw(Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis) { SequenceAdapter data = new SequenceAdapter(DataSource, DataMember, OrdinateData, AbscissaData); float yoff; for (int i = 0; i < data.Count; ++i) { // (1) determine the top left hand point of the bar (assuming not centered) PointD p1 = data[i]; if (double.IsNaN(p1.X) || double.IsNaN(p1.Y)) { continue; } // (2) determine the top right hand point of the bar (assuming not centered) PointD p2; if (i + 1 != data.Count) { p2 = data[i + 1]; if (double.IsNaN(p2.X) || double.IsNaN(p2.Y)) { continue; } p2.Y = p1.Y; } else if (i != 0) { p2 = data[i - 1]; if (double.IsNaN(p2.X) || double.IsNaN(p2.Y)) { continue; } double offset = p1.X - p2.X; p2.X = p1.X + offset; p2.Y = p1.Y; } else { double offset = 1.0f; p2.X = p1.X + offset; p2.Y = p1.Y; } // (3) now account for plots this may be stacked on top of. HistogramPlot currentPlot = this; yoff = 0.0f; double yval = 0.0f; while (currentPlot.isStacked_) { SequenceAdapter stackedToData = new SequenceAdapter( currentPlot.stackedTo_.DataSource, currentPlot.stackedTo_.DataMember, currentPlot.stackedTo_.OrdinateData, currentPlot.stackedTo_.AbscissaData); yval += stackedToData[i].Y; yoff = yAxis.WorldToPhysical(yval, false).Y; p1.Y += stackedToData[i].Y; p2.Y += stackedToData[i].Y; currentPlot = currentPlot.stackedTo_; } // (4) now account for centering if (center_) { double offset = (p2.X - p1.X) / 2.0f; p1.X -= offset; p2.X -= offset; } // (5) now account for BaseOffset (shift of bar sideways). p1.X += baseOffset_; p2.X += baseOffset_; // (6) now get physical coordinates of top two points. PointF xPos1 = xAxis.WorldToPhysical(p1.X, false); PointF yPos1 = yAxis.WorldToPhysical(p1.Y, false); PointF xPos2 = xAxis.WorldToPhysical(p2.X, false); PointF yPos2 = yAxis.WorldToPhysical(p2.Y, false); if (isStacked_) { currentPlot = this; while (currentPlot.isStacked_) { currentPlot = currentPlot.stackedTo_; } baseWidth_ = currentPlot.baseWidth_; } float width = xPos2.X - xPos1.X; float height; if (isStacked_) { height = -yPos1.Y + yoff; } else { height = -yPos1.Y + yAxis.PhysicalMin.Y; } float xoff = (1.0f - baseWidth_) / 2.0f * width; Rectangle r = new Rectangle((int)(xPos1.X + xoff), (int)yPos1.Y, (int)(width - 2 * xoff), (int)height); if (Filled) { if (r.Height != 0 && r.Width != 0) { // room for optimization maybe. g.FillRectangle(rectangleBrush_.Get(r), r); } } g.DrawRectangle(Pen, r.X, r.Y, r.Width, r.Height); } }
/// <summary> /// Draws the point plot on a GDI+ surface against the provided x and y axes. /// </summary> /// <param name="g">The GDI+ surface on which to draw.</param> /// <param name="xAxis">The X-Axis to draw against.</param> /// <param name="yAxis">The Y-Axis to draw against.</param> public virtual void Draw(Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis) { SequenceAdapter data_ = new SequenceAdapter(this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData); float leftCutoff_ = xAxis.PhysicalMin.X - marker_.Size; float rightCutoff_ = xAxis.PhysicalMax.X + marker_.Size; for (int i = 0; i < data_.Count; ++i) { var pointMarker = marker_; if (MarkerCallback != null) { pointMarker = MarkerCallback(data_[i].X, data_[i].Y); } if (!Double.IsNaN(data_[i].X) && !Double.IsNaN(data_[i].Y)) { PointF xPos = xAxis.WorldToPhysical(data_[i].X, false); if (xPos.X < leftCutoff_ || rightCutoff_ < xPos.X) { continue; } PointF yPos = yAxis.WorldToPhysical(data_[i].Y, false); pointMarker.Draw(g, (int)xPos.X, (int)yPos.Y); if (pointMarker.DropLine) { PointD yMin = new PointD(data_[i].X, Math.Max(0.0f, yAxis.Axis.WorldMin)); PointF yStart = yAxis.WorldToPhysical(yMin.Y, false); g.DrawLine(pointMarker.Pen, new Point((int)xPos.X, (int)yStart.Y), new Point((int)xPos.X, (int)yPos.Y)); } if (LabelFont != null) { var markerHalfSize = (float)pointMarker.Size / 2.0f; // Top-left corner var yText = data_[i].Y.ToString(); var textSize = g.MeasureString(yText, LabelFont); var labelRect = new RectangleF(xPos.X, yPos.Y, textSize.Width + LabelPadding + LabelPadding, textSize.Height + LabelPadding + LabelPadding); if (!g.ClipBounds.Contains(labelRect)) { // Try bottom-left corner labelRect.Y = yPos.Y - labelRect.Height; } if (!g.ClipBounds.Contains(labelRect)) { // Try bottom-right corner labelRect.X = xPos.X - labelRect.Width; } if (!g.ClipBounds.Contains(labelRect)) { // Try top-right corner labelRect.Y = yPos.Y; } g.FillRectangle(Brushes.White, labelRect); g.DrawRectangle(Pens.Black, labelRect.X, labelRect.Y, labelRect.Width, labelRect.Height); g.DrawString(yText, LabelFont, pointMarker.FillBrush, labelRect.X + LabelPadding, labelRect.Y + LabelPadding); } } } }