plotterfun

Fun with plotters
git clone https://git.mitxela.com/plotterfun.git
Log | Files | Refs | README

Branches

Name Last commit date Author
am/fm_switch2020-06-08 22:16:11 +0100mitxela
master2020-06-16 17:31:32 +0100mitxela
plot-time2020-05-30 00:27:40 +0100mitxela

File Tree (HEAD)

Name Size
LICENSE1.057K
README.md4.756K
delaunay.js4.37K
external/rhill-voronoi-core.min.js15.99K
external/stackblur.min.js6.259K
halftone.js1.521K
helpers.js6.714K
implode.js1.359K
linedraw.js7.194K
loading.gif616B
main.htm11.6K
mosaic.js2.356K
needles.js1.061K
polyspiral.js1.302K
range.css1.774K
sawtooth.js1.023K
spiral.js1.205K
springs.js1.145K
squiggle.js1.178K
squiggleLeftRight.js1.499K
stipple.js7.826K
subline.js1.168K
waves.js1.756K

History

* a4997e7 (HEAD -> master) |\ mitxela 2020-06-16 17:31 | | Merge pull request #6 from HomineLudens/master | | | * 60f6480 | | Filippo 2020-06-15 20:54 | | Delete gradient.js | | | * 4327bca |/ HomineLudens 2020-06-15 20:35 | Clean up, halftone | * 92e493d |\ mitxela 2020-06-12 00:00 | | Merge pull request #5 from HomineLudens/master | | | * 3a5ae63 | | HomineLudens 2020-06-11 20:55 | | More options on Halftone | | | * eaa7157 |/ HomineLudens 2020-06-11 18:49 | Halftone plugin | * 376dfae |\ mitxela 2020-06-08 22:17 | | Merge pull request #3 'am/fm_switch' | | | * 0dc02f1 (am/fm_switch) | | mitxela 2020-06-08 22:16 | | Questionable improvement to clarity | | | * 3e2d7dc | | christoph 2020-06-07 22:21 | | Added AM/FM/Both switch to squiggle | | * | 2fc796e |/ mitxela 2020-06-08 21:57 | Add Implode algorithm | * 5c6e0c0 | mitxela 2020-06-06 17:18 | Avoid floating point errors when incrementing with arrow keys | * 372ec6e | mitxela 2020-06-06 13:14 | Use up/down arrow keys for input incrementation | * 420bd89 | mitxela 2020-06-06 13:06 | Add MIT licence | * f2e3597 | mitxela 2020-06-05 20:31 | Add title | * cd4ab52 | mitxela 2020-06-05 16:11 | Add vanity line | * 5cea8ec | mitxela 2020-06-05 15:43 | fixup! If we're going to have persistent controls, at least make it consistent | * 7ebb31f | mitxela 2020-06-05 15:17 | Allow speed change for animations | * e151fcf | mitxela 2020-06-05 15:14 | Questionable webcam aspect ratio fix | | * a498275 (plot-time) |/ mitxela 2020-05-30 00:08 | Attempt at estimating plot time. Kinda useless until we can figure out the fudge factor for corners | * 5d1937d | mitxela 2020-05-29 19:09 | Add gamma control to delaunay, much better | * 9923788 | mitxela 2020-05-29 18:10 | If we're going to have persistent controls, at least make it consistent | * bbfa8c1 | mitxela 2020-05-29 17:50 | More nonsense, zoom from centre of preview | * bfe8abf | mitxela 2020-05-29 13:15 | Add README.md | * be31843 | mitxela 2020-05-26 14:18 | Cleanup, reuse path element on update | * d1d45d2 | mitxela 2020-05-26 14:18 | Make chrome happy about wheel events | * 34da73e | mitxela 2020-05-25 18:14 | Fix typo in stipple.js | * ed0021a | mitxela 2020-05-25 16:53 | Make loading gif blue | * 78c543c | mitxela 2020-05-25 16:42 | This is probably a much better way of doing the worker fallback | * 0c48e50 | mitxela 2020-05-25 15:46 | Attempt to fix hacky-fallback-stuff | * b230b42 | mitxela 2020-05-25 15:44 | Loading animation while scripts are fetched | * af09734 | mitxela 2020-05-25 14:09 | Rename wave amplitude control so it doesn't conflict | * 4301868 | mitxela 2020-05-25 13:57 | Styling, the lengths we must go to to make range input consistent | * 88a2940 | mitxela 2020-05-24 13:57 | Update all algorithms to generate pathstrings in workers | * d4b65b4 | mitxela 2020-05-24 12:26 | Give circles the same pathstring treatment | * 39d599b | mitxela 2020-05-23 21:28 | Allow generating pathstring in workers | * 14b29f3 | mitxela 2020-05-23 20:04 | Combine paths into single pathstring for perfomance reasons | * a28c7c2 | mitxela 2020-05-23 18:08 | Route optimise for delaunay | * 6e3b984 | mitxela 2020-05-23 17:55 | Delaunay triangulation algo | * 257a73b | mitxela 2020-05-23 13:16 | fixup! Allow scrolling when window is smaller than SVG | * 44be770 | mitxela 2020-03-08 16:54 | fixup! Add needles algo | * eab075f | mitxela 2020-02-25 10:48 | Allow scrolling when window is smaller than SVG | * 5eadaa6 | mitxela 2020-02-21 19:58 | Add needles algo | * 03d9fe4 | mitxela 2020-02-20 14:54 | Add waves algo | * 214975a | mitxela 2020-02-20 13:11 | Add springs algo | * 6b94141 | mitxela 2020-02-18 22:05 | Add subline algo | * 211620a | mitxela 2020-01-04 16:25 | Update complex scripts to sort-of work not in workers | * e863b02 | mitxela 2020-01-01 20:33 | Hacky fallback for running workers from file:/// | * a2e370b | mitxela 2019-12-31 14:12 | Equalize threshold levels | * 9961021 | mitxela 2019-12-31 13:59 | Add mosaic algo | * a7f0623 | mitxela 2019-12-21 23:31 | Snowflakes | * 0d69ee7 | mitxela 2019-12-20 16:56 | Pentagrams | * c06d501 | mitxela 2019-12-10 15:53 | Fix linedraw route-optimise | * 1f073b0 | mitxela 2019-12-09 19:03 | Improve TSP termination | * 47c4bd5 | mitxela 2019-12-09 17:40 | Image size controls | * cb336fd | mitxela 2019-12-09 04:49 | Move and resize preview image | * cdc1249 | mitxela 2019-12-09 03:57 | Start on select image and splat a bunch of CSS in | * d56b6d9 | mitxela 2019-12-08 17:21 | Add stipple shape option | * 902c1f2 | mitxela 2019-12-08 16:27 | Move more stuff into helpers.js | * 5bd9eb5 | mitxela 2019-12-08 16:04 | Add perlin noise | * 77fb7bf | mitxela 2019-12-08 04:48 | route optimize | * e3f4ced | mitxela 2019-12-08 03:48 | massive speedup to hatching | * 57c7428 | mitxela 2019-12-08 03:00 | Hatching added | * 4d2f878 | mitxela 2019-12-07 19:16 | contours done | * 58fd228 | mitxela 2019-12-07 15:46 | progress on linedraw.js | * 0555a54 | mitxela 2019-12-07 01:41 | Work begins on linedraw.js | * 2739b6f | mitxela 2019-12-06 20:56 | check-in | * fe9c175 | mitxela 2019-12-05 19:45 | Rewrite stipple.js to run asynchronously | * f484e16 | mitxela 2019-12-05 03:25 | improve controls | * f30701c | mitxela 2019-12-04 17:22 | Potential method of changing params without restarting thread | * 8b8a2de | mitxela 2019-12-03 22:03 | Add pre-blur using StackBlur.js | * bb6a9ed | mitxela 2019-12-03 16:20 | TSP optimization done | * c5a1fa0 | mitxela 2019-12-03 00:17 | Working weighted voronoi stipples, need to do TSP next | * e1f061e | mitxela 2019-12-02 13:22 | progress on stipples | * c2f9445 | mitxela 2019-12-02 00:33 | Add sawtooth algorithm | * 2c87027 | mitxela 2019-12-02 00:16 | Simplify squiggle.js as much as possible | * cfa28ed | mitxela 2019-12-01 23:56 | Stick contrast into helper function, kill thread on param change, cleanup squiggles | * c081152 | mitxela 2019-11-30 14:32 | Almost viable stipples | * a58d34f | mitxela 2019-11-30 03:10 | Polygon spiral | * 8fba367 | mitxela 2019-11-28 22:06 | Add more algorithms: left/right, spiral | * ac0a68f | mitxela 2019-11-28 15:20 | add invert & download svg | * f510286 mitxela 2019-11-28 14:14 Initial commit

Contents of README.md:

Plotterfun

A collection of algorithms for turning images into vector art.

Try it out here: https://mitxela.com/plotterfun/

The aim is to make it simple to develop new algorithms. Each algorithm is a separate .js file and is loaded as a webworker. Some of the algorithms are my versions of other vector art programs.

Squiggle

Based on SquiggleCam / SquiggleDraw. The left/right, spiral and PolygonSpiral versions apply the same squiggling to different paths.

SippleGen

Iterative weighted voronoi stippling, with 2-opt travelling-salesman route optimization. I love StippleGen but it runs very slowly, and because it's single threaded the interface freezes while it's running. In porting it to javascript, I significantly rewrote parts of it in order to get it to run much faster.

Makes use of rhill's voronoi library and StackBlur, both included in minimized form in the 'external' directory.

Linedraw

Port of linedraw.py by LingDong-

Other algorithms

The rest are things I came up with on my own. Delaunay is very similar to StippleGen, but after the weighted voronoi iteration the Delaunay Triangulation is plotted. There are a few variations on squiggles (sawtooth, springs) and other algorithms not based on anything in particular. Try them out, it should be fairly clear what each control does.

Usage

When you load a picture, you can drag the preview image around and zoom with the scroll wheel.

The size is limited to 800px when you first load the image, but you're welcome to make it as big as you like. This is mostly because some algorithms have hard-coded defaults (like blur radius or border size) which work best with images of about 800px wide. However, if you're trying to produce a Stipple or Delaunay image with a huge number of stipples, the integration will not work very well if the polygons are too small, so making the image bigger can improve the results.

Each slider has a text box next to it, where you can type in an arbitrary number. Absurd numbers may crash the algorithm, but in the worst case scenario refreshing the page will fix everything. You're welcome to attempt a million stipples if it takes your fancy.

Plotting

When you're happy with the vector image, download the SVG and open it in Inkscape. Resize it (change units to mm or inches) then head to Extensions > Export > Plot.

Developing new algorithms

Each algorithm is in its own .js file. The helpers.js file can be imported to simplify things. The algo first sends a message describing the controls it needs, which usually starts with defaultControls (brightness/contrast/inverted etc). In addition to sliders, checkboxes and combo boxes are possible.

The worker is then sent a message with configuration (describing the state of the controls) and the imagedata. If using the default controls, pixelProcessor from helpers.js will return a function that lets you get the darkness of a pixel after the brightness/contrast has been applied.

Each time a control is changed, the algorithm is killed and restarted. If the algorithm is complex, you can post messages to the main thread with status information. To send vector data, use postCircles or postLines to send paths, or lists of paths.

For complex algorithms, specifying noRestart: true on a control will stop it from killing and restarting the worker. However, since workers won't receive another message until they've finished working, you will need to periodically stop and check for messages to make use of this. The approach I took in stipple.js was to wrap chunks of work in setTimeout() calls and make the main rendering an async function that can await them. You might describe this as a method-of-least-ugliness.

I strongly recommend reading the code for the existing algorithms, I've tried to make things as clear as possible.

About webworkers

For "security" reasons, browsers refuse to run webworkers from files loaded straight from your disk. As a hacky fallback, plotterfun will detect this happening and append the script to the document, so that simple algorithms can still be developed this way. Complex algorithms will either freeze the interface while they run, or if they're asynchronous, risk running repeatedly since they cannot be killed properly.

It's much better to host the files locally for development, using either node's http-server or python -m http.server. Be aware that browsers aggressively cache webworkers, it's essential to have the developer tools open and "Disable Cache" ticked, or you will not have any fun.