Skip to content

Instantly share code, notes, and snippets.

@miracle2k
Forked from johnburnmurdoch/.block
Created December 21, 2020 00:23
Show Gist options
  • Select an option

  • Save miracle2k/6bbbb30535360a1f410665335de33fe5 to your computer and use it in GitHub Desktop.

Select an option

Save miracle2k/6bbbb30535360a1f410665335de33fe5 to your computer and use it in GitHub Desktop.

Revisions

  1. Michael Elsdörfer revised this gist Dec 21, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <script src="https://unpkg.com/d3/build/d3.min.js"></script>
    <script src="https://unpkg.com/d3@5"></script>
    <script src="https://unpkg.com/d3-selection-multi"></script>
    <script src="randgen.js"></script>

  2. @johnburnmurdoch johnburnmurdoch revised this gist Feb 4, 2018. 2 changed files with 0 additions and 0 deletions.
    Binary file added preview.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added thumbnail.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  3. @johnburnmurdoch johnburnmurdoch revised this gist Feb 4, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion .block
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    license: mit
    height: 620
    scrolling: no
    border: yes
    border: no
  4. @johnburnmurdoch johnburnmurdoch revised this gist Feb 4, 2018. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions .block
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,4 @@
    license: mit
    height: 620
    scrolling: no
    border: yes
  5. @johnburnmurdoch johnburnmurdoch created this gist Feb 4, 2018.
    4 changes: 4 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,4 @@
    A rough first attempt at recreating Tyler Hobbs' wonderful [generative watercolour effect](http://www.tylerlhobbs.com/writings/watercolor), this time in Javascript rather than Processing as in Tyler's original. Uses Rob Britton's [randgen.js](https://www.npmjs.com/package/randgen) to generate the Gaussian random numbers required in the polygon deformation step.

    ## Instructions
    Double-click anywhere in the canvas to “paint” a blotch of colour (currently set to use hues from blue-green to pink-purple, see line 108 of index.html).
    119 changes: 119 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,119 @@
    <!doctype html>
    <html lang="">
    <head>
    <meta charset="utf-8">
    <title>Canvas watercolour</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <script src="https://unpkg.com/d3/build/d3.min.js"></script>
    <script src="https://unpkg.com/d3-selection-multi"></script>
    <script src="randgen.js"></script>

    <style>
    canvas{border: 1px solid #aaaaaa;}
    </style>
    </head>
    <body>
    <canvas></canvas>
    <script type='text/javascript'>

    let width = 600,
    height = 600,
    PR = window.devicePixelRatio || 1,
    scaledWidth = width*PR,
    scaledHeight = height*PR;

    const canvas = d3.select('canvas')
    .attrs({
    width: scaledWidth,
    height: scaledHeight,
    })
    .styles({
    width: `${width}px`,
    height: `${height}px`
    });

    const context = d3.select('canvas').node().getContext("2d");
    context.scale(PR, PR);
    context.clearRect(0,0, scaledWidth, scaledHeight);

    context.lineWidth = 1;

    context.globalCompositeOperation = 'multiply;'

    function makeShape(x, y, radius){
    return [
    [x, y-radius],
    [x+(radius*.65), y-(radius*.65)],
    [x+radius, y],
    [x+(radius*.65), y+(radius*.65)],
    [x, y+radius],
    [x-(radius*.65), y+(radius*.65)],
    [x-radius, y],
    [x-(radius*.65), y-(radius*.65)],
    ]
    }

    function deform(points, factor){
    let newPoints = [],
    midX, midY, rangeX, rangeY;
    for(let p=0; p<points.length; p++){
    newPoints.push(points[p]);
    if(p == points.length-1){
    midX = d3.mean([points[p][0], points[0][0]]);
    midY = d3.mean([points[p][1], points[0][1]]);
    rangeX = Math.abs(points[p][0]-points[0][0]);
    rangeY = Math.abs(points[p][1]-points[0][1]);
    }else{
    midX = d3.mean([points[p][0], points[p+1][0]]);
    midY = d3.mean([points[p][1], points[p+1][1]]);
    rangeX = Math.abs(points[p][0]-points[p+1][0]);
    rangeY = Math.abs(points[p][1]-points[p+1][1]);
    }
    let newX = rnorm(midX, rangeX*factor),
    newY = rnorm(midY, rangeY*factor);
    newPoints.push([newX, newY]);
    }
    newPoints.push(points[0]);
    return newPoints;
    }

    function draw(points){
    context.beginPath();
    context.moveTo(points[0][0], points[0][1]);
    for(let v=1; v<points.length; v++){
    context.lineTo(points[v][0], points[v][1]);
    }
    context.closePath();
    context.fill();
    }

    function paint(shape, colour, deforms, layers){
    context.fillStyle = colour;
    for(let l=0; l<layers; l++){
    let layer = shape;
    for(let it=0; it<=deforms; it++){
    layer = deform(layer, 0.8);
    if(it == deforms){
    draw(layer);
    }
    }
    }
    }

    d3.select(window).on('dblclick', () => {
    let trans = d3.mouse(canvas.node());
    let shape = makeShape(trans[0], trans[1], 50),
    maxIt = 1;
    for(let it=0; it<=maxIt; it++){
    shape = deform(shape, 0.5);
    if(it == maxIt){
    paint(shape, `hsla(${Math.random()*150+150},70%,50%,0.005)`, 8, 50);
    }
    }
    });

    </script>
    </body>
    </html>
    162 changes: 162 additions & 0 deletions randgen.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,162 @@
    /*jslint indent: 2, plusplus: true, sloppy: true */
    // Generate uniformly distributed random numbers
    // Gives a random number on the interval [min, max).
    // If discrete is true, the number will be an integer.
    function runif(min, max, discrete) {
    if (min === undefined) {
    min = 0;
    }
    if (max === undefined) {
    max = 1;
    }
    if (discrete === undefined) {
    discrete = false;
    }
    if (discrete) {
    return Math.floor(runif(min, max, false));
    }
    return Math.random() * (max - min) + min;
    }

    // Generate normally-distributed random nubmers
    // Algorithm adapted from:
    // http://c-faq.com/lib/gaussian.html
    function rnorm(mean, stdev) {
    var u1, u2, v1, v2, s;
    if (mean === undefined) {
    mean = 0.0;
    }
    if (stdev === undefined) {
    stdev = 1.0;
    }
    if (rnorm.v2 === null) {
    do {
    u1 = Math.random();
    u2 = Math.random();

    v1 = 2 * u1 - 1;
    v2 = 2 * u2 - 1;
    s = v1 * v1 + v2 * v2;
    } while (s === 0 || s >= 1);

    rnorm.v2 = v2 * Math.sqrt(-2 * Math.log(s) / s);
    return stdev * v1 * Math.sqrt(-2 * Math.log(s) / s) + mean;
    }

    v2 = rnorm.v2;
    rnorm.v2 = null;
    return stdev * v2 + mean;
    }

    rnorm.v2 = null;

    // Generate Chi-square distributed random numbers
    function rchisq(degreesOfFreedom) {
    if (degreesOfFreedom === undefined) {
    degreesOfFreedom = 1;
    }
    var i, z, sum = 0.0;
    for (i = 0; i < degreesOfFreedom; i++) {
    z = rnorm();
    sum += z * z;
    }

    return sum;
    }

    // Generate Poisson distributed random numbers
    function rpoisson(lambda) {
    if (lambda === undefined) {
    lambda = 1;
    }
    var l = Math.exp(-lambda),
    k = 0,
    p = 1.0;
    do {
    k++;
    p *= Math.random();
    } while (p > l);

    return k - 1;
    }

    // Generate Cauchy distributed random numbers
    function rcauchy(loc, scale) {
    if (loc === undefined) {
    loc = 0.0;
    }
    if (scale === undefined) {
    scale = 1.0;
    }
    var n2, n1 = rnorm();
    do {
    n2 = rnorm();
    } while (n2 === 0.0);

    return loc + scale * n1 / n2;
    }

    // Bernoulli distribution: gives 1 with probability p
    function rbernoulli(p) {
    return Math.random() < p ? 1 : 0;
    }

    // Vectorize a random generator
    function vectorize(generator) {
    return function () {
    var n, result, i, args;
    args = [].slice.call(arguments)
    n = args.shift();
    result = [];
    for (i = 0; i < n; i++) {
    result.push(generator.apply(this, args));
    }
    return result;
    };
    }

    // Generate a histogram from a list of numbers
    function histogram(data, binCount) {
    binCount = binCount || 10;

    var bins, i, scaled,
    max = Math.max.apply(this, data),
    min = Math.min.apply(this, data);

    // edge case: max == min
    if (max === min) {
    return [data.length];
    }

    bins = [];

    // zero each bin
    for (i = 0; i < binCount; i++) {
    bins.push(0);
    }

    for (i = 0; i < data.length; i++) {
    // scale it to be between 0 and 1
    scaled = (data[i] - min) / (max - min);

    // scale it up to the histogram size
    scaled *= binCount;

    // drop it in a bin
    scaled = Math.floor(scaled);

    // edge case: the max
    if (scaled === binCount) { scaled--; }

    bins[scaled]++;
    }

    return bins;
    }

    /**
    * Get a random element from a list
    */
    function rlist(list) {
    return list[runif(0, list.length, true)];
    }