This might be handy if you have an SVG file that you want to use as, say, a mask for a generative algorithm.
Place the SVG file in the same directory that you are running penplot from.
| import { Orientation } from 'penplot'; | |
| import { polylinesToSVG } from 'penplot/util/svg'; | |
| import { parse } from 'extract-svg-path'; | |
| import parseSvgPath from 'parse-svg-path'; | |
| import svgPathContours from 'svg-path-contours'; | |
| import normalizePathScale from 'normalize-path-scale'; | |
| import boundPoints from 'bound-points'; | |
| export const orientation = Orientation.LANDSCAPE; | |
| export const dimensions = [ 22.0, 22.0 ]; | |
| export default function createPlot (context, dimensions) { | |
| const [ width, height ] = dimensions; | |
| let lines = []; | |
| return window.fetch('svg-test.svg') | |
| .then(resp => resp.text()) | |
| .then(text => { | |
| // Update list of lines | |
| lines = toPolylines(text); | |
| // Return penplot options to start rendering | |
| return { | |
| draw, | |
| print, | |
| background: 'white', | |
| animate: false, | |
| clear: true | |
| }; | |
| }); | |
| // render SVG into line segments for penplotter | |
| function toPolylines (svgContents) { | |
| // Extract <path> data from SVG contents | |
| const svgPath = parse(svgContents); | |
| // Turn into MoveTo, LineTo, etc SVG commands | |
| const svgCommands = parseSvgPath(svgPath); | |
| // Normalize all the commands and discretize curves/etc into 2D polylines | |
| const curveDetail = 1; | |
| const contours = svgPathContours(svgCommands, curveDetail); | |
| // Now, to work with general SVGs you may want to normalize the path scale | |
| // so that your print doesn't need to match the same size as your SVG | |
| // Do this by getting all 2D points of the polylines | |
| const points = contours.reduce((a, b) => a.concat(b), []); | |
| // Then get the bounding box of all 2D points | |
| const bounds = boundPoints(points); | |
| // And normalize each polyline to that bounding box | |
| const lines = contours.map(line => normalizePathScale(line, bounds)); | |
| // Now you are in 0..1 range, you can apply translation/scale here to center it | |
| const x = width / 2; | |
| const y = height / 2; | |
| const margin = 2; // margin from edge in centimeters | |
| const scale = Math.min(width, height) / 2 - margin; | |
| return lines.map(line => { | |
| return line.map(point => { | |
| return [ x + point[0] * scale, y + point[1] * scale ]; | |
| }); | |
| }); | |
| } | |
| function draw () { | |
| lines.forEach(points => { | |
| context.beginPath(); | |
| points.forEach(p => context.lineTo(p[0], p[1])); | |
| context.stroke(); | |
| }); | |
| } | |
| function print () { | |
| return polylinesToSVG(lines, { | |
| dimensions | |
| }); | |
| } | |
| } |