JSFiddle - React, Tailwind, and code Playground

by Case Mate

HTML

<canvas id="canvas" width="300" height="250" style="background-color: #f1f1f1;"></canvas>

JavaScript

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');

var redRect = {
    x: 33,
    y: 33,
    width: 200,
    height: 60,
    color: '#af0000'
};
var blackRect = {
    x: 77,
    y: 66,
    width: 120,
    height: 60,
    color: '#000'
};
var blackRectHole = {
    x: 110,
    y: 80,
    width: 20,
    height: 20
};
var cvRect = {
    x: 0,
    y: 0,
    width: canvas.width,
    height: canvas.height
};


function drawRect(rect) {
    ctx.beginPath();
    ctx.fillStyle = rect.color;
    ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
    ctx.closePath();
}

function drawRectClipped(rect, clipRect) {
    ctx.save();
   clipOut(clipRect);
    drawRect(rect);
    ctx.restore();
}

function clipOut(clipRect) {
    ctx.beginPath();
    rectPath(cvRect);
    ctx.lineTo(clipRect.x, clipRect.y);
    rectPath_ccw(clipRect);
    ctx.clip();    
}

function rectPath(rect) {
    ctx.moveTo(rect.x, rect.y);
    ctx.lineTo(rect.x + rect.width, rect.y);
    ctx.lineTo(rect.x + rect.width, rect.y + rect.height);
    ctx.lineTo(rect.x, rect.y + rect.height);
    ctx.lineTo(rect.x, rect.y);
}

function rectPath_ccw(rect) {
    ctx.moveTo(rect.x, rect.y);
    ctx.lineTo(rect.x, rect.y + rect.height);
    ctx.lineTo(rect.x + rect.width, rect.y + rect.height);
    ctx.lineTo(rect.x + rect.width, rect.y);
    ctx.lineTo(rect.x, rect.y);
}

drawRect(redRect);
drawRectClipped(blackRect, blackRectHole);