Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
499 views
in Technique[技术] by (71.8m points)

javascript - Drawing semi-transparent lines on mouse movement in HTML5 canvas

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!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem is that you are drawing the whole path again and again:

function mouseMove(e) {
    ...
    ctx.stroke(); // Draws whole path which begins where mouseDown happened.
}

You have to draw only the new segment of the path (http://jsfiddle.net/jF9a6/). And then ... you have the problem with the 15px width of the line.

So how to solve this? We have to draw the line at once as you did, but avoid painting on top of existing lines. Here is the code: http://jsfiddle.net/yfDdC/

The biggest change is the paths array. It contains yeah, paths :-) A path is an array of points stored in mouseDown and mouseMove functions. New path is created in mouseDown function:

paths.push([pos]); // Add new path, the first point is current pos.

In the mouseMove you add current mouse position to the last path in paths array and refreshs the image.

paths[paths.length-1].push(pos); // Append point tu current path.
refresh();

The refresh() function clears the whole canvas, draws the cat again and draws every path.

function refresh() {
    // Clear canvas and draw the cat.
    ctx.clearRect(0, 0, ctx.width, ctx.height);
    if (globImg)
        ctx.drawImage(globImg, 0, 0);

    for (var i=0; i<paths.length; ++i) {
        var path = paths[i];

        if (path.length<1)
            continue; // Need at least two points to draw a line.

        ctx.beginPath();
        ctx.moveTo(path[0].x, path[0].y);
        ... 
        for (var j=1; j<path.length; ++j)
            ctx.lineTo(path[j].x, path[j].y);
        ctx.stroke();

    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...