Skip to content

Instantly share code, notes, and snippets.

@lorenzopub
Created March 5, 2018 08:45
Show Gist options
  • Save lorenzopub/c1eaef07aaf34f07334f3a8215dbbfcd to your computer and use it in GitHub Desktop.
Save lorenzopub/c1eaef07aaf34f07334f3a8215dbbfcd to your computer and use it in GitHub Desktop.
Watercolour affect using HTML5 canvas
license: mit
height: 620
scrolling: no
border: no

A rough first attempt at recreating Tyler Hobbs' wonderful generative watercolour effect, this time in Javascript rather than Processing as in Tyler's original. Uses Rob Britton's randgen.js 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).

forked from johnburnmurdoch's block: Watercolour affect using HTML5 canvas

<!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>
View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment