JSFiddle - React, Tailwind, and code Playground

CSS

body {
    margin: 0;
    padding: 0;
    background: #fff;
}

JavaScript

var canvas = document.createElement('canvas'),
    context = canvas.getContext('2d');

var image = new Image();
image.addEventListener('load', function () {
    canvas.width = this.width *.8;
    canvas.height = this.height *.8;
    context.drawImage(image, 0, 0, canvas.width, canvas.height);
    document.body.appendChild(canvas);
});
image.src = 'http://freetopwallpaper.com/wp-content/uploads/2013/09/free-beautiful-place-wallpaper-hd-104.jpg';


canvas.addEventListener('click', function (event) {
    var rect = document.body.getBoundingClientRect(),
        x = event.pageX - rect.left - window.scrollX,
        y = event.pageY - rect.top - window.scrollY;
   
    draw(new Date(), x, y);
});
    
function draw(start, x, y) {
    var duration = 1000,
        ms = new Date() - start,
        percent = ms / duration;


    if (ms > duration + 100) {
        setTimeout(function () {
            context.drawImage(image, 0, 0, canvas.width, canvas.height);
        }, 1000);
        return;
    }

    context.drawImage(image, 0, 0, canvas.width, canvas.height);
    
    context.save();
	context.globalCompositeOperation = 'destination-in';

    var radius = Math.floor(1 + (canvas.width*3 - (canvas.width*3 * percent)));
    if (radius < 1) radius = 1;
	var gradient = context.createRadialGradient(x, y, 0, x, y, radius);
	gradient.addColorStop(0, 'rgba(0,0,0,1)');
	gradient.addColorStop(1, 'rgba(0,0,0,0)');
	context.fillStyle = gradient;
    
    // repeat to intensify the fade
	context.fillRect(0, 0, canvas.width, canvas.height);
	//context.fillRect(0, 0, canvas.width, canvas.height);
    
    context.restore();
    
    window.requestAnimationFrame(function () {
        draw(start, x, y);
    });
}