Search code examples
javascripthtmlkineticjskonvajs

Draw smooth Lines on a Canvas


I want to draw a line on a canvas with

context.globalCompositeOperation = 'destination-out';
context.globalAlpha = 0.118;

The result looks like this:

enter image description here

The background if the image is a yellow rectangle. I use a circle to drag and drop it over the image and it will paint the line. As you can see my drawn line is not so smooth. You can see the circles and you do not have a compound line.

I created a JSFiddle here:

console.clear();

var history = new Array();

var imageObj = new Image();
var img = null;

stage = new Konva.Stage({
    container: 'container',
    width: 600,
    height: 400
});
layer = new Konva.Layer();
stage.add(layer);

var rect = new Konva.Rect({
      x: 30,
      y: 30,
      width: 438,
      height: 300,
      fill: 'yellow'
    });
layer.add(rect);

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



var circle = new Konva.Circle({
    x: 0,
    y: 0,
    radius: 40,
    opacity: 0.7,
    fill: '#ff5e0a',
    stroke: '#d95009',
    strokeWidth: 1,
    draggable: true
});
layer.add(circle);


circle.on('dragmove touchmove', function (e) {
    erase(e.evt.clientX, e.evt.clientY, circle.radius(), img.x(), img.y());
});


imageObj.onload = function () {
    canvas.width = imageObj.width;
    canvas.height = imageObj.height;
    context.drawImage(imageObj, 0, 0, imageObj.width, imageObj.height);

    img = new Konva.Image({
        x: 30,
        y: 30,
        image: canvas
    });

    layer.add(img);

    circle.moveToTop();
    layer.draw();
};

imageObj.crossOrigin = "anonymous";
imageObj.src = "https://dl.dropboxusercontent.com/u/47067729/darth-vader.jpg";


function erase(absX, absY, radius, imgX, imgY) {
    var x = 0;
    var y = 0;

    // set pointer
    circle.x(absX);
    circle.y(absY);

    x= absX - imgX;
    y= absY - imgY;

    context.globalCompositeOperation = 'destination-out';
    context.globalAlpha = 0.118;
    context.beginPath();
    context.arc(x, y, radius, 0, 2 * Math.PI);
    context.fill();

    layer.draw();
}

How can I draw more smooth and compound lines where you cannot see each small chunk of the circles?


Solution

  • Assuming your Konva thingie does not provide a readymade solution, you will have to interpolate the touch screen event positions with a constant displacement.

    Something like this:

    circle.on('dragmove touchmove', function (e) {
    
        if (circle.prev_pos) {
            var dx = e.evt.clientX - circle.prev_pos.x;
            var dy = e.evt.clientY - circle.prev_pos.y;
            var dist = Math.max (Math.abs(dx), Math.abs(dy));
            dx = dx / dist;
            dy = dy / dist;
            var x = circle.prev_pos.x;
            var y = circle.prev_pos.y;
            var d;
            for (d = 0 ; d < dist ; d++)
            {
                erase(x, y, circle.radius(), img.x(), img.y());
                x += dx;
                y += dy;
            } 
        }
        circle.prev_pos = { x:e.evt.clientX, y:e.evt.clientY};
    });
    

    See this fiddle.