JSFiddle - React, Tailwind, and code Playground

by Lachlan Arthur

HTML

<p>CAPTCHA generator in JS</p>
<canvas id="c" width="500" height="200" />

JavaScript

console.time("drawing");

var c = document.querySelector("#c");
var ctx = c.getContext("2d");

// The text, obviously
var text = "A1b23Cd";

// Start at th height of the canvas
var textHeight = c.height;
ctx.font = textHeight + "px serif";

// Always have 20px on each side of text
while (ctx.measureText(text).width > c.width - 40) {
    textHeight--;
    ctx.font = textHeight + "px serif";
}

// Align the text in the middle of the image
ctx.textAlign = "center";
ctx.textBaseline = "middle";

// Move the canvas down and right 1 pixel before drawing the shadow
ctx.translate(2, 2);

// draw the full black text (the shadow)
ctx.fillStyle = "#000";
ctx.fillText(text, c.width / 2, c.height / 2);

// prepare to punch the text out of the shadow
ctx.globalCompositeOperation = "destination-out";

// Move the canvas back to it's original position
ctx.translate(-2, -2);

// This text will remove most of the shadow (the parts that will be transparent text)
ctx.fillStyle = "#f00";
ctx.fillText(text, c.width / 2, c.height / 2);

// Change back to normal composition
ctx.globalCompositeOperation = "source-over";

// Draw the transparent text
ctx.fillStyle = "rgba(127,127,127,.15)";
ctx.fillText(text, c.width / 2, c.height / 2);

// Make the background draw behind everything else
ctx.globalCompositeOperation = "destination-over";

// The centre for the gradient background
var centreX = Math.floor(Math.random() * c.width);
var centreY = Math.floor(Math.random() * c.height);

// Draw the background
for (var x = 0; x < c.width; x++) {
    for (var y = 0; y < c.height; y++) {
        var dist = Math.sqrt(Math.pow(centreX - x, 2) + Math.pow(centreY - y, 2));
        var colour = (
            Math.floor(
                77 * Math.cos(
                    .1 * dist
                )
            )
        ) + 128;
        ctx.fillStyle = "rgb(" + colour + ", " + colour+ ", " + colour + ")";
        ctx.fillRect(x, y, 1, 1);
    }
}

console.timeEnd("drawing");