Drawing semi-transparent lines on mouse movement in HTML5 canvas

Viewed 3875

I'm trying to let users specify an area by painting over it with a "paint" tool that draws semi-transparent lines on a canvas. Its purpose is specifying a "mask" for an image that will be drawn below on the canvas.

This is what I tried so far:

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

var dragging = false;

drawImage();

$(canvas).mousedown(mouseDown);
$(canvas).mouseup(mouseUp);
$(canvas).mousemove(mouseMove);

function drawImage() {
    var img = new Image();
    img.src = 'http://img2.timeinc.net/health/img/web/2013/03/slides/cat-allergies-400x400.jpg';

    img.onload = function () {
        ctx.drawImage(img, 0, 0);
    };
}

function mouseDown(e) {
    var pos = getCursorPosition(e);

    dragging = true;

    ctx.strokeStyle = 'rgba(0, 100, 0, 0.25)';
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.lineWidth = 15;
    ctx.beginPath();
    ctx.moveTo(pos.x, pos.y);
}

function mouseUp(e) {
    dragging = false;
}

function mouseMove(e) {
    var pos, i;

    if (!dragging) {
        return;
    }

    pos = getCursorPosition(e);

    ctx.lineTo(pos.x, pos.y);
    ctx.stroke();
}

function getCursorPosition(e) {
    return {
        x: e.clientX - canvasPos.left,
        y: e.clientY - canvasPos.top
    };
}

The issue with this example code is that subsequent pixels that are drawn are making the opacity becomes less and less visible. I think it's because the line is 15 pixels wide (but I want it that wide though).

How can I solve this issue?

Thanks!

3 Answers

I agree with Strix. Here you will find an example based on his answer.

    //    
    let mouseDownStartPosition: number | null = null;
    let mouseDownLastPaintedPosition: number | null = null;
    
    const drawRect = (canvas: HTMLCanvasElement, pixelX0 : number, pixelX1: number) => {
        const context: CanvasRenderingContext2D = canvas.getContext('2d')!;

        context.globalAlpha = 0.3;
        context.fillStyle = "#bada55";
        context.fillRect(pixelX0, 0, pixelX1 - pixelX0, context.canvas.height);
        context.globalAlpha = 1.0;
    }

    const onCanvasMouseDown = (e: { clientX: number; }) => {
        const canvas: HTMLCanvasElement = canvasRef.current!;
        let rect = canvas.getBoundingClientRect();
        mouseDownStartPosition = e.clientX - rect.left;
        mouseDownLastPaintedPosition = mouseDownStartPosition;
    }

    const onCanvasMouseMove = (e: { clientX: number; }) => {
        if (mouseDownLastPaintedPosition == null) return;

        const canvas: HTMLCanvasElement = canvasRef.current!;
        let rect = canvas.getBoundingClientRect();
        const mouseCurrentPosition = e.clientX - rect.left;
        drawRect(canvas, Math.min(mouseDownLastPaintedPosition, mouseCurrentPosition), Math.max(mouseDownLastPaintedPosition, mouseCurrentPosition));
        mouseDownLastPaintedPosition = mouseCurrentPosition;
    }

    const onCanvasMouseUp = () => {
        mouseDownStartPosition = null;
        mouseDownLastPaintedPosition = null;
    }
                <MyCanvas
                    ref={canvasRef}
                    onMouseDown={onCanvasMouseDown}
                    onMouseMove={onCanvasMouseMove}
                    onMouseUp={onCanvasMouseUp}
                />

Related