/// <inheritdoc cref="ICanvas"/> public ICanvas DrawRectangle(PointPair rect, float thickness, float unitsOn) { ValidationUtil.RequireNonNull(rect); var r = rect.ToRectangle(currentDrawingSpace); var pen = GetPen(thickness); if (unitsOn.CompareTo(1f) == 0) { pen.DashStyle = XDashStyle.Solid; } else { pen.DashStyle = XDashStyle.Dash; //var lineLength = rect.ConvertLineLength(currentDrawingSpace); var lineLength = r.Width * 2 + r.Height * 2; var numUnits = lineLength / thickness; var numOnUnits = unitsOn * numUnits; var numOffUnits = numUnits - numOnUnits; pen.DashPattern = new double[] { Math.Max(1, numOnUnits / numOffUnits), Math.Max(1, numOffUnits / numOnUnits) }; } var from = BindPoint(r.X, r.Y, thickness / 2, currentDrawingSpace); var to = BindPoint(r.X + r.Width, r.Y + r.Height, thickness / 2, currentDrawingSpace); //currentGfx.DrawRectangle(pen, r.X, r.Y, r.Width, r.Height); currentGfx.DrawRectangle(pen, from.Item1, from.Item2, to.Item1 - from.Item1, to.Item2 - from.Item2); return(this); }
/// <summary> /// Adds a line with the specified line information. /// </summary> /// <param name="points">the values</param> /// <param name="line">the design</param> /// <param name="lineMarkers">marker above the line; (point index, image)</param> /// <returns>this Builder for chaining</returns> /// <exception cref="ArgumentException">if any arguments is null or points contain less than 2 values</exception> public Builder AddLine(List <float> points, LineInfo line, List <Tuple <int, Bitmap> > lineMarkers) { ValidationUtil.RequireNonNull(points); ValidationUtil.RequireNonNull(line); ValidationUtil.RequirePositive(points.Count - 1, "There must be at least two values in points."); ValidationUtil.RequireNonNull(lineMarkers); if (lineMarkers.Any(t => t == null)) { throw new ArgumentException("No line marker can be null."); } if (lineMarkers.Any(t => t.Item2 == null)) { throw new ArgumentException("No line marker image can be null."); } if (lineMarkers.Select(t => t.Item1).Any(i => i >= points.Count || i < 0)) { throw new ArgumentException("No line marker can have an index outside of the points."); } lines.Add(new Tuple <List <float>, LineInfo, List <Tuple <int, Bitmap> > >(points, line, lineMarkers)); return(this); }
/// <inheritdoc cref="ICanvas"/> public ICanvas WriteText(string text, float x, float y) { ValidationUtil.RequireNonNull(text); ValidationUtil.RequireBetween(x, 0, 1, $"x({x}) must be in range [0, 1]."); ValidationUtil.RequireBetween(y, 0, 1, $"y({y}) must be in range [0, 1]."); var textWidth = GetTextWidth(text); var textHeight = GetTextHeight(text); var textRect = new RectangleF( (currentDrawingSpace.Width * x) + currentDrawingSpace.X, (currentDrawingSpace.Height * y) + currentDrawingSpace.Y, textWidth * currentDrawingSpace.Width, textHeight * currentDrawingSpace.Height); /* * var f = GetFont(); * if (!currentDrawingSpace.Contains(textRect)) * { * throw new ArgumentException("The text does not fit in the current drawing space."); * } */ //currentGfx.DrawString(text, GetFont(), GetBrush(), currentDrawingSpace.Width * x, currentDrawingSpace.Height * y); currentGfx.DrawString(text, GetFont(), GetBrush(), new XPoint(textRect.X, textRect.Y)); return(this); }
/// <summary> /// Adds a horizontal line across the graph. /// </summary> /// <param name="line">the line</param> /// <param name="yValue">the y value to start the line it</param> /// <param name="text">the marker to the left of the line</param> /// <returns>this Builder for chaining</returns> /// <exception cref="ArgumentException">if line is null</exception> public Builder AddHorizontalLine(LineInfo line, float yValue, string text) { ValidationUtil.RequireNonNull(line); horizontalLines.Add(Tuple.Create(line, yValue, text)); return(this); }
/// <summary> /// Adds a vertical line across the graph. /// </summary> /// <param name="line">the line</param> /// <param name="xValue">the x value to start the line at</param> /// <param name="text">the marker below the line</param> /// <returns>this Builder for chaining</returns> /// <exception cref="ArgumentException">if line is null</exception> public Builder AddVerticalLine(LineInfo line, int xValue, string text) { ValidationUtil.RequireNonNull(line); verticalLines.Add(Tuple.Create(line, xValue, text)); return(this); }
/// <summary> /// Adds a IPlottable. /// </summary> /// <param name="plottable">the plottable to add</param> /// <returns>this instance for chaining</returns> public Area AddPlottable(IPlottable plottable) { ValidationUtil.RequireNonNull(plottable); plottables.Add(plottable); return(this); }
/// <summary> /// Returns a new Builder instance. /// </summary> /// <param name="lineWidth">the width of the line</param> /// <param name="subtitle">the subtitle below</param> /// <returns>new Builder instance</returns> public static Builder NewInstance(float lineWidth, string subtitle) { ValidationUtil.RequireBetween(lineWidth, 0, 1, $"lineWidth({lineWidth}) must be in the interval [0, 1]"); ValidationUtil.RequirePositive(lineWidth, $"lineWidth({lineWidth}) must be greater than 0."); ValidationUtil.RequireNonNull(subtitle); return(new Builder(lineWidth, subtitle)); }
/// <summary> /// Sets the numerical markers on the x and y axis. /// </summary> /// <param name="numAxisX">number of markers on x axis</param> /// <param name="numAxisY">number of markers on y axis</param> /// <param name="axisX">function to transform index value to any marker</param> /// <param name="axisY">function to transform value to any marker</param> /// <returns>this Builder for chaining</returns> /// <exception cref="ArgumentException">if any argument is negative</exception> public Builder SetAxisMarkers(int numAxisX, int numAxisY, Func <int, string> axisX, Func <float, string> axisY) { NumMarkersAxisX = ValidationUtil.RequireNonNegative(numAxisX, $"numAxisX({numAxisX}) cannot be negative."); NumMarkersAxisY = ValidationUtil.RequireNonNegative(numAxisY, $"numAxisY({numAxisY}) cannot be negative."); AxisX = ValidationUtil.RequireNonNull(axisX); AxisY = ValidationUtil.RequireNonNull(axisY); return(this); }
/// <summary> /// Fills the rectangle in the graph as specified by the two y-values. /// </summary> /// <param name="fromYValue">the lower y value</param> /// <param name="toYValue">the upper y value</param> /// <param name="color">the color</param> /// <returns>this Builder for chaining</returns> /// <exception cref="ArgumentException">if color is null or fromYValue is equal or greater than toYValue</exception> public Builder SetHorizontalFill(float fromYValue, float toYValue, Color color) { ValidationUtil.RequireNonNull(color); ValidationUtil.RequirePositive(toYValue - fromYValue, $"toYValue({toYValue}) cannot be less than or equal to fromYValue({fromYValue})."); HorizontalFill = Tuple.Create(fromYValue, toYValue, color); return(this); }
/// <summary> /// Returns a new Builder for the version of the form: "vMAJOR.MINOR.PATCH" where /// MAJOR = Major, MINOR = Minor and PATCH = Build. /// </summary> /// <param name="version">the version</param> /// <param name="textInfo">the text information</param> /// <param name="prefix">the prefix added before the version</param> /// <returns>new Builder instance</returns> public static Builder NewVersionInstance(Version version, TextInfo textInfo, string prefix) { ValidationUtil.RequireNonNull(version); ValidationUtil.RequireNonNull(textInfo); ValidationUtil.RequireNonNull(prefix); var versionString = $"{prefix}v{version.Major}.{version.Minor}.{version.Build}"; return(new Builder(versionString, textInfo)); }
/// <summary> /// Returns a new Builder instance with the title to the left of the comment lines. One lineSpacing will be /// added under the title before the first line. /// </summary> /// <param name="lineSpacing">the space between the lines</param> /// <param name="title">the title; if empty no title is used</param> /// <param name="textInfo">the font information of the title</param> /// <returns>new Builder instance</returns> public static Builder NewInstance(float lineSpacing, string title, TextInfo textInfo) { ValidationUtil.RequireBetween(lineSpacing, 0, 1, $"lineSpacing({lineSpacing}) must be in the interval [0, 1]"); ValidationUtil.RequirePositive(lineSpacing, $"lineSpacing({lineSpacing}) must be greater than 0."); ValidationUtil.RequireNonNull(title); ValidationUtil.RequireNonNull(textInfo); return(new Builder(lineSpacing, title, textInfo)); }
/// <inheritdoc cref="ICanvas"/> public ICanvas DrawRectangle(PointPair rect) { ValidationUtil.RequireNonNull(rect); var r = rect.ToRectangle(currentDrawingSpace); currentGfx.DrawRectangle(GetBrush(), r.X, r.Y, r.Width, r.Height); return(this); }
/* * ================================================================================ * ========================== Helper Methods ========================== * ================================================================================ */ #region HelperMethods private XGraphics GetGraphics(int pageId) { if (!graphics.ContainsKey(pageId)) { graphics.Add(pageId, XGraphics.FromPdfPage(currentPage)); } graphics.TryGetValue(pageId, out var graphic); return(ValidationUtil.RequireNonNull(graphic)); }
/// <summary> /// Sets a grid in the graph with automatic number of horizontal lines to make a grid of squares. /// <para> /// Note that the last call to any AddGrid method is applied, rest is ignored. /// </para> /// </summary> /// <param name="grid">the grid lines information</param> /// <param name="numVertical">number of vertical lines</param> /// <returns>this Builder for chaining</returns> /// <exception cref="ArgumentException">if grid is null</exception> public Builder SetGrid(LineInfo grid, int numVertical) { Grid = ValidationUtil.RequireNonNull(grid); NumVertical = ValidationUtil.RequirePositive(numVertical, $"numVertical({numVertical}) must be positive.."); NumHorizontal = -1; AgainstMarkersX = false; AgainstMarkersY = false; return(this); }
/// <summary> /// Sets a grid in the graph where the vertical lines (againstMarkersX) and horizontal lines (againstMarkersY) /// are going out from the numerical markers as set by <see cref="SetAxisMarkers(int,int)"/> or <see cref="SetAxisMarkers(int,int,Func{int,string},Func{float,string})"/> /// <para> /// Note that the last call to any AddGrid method is applied, rest is ignored. /// </para> /// </summary> /// <param name="grid">the grid lines information</param> /// <param name="againstMarkersX">if vertical lines from the markers on the x axis</param> /// <param name="againstMarkersY">if horizontal lines from the markers on the y axis</param> /// <returns>this Builder for chaining</returns> /// <exception cref="ArgumentException">if grid is null</exception> public Builder SetGrid(LineInfo grid, bool againstMarkersX, bool againstMarkersY) { Grid = ValidationUtil.RequireNonNull(grid); AgainstMarkersX = againstMarkersX; AgainstMarkersY = againstMarkersY; NumVertical = 0; NumHorizontal = 0; return(this); }
/// <summary> /// Sets a grid in the graph. /// <para> /// Note that the last call to any AddGrid method is applied, rest is ignored. /// </para> /// </summary> /// <param name="grid">the grid lines information</param> /// <param name="numVertical">number of vertical lines</param> /// <param name="numHorizontal">number of horizontal lines</param> /// <returns>this Builder for chaining</returns> /// <exception cref="ArgumentException">if grid is null</exception> public Builder SetGrid(LineInfo grid, int numVertical, int numHorizontal) { Grid = ValidationUtil.RequireNonNull(grid); NumVertical = ValidationUtil.RequireNonNegative(numVertical, $"numAxisY({numVertical}) cannot be negative."); NumHorizontal = ValidationUtil.RequireNonNegative(numHorizontal, $"numHorizontal({numHorizontal}) cannot be negative."); AgainstMarkersX = false; AgainstMarkersY = false; return(this); }
/// <summary> /// Adds a legend to the graph. /// </summary> /// <param name="text">the text</param> /// <param name="info">the text display info</param> /// <param name="startX">the start x position of the top left corner</param> /// <param name="startY">the start y position of the top left corner</param> /// <returns>this Builder for chaining</returns> /// <exception cref="ArgumentException">if text or info is null or startX or startY not in 0,1 interval</exception> public Builder AddLegend(string text, TextInfo info, float startX, float startY) { ValidationUtil.RequireNonNull(text); ValidationUtil.RequireNonNull(info); ValidationUtil.RequireBetween(startX, 0f, 1f, $"startX({startX}) has to be in the interval [0, 1]."); ValidationUtil.RequireBetween(startY, 0f, 1f, $"startY({startY}) has to be in the interval [0, 1]."); legends.Add(Tuple.Create(text, info, startX, startY)); return(this); }
/// <summary> /// Sets the number of lines. This will result in crash if they cannot fit. Give -1 to mean as many as possible. /// <para> /// Defaults to -1 and a .5 thickness line with RGB(66, 66, 66) with width of 1f. /// </para> /// </summary> /// <param name="numLines">the number of lines</param> /// <param name="lineWidth">the width of the lines</param> /// <param name="lineInfo">the line info</param> /// <returns>this Builder for chaining</returns> public Builder SetLines(int numLines, float lineWidth, LineInfo lineInfo) { if (numLines != -1) { ValidationUtil.RequireNonNegative(numLines, $"numLines({numLines}) must be greater or equal to -1"); } ValidationUtil.RequireBetween(lineWidth, 0, 1, $"lineWidth({lineWidth}) must be in the interval [0, 1]"); ValidationUtil.RequireNonNull(lineInfo); NumLines = numLines; LineWidth = lineWidth; LineInfo = lineInfo; return(this); }
/// <inheritdoc cref="ICanvas"/> public ICanvas DrawImage(Bitmap pngImage, PointPair box) { // Validates the arguments. ValidationUtil.RequireNonNull(pngImage); ValidationUtil.RequireNonNull(box); using (var stream = new MemoryStream()) { pngImage.Save(stream, ImageFormat.Png); // Calculates the dimensions. var rect = box.ToRectangle(currentDrawingSpace); var image = XImage.FromStream(stream); currentGfx.DrawImage(image, rect.X, rect.Y, rect.Width, rect.Height); return(this); } }
/// <inheritdoc cref="ICanvas"/> public ICanvas DrawLine(PointPair line, float thickness, float unitsOn) { ValidationUtil.RequireNonNull(line); ValidationUtil.RequirePositive(thickness, $"thickness({thickness}) must be positive (>0)."); ValidationUtil.RequireBetween(unitsOn, 0, 1, $"unitsOn({unitsOn}) must be in the range [0, 1]."); // Draws the line with the pen. var pen = GetPen(thickness); if (unitsOn.CompareTo(1f) == 0) { pen.DashStyle = XDashStyle.Solid; } else { pen.DashStyle = XDashStyle.Dash; var lineLength = line.ConvertLineLength(currentDrawingSpace); var numUnits = lineLength / thickness; var numOnUnits = unitsOn * numUnits; var numOffUnits = numUnits - numOnUnits; //pen.DashPattern = new double[] {numOnUnits, numOffUnits}; pen.DashPattern = new double[] { Math.Max(1, numOnUnits / numOffUnits), Math.Max(1, numOffUnits / numOnUnits) }; } var fromX = line.ConvertFromX(currentDrawingSpace); var fromY = line.ConvertFromY(currentDrawingSpace); var toX = line.ConvertToX(currentDrawingSpace); var toY = line.ConvertToY(currentDrawingSpace); var from = BindPoint( fromX, fromY, thickness / 2, currentDrawingSpace); var to = BindPoint( toX, toY, thickness / 2, currentDrawingSpace); //currentGfx.DrawLine(pen, fromX, fromY, toX, toY); currentGfx.DrawLine(pen, from.Item1, from.Item2, to.Item1, to.Item2); return(this); }
/// <inheritdoc cref="ICanvas"/> public ICanvas DrawImage(string imageFile, PointPair box) { // Validates the arguments. ValidationUtil.RequireFileExist(imageFile); if (!FileUtil.IsImageFile(imageFile)) { throw new ArgumentException($"imageFile({imageFile}) is not an image."); } ValidationUtil.RequireNonNull(box); // Calculates the dimensions. var rect = box.ToRectangle(currentDrawingSpace); var image = XImage.FromFile(imageFile); currentGfx.DrawImage(image, rect.X, rect.Y, rect.Width, rect.Height); return(this); }
/// <summary> /// Draws all the added <see cref="IPlottable"/> instances. /// </summary> /// <param name="canvasConfig">the canvas config use to get the canvas for drawing</param> public void Draw(ICanvasConfig canvasConfig) { ValidationUtil.RequireNonNull(canvasConfig); canvasConfig.AddPage(page); var canvas = canvasConfig.UsePageArea(box, page); if (canvas.GetModeParam() == ModeParam.Boxed || canvas.GetModeParam() == ModeParam.BoxedCalibration) { canvas.SetColor(Color.Black); canvas.DrawRectangle(PointPair.Full, 1f, 1f); } foreach (var plottable in plottables) { plottable.Plot(canvas); } }
/// <summary> /// Sets the text info of the subtitle. /// <para> /// Defaults to black Helvetica with font size 8. /// </para> /// </summary> /// <param name="textInfo">the text info</param> /// <returns>this Builder for chaining</returns> public Builder SetTextInfo(TextInfo textInfo) { TextInfo = ValidationUtil.RequireNonNull(textInfo); return(this); }
/// <summary> /// Sets the line info of the signature line. /// <para> /// Defaults to a filled .5 thickness line with RGB(66, 66, 66). /// </para> /// </summary> /// <param name="lineInfo">the line info</param> /// <returns>this Builder for chaining</returns> public Builder SetLineInfo(LineInfo lineInfo) { LineInfo = ValidationUtil.RequireNonNull(lineInfo); return(this); }
/// <summary> /// Creates a new Area defined by the box on the specified page. /// </summary> /// <param name="box">the area that the plottables will be plotted in</param> /// <param name="page">the page on the pdf</param> /// <returns>new Area instance</returns> public static Area NewInstance(PointPair box, int page) { ValidationUtil.RequireNonNull(box); return(new Area(box, page)); }
/// <summary> /// Creates a new LinePlottable. /// </summary> /// <param name="line">the line</param> /// <param name="info">the line info</param> /// <returns>new LinePlottable instance</returns> public static LinePlottable NewInstance(PointPair line, LineInfo info) { ValidationUtil.RequireNonNull(line); ValidationUtil.RequireNonNull(info); return(new LinePlottable(line, info)); }
/// <summary> /// Returns a new Builder instance. /// </summary> /// <param name="text">the text</param> /// <param name="textInfo">the text information</param> /// <returns>new Builder instance</returns> public static Builder NewInstance(string text, TextInfo textInfo) { ValidationUtil.RequireNonNull(text); ValidationUtil.RequireNonNull(textInfo); return(new Builder(text, textInfo)); }
/// <summary> /// Centers the text inside the specified box. /// <para> /// Note: this might result in a <see cref="ArgumentException"/> in the <see cref="IPlottable.Plot(ICanvas)"/> method /// if the text cannot fit in the box. /// </para> /// </summary> /// <param name="box">the box</param> /// <returns>this Builder for chaining</returns> public Builder SetCenterIn(PointPair box) { CenterIn = ValidationUtil.RequireNonNull(box); return(this); }
/// <summary> /// Creates a new Builder instance with the PNG as a bitmap. /// </summary> /// <param name="pngImage">the PNG as a bitmap</param> /// <returns>new Builder instance</returns> public static Builder NewInstance(Bitmap pngImage) { ValidationUtil.RequireNonNull(pngImage); return(new Builder(pngImage)); }
/// <summary> /// Sets the scale of the image inside the specified image box. /// <para> /// Defaults to <see cref="ScaleType.Fill"/> with maximum <see cref="PointPair"/>. /// </para> /// </summary> /// <param name="scale">the scale type to apply</param> /// <param name="imageBox">the box to apply scale typ inside</param> /// <returns></returns> public Builder SetScale(ScaleType scale, PointPair imageBox) { Scale = scale; ImageBox = ValidationUtil.RequireNonNull(imageBox); return(this); }