📕 canvas-sketch-util → Documentation → penplot
A set of utilities around pen plotting with the AxiDraw V3. This is ideally used alongside canvas-sketch CLI tools for exporting SVG files.
This tool allows you to create arbitrary "path" instances using familiar Canvas2D APIs, and then serialize these as a complete SVG that should be plottable. In this utility, a "path" can be a polyline, Path instance, or SVGPath string.
const { pathsToSVG, createPath } = require('canvas-sketch-util/penplot');
// You can create a Path serializer like so
const path0 = createPath(context => {
context.moveTo(25, 50);
context.lineTo(10, 10);
context.arc(52, 50, 25, 0, Math.PI * 2);
});
// You can also append commands onto the path
// path.lineTo(50, 50);
// And/or you can use manual polylines like so
const path1 = [
[ 0, 0 ], [ 50, 25 ], [ 25, 50 ]
];
// Generate a SVG file as a string
// Accepts a single or multiple (potentially nested) "path" interfaces
// A "path" can be a polyline, SVGPath string, or Path object from createPath
const svg = pathsToSVG([ path0, path1 ], {
width: 2,
height: 2,
units: 'cm',
lineWidth: 0.04,
// optimize the SVG output for pen plotter use
optimize: true
});
Creates a new Path serializer which can be used for drawing lines, arcs, rectangles and shapes with Canvas2D-style functions. If you specify a fn
, it will be called with the path as the argument before returning. For example:
const path = createPath(context => {
// Circle in centre of page
context.arc(width / 2, height / 2, 25, 0, Math.PI * 2);
});
// Get a SVG string of the path
const svg = path.toString();
The Path interface has the following drawing functions, see d3-path API for details. The drawing functions match those in Canvas2D contexts.
moveTo(x, y)
lineTo(x, y)
quadraticCurveTo(cpx, cpy, x, y)
bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x, y)
arcTo(x1, y1, x2, y2, radius)
arc(x, y, radius, startAngle, endAngle[, anticlockwise])
closePath()
rect(x, y, width, height)
To get the SVGPath string, use path.toString()
.
Converts a single or multiple (potentially listed) array of 'paths' (Path objects, SVGPath strings, or polylines) into a flat 1-dimensional list of polyline contours.
This is done by converting all SVGPath strings into cubic bezier arcs, and then subdividing them into discrete lists of points.
const inputs = /* .. path, polylines, etc .. */;
pathsToPolylines(inputs).forEach(contour => {
context.beginPath();
contour.forEach(point => {
context.lineTo(point[0], point[1]);
});
context.stroke();
});
You can specify { curveResolution }
option (a number) to adjust the smoothness when converting SVG paths into discrete polyline lists. The number is the inverse of the distance threshold to further subdivide curves, a higher resolution leads to more subdivisions. By default, a reasonable default will be selected from your { units }
option (4 units converted to pixels at 96 DPI). For example:
// Use a resolution of 1
pathsToPolylines(inputs, { curveResolution: 1 });
// Choose a reasonable default resolution based on units
pathsToPolylines(inputs, { units: 'cm' });
// No options specified, will default to a resolution of 4
pathsToPolylines(inputs);
Generates a physically-sized SVG file as a string from the given list of paths
with the specified options in opt
. The paths
can be a single or multiple nested path instances, such as Path objects from createPath
, or SVGPath strings, or polylines (nested 2D points using arrays).
Options:
units
(defaults to'px'
) a unit string like'cm'
,'px'
,'in'
, etcwidth
(required) the width of the resulting output inunits
height
(required) the height of the resulting output inunits
lineWidth
(defaults to 0.03 cm in userunits
) the line width of strokesstrokeStyle
(defaults to'black'
) the color of the strokesprecision
(defaults to 5) the decimal precision for floating point numbers as they are converted to stringsfillStyle
(defaults to'none'
) the fill style of SVG path elementscurveResolution
(defaults to a reasonable smoothness) the resolution when converting SVG paths into discrete arcs, see pathsToPolylines for detailsoptimize
(defaults to false) if true, enables path sorting for optimal traversal distance and merging end-points to reduce pen lifts. Can also specify an object instead of a boolean:optimize.sort
(default true) – can disable distance sortingoptimize.removeDuplicates
(default true) – remove duplicaet adjacent points (before merging)optimize.removeCollinear
(default true) – remove unnecessary collinear adjacent points within linesoptimize.merge
(default true) – can disable end point mergingoptimize.mergeThreshold
(default 0.25 mm in your units) – adjsut the distance threshold at which to merge end points
Returns a string of the SVG file.
The SVG is formatted in such a way that it can be easily opened and exported to AxiDraw V3 with Inkscape.
Renders the specified list of lines
(each containing an array of 2D coordinates) using the specified props
(expected to be from canvas-sketch
), returning an array of renderable layers: [ canvas, svgOutput ]
.
💡
This is a convenience function to be used alongside
canvas-sketch
.
This will render the lines as 2D paths into the canvas context given by props
, and then convert them into a SVG file. The return value is a list of layers that can be used for exporting both a PNG and SVG file with canvas-sketch-cli
.
Example:
const canvasSketch = require('canvas-sketch');
const { createPath, renderPaths } = require('canvas-sketch-util/penplot');
const settings = {
dimensions: 'A4',
pixelsPerInch: 300,
units: 'cm',
};
const sketch = ({ width, height }) => {
// Create shapes with path interface
const shape0 = createPath(ctx => ctx.arc(0, 0, 50, 0, Math.PI * 2));
// And/or with polylines or plain SVGStrings, e.g. from a .svg file
const shape1 = [ [ 0, 0 ], [ 50, 25 ] ];
// Combine into an array or nested array
const paths = [ shape0, shape1 ];
// Export both PNG and SVG files on 'Cmd + S'
return props => renderPaths(paths, props);
};
canvasSketch(sketch, settings);
You can also override settings such as lineWidth
or strokeStyle
if you want a different SVG output:
const sketch = ({ width, height }) => {
// ...
return props => renderPaths(paths, {
...props,
lineWidth: 0.05
});
};
Full list of expected props:
context
(required) The canvas contextunits
The units of the artworkwidth
(required) the width of the artwork inunits
height
(required) the width of the artwork inunits
background
The backgroundfillStyle
for 2D canvas, default'white'
foreground
The foregroundstrokeStyle
applied only to the 2D canvas, defaults to'black'
(use this if you wish to have a white stroke on black PNG, but still a black stroke SVG)- Other properties passed into
pathsToSVG
function