Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Canvas: Animate bezier curve drawing

im trying to make a line that crossing the canvas from left to right. im still in early stage to achieve that، to do that im using the following function to do the step by step animation

timer = window.setInterval(draw_line, 30);

my drawing function is like this

function draw_line()
    {
        context.fillStyle = "#000";
        context.fillRect(0, 0, canv.width, canv.height);

            context.beginPath();
        context.lineWidth = 2;
        context.strokeStyle = '#fff';

            //Where p1, p2, cp1, cp2 are point objects that has x & y values already defined    
        context.moveTo(p1.x, p1.y);
        context.bezierCurveTo(cp1.x,cp1.y,cp2.x,cp2.y,p2.x,p2.y);
        context.stroke();
        context.closePath();

            // now i have to move p1, p2 ,cp1,cp2
            // now here is my problem
    }

i understand that i need to move p1.x+= a random number; and also the same for cp1 and cp2, but what about p2 the End point it should follow the line same track ! how can i achieve that ?

Thank you

like image 723
trrrrrrm Avatar asked Oct 07 '22 01:10

trrrrrrm


1 Answers

Edited answer

With your clarification, I think I can answer this appropriately now.

In order to have the end point follow the path the start point took through the canvas, you have to store the historical values. In this example, http://jsfiddle.net/mobidevelop/bGgHQ/, I use mouse movements to fill a buffer of the last 16 positions, then use that to form a bezier curve through the points by iterating over the RingBuffer.

function RingBuffer(length) {
    this.length = length;
    this.pointer = 0;
    this.buffer = [];
}
RingBuffer.prototype.get = function(index) {
    if (index < 0) {
        index += this.length;        
    }
    return this.buffer[index];
}
RingBuffer.prototype.push = function(value) {
    this.buffer[this.pointer] = value;
    this.pointer = (this.length + this.pointer +1) % this.length;    
}

var c = document.getElementById("myCanvas");
var context =c.getContext("2d");

timer = window.setInterval(draw_line, 30);
function Point(x,y) {
    this.x = x;
    this.y = y;
}
Point.prototype.translateX = function(x) {
    return this.x += x;
};
Point.prototype.translateY = function(y) {
    return this.y += y;
};

function draw_line()
{
    context.fillStyle = "#000";
    context.fillRect(0, 0, c.width, c.height);

    var pointer = history.pointer;
    context.beginPath();
    context.lineWidth = 2;
    context.strokeStyle = '#F00';     
    for (iteration = 0, count = 15; iteration < count; iteration += 3) {
        var p1 = history.get(--pointer);
        var p2 = history.get(--pointer);
        var p3 = history.get(--pointer);
        var p4 = history.get(--pointer);        

        if (p1 && p2 && p3 && p4) {

            context.moveTo(p1.x, p1.y);
            context.bezierCurveTo(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);

        }
        pointer++;
    }
    context.stroke();
    context.closePath();    

}

var history = new RingBuffer(16);
var lastGrab = new Date();
c.addEventListener('mousemove', function() {
    now = new Date();
    if (now - lastGrab > 15) {
        history.push(new Point(event.clientX - c.offsetLeft, event.clientY - c.offsetTop)); 
        lastGrab = now;
    }    
});​

Previous answer left below, for historical purposes.

I am not sure I completely understand what you are trying to achieve, but I think all you need to do is translate all of your points by the same value. This will result in the line traversing the canvas keeping the same shape. something like this:

JSFiddle

var c = document.getElementById("myCanvas");
var context =c.getContext("2d");

timer = window.setInterval(draw_line, 30);
function Point(x,y) {
    this.x = x;
    this.y = y;
}
Point.prototype.translateX = function(x) {
    return this.x += x;
};
Point.prototype.translateY = function(y) {
    return this.y += y;
};

var p1 = new Point(0,0);
var p2 = new Point(100,100);
var cp1 = new Point(15,45);
var cp2 = new Point(85,45);

function draw_line()
{
    context.fillStyle = "#000";
    context.fillRect(0, 0, c.width, c.height);

    context.beginPath();
    context.lineWidth = 2;
    context.strokeStyle = '#fff';

        //Where p1, p2, cp1, cp2 are point objects that has x & y values already defined    
    context.moveTo(p1.x, p1.y);
    context.bezierCurveTo(cp1.x,cp1.y,cp2.x,cp2.y,p2.x,p2.y);
    context.stroke();
    context.closePath();

    p1.translateX(1);
    p2.translateX(1);
    cp1.translateX(1);
    cp2.translateX(1);

    if (p1.x > 300) {
        p1.translateX(-400);
        p2.translateX(-400);
        cp1.translateX(-400);
        cp2.translateX(-400);        
    }
}

Unless I am misunderstanding the goal...

like image 113
nEx.Software Avatar answered Oct 13 '22 10:10

nEx.Software