<canvas></canvas>
body {
    margin: 0;
    overflow: hidden;
}

canvas {
    image-rendering: pixelated;
}
const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');

const mouse = {
    position: {
        x: null,
        y: null
    },
    pressed: {
        x: null,
        y: null
    },
    isDown: false
};
const rects = [];

const update = (time) => {
    context.clearRect(0, 0, canvas.width, canvas.height);
    
    context.save();
    context.translate(0.5, 0.5);
    
    for (const rect of rects) {
        context.strokeRect(...rect);
    }
    
    if (mouse.isDown) {
        context.beginPath();
        context.arc(mouse.pressed.x, mouse.pressed.y, 2, 0, Math.PI * 2);
        context.closePath();
        context.fill();
        
        if (mouse.position.x !== null && mouse.position.y !== null) {
            context.beginPath();
            context.arc(mouse.position.x, mouse.position.y, 2, 0, Math.PI * 2);
            context.closePath();
            context.fill();
            
            context.save();
            context.setLineDash([10, 10]);
            context.strokeRect(
                mouse.pressed.x,
                mouse.pressed.y,
                mouse.position.x - mouse.pressed.x,
                mouse.position.y - mouse.pressed.y
            );
            context.restore();
        }
    }
    
    context.restore();
    
    requestAnimationFrame(update);
};

const resize = () => {
    [canvas.width, canvas.height] = [innerWidth, innerHeight];
};

const init = () => {
    canvas.addEventListener('mousedown', event => {
        [mouse.pressed.x, mouse.pressed.y] = [event.offsetX, event.offsetY];
        mouse.isDown = true;
    });
    
    canvas.addEventListener('mousemove', event => {
        [mouse.position.x, mouse.position.y] = [event.offsetX, event.offsetY];
    });
    
    canvas.addEventListener('mouseup', () => {
        if (mouse.position.x !== null && mouse.position.y !== null) {
            rects.push([
                mouse.pressed.x,
                mouse.pressed.y,
                mouse.position.x - mouse.pressed.x,
                mouse.position.y - mouse.pressed.y
            ]);
        }
        
        [mouse.pressed.x, mouse.pressed.y] = [null, null];
        [mouse.position.x, mouse.position.y] = [null, null];
        mouse.isDown = false;
    });
    
    resize();
    
    requestAnimationFrame(update);
};

window.addEventListener('load', init);
window.addEventListener('resize', resize);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.