MichaelAngelo
MichaelAngelo

Reputation: 375

drawing canvas works as long i use it one time

I am drawing a canvas and rotating it based on a value, it works if i use the canvas one time on a page.

If i add it the second time to the page, only the last one gets drawn, i cant find the error in my code and i dont get a js error.

i think the problem is in the next function:

function animate(){ 

function drawnumbers()
{context.save(); 
context.fillStyle = "#000000"; 
context.translate(73,0); 
context.font="10px Orbitron"; 
context.textAlign = "center"; 
context.rotate(((i*(180/min)))*Math.PI/180); 
context.fillText(data.values[i].amount,0,3); 
context.restore(); 
}; 
if (d < defer){ 
context.clearRect(0,0,400,400); 
d++; 

context.save(); 
var ang = ((((d-minn)*(180/angle)))*(Math.PI/180)); 
context.translate(38,39); 
context.scale(.8,.8); 
base_image = new Image(); 

base_image.src = 'http://oi44.tinypic.com/2hfkx8p.jpg'; 
context.translate(base_image.width/2, base_image.height/2); 
context.rotate(ang ); 
context.drawImage(base_image, -base_image.width/2, -base_image.height/2); 
context.restore(); 

context.save();
context.beginPath(); 
context.arc(100,100,64,1*Math.PI,2*Math.PI, false); 
context.lineWidth = .4; 
context.strokeStyle="#00A1DE"; 
context.globalAlpha = 0.7; 
context.stroke(); 
context.restore(); 

context.save(); 
context.translate(100,100); 
context.rotate(Math.PI/180); 
context.strokeStyle = "#00A1DE"; 
context.lineWidth = .7; 
for (var i=0;i < data.values.length; i++){ 
context.beginPath(); 
context.moveTo(62,0); 
context.lineTo(67,0); 
context.stroke(); 
context.globalAlpha = 0.7; 
drawnumbers(); 
context.rotate((182/(min))*(-Math.PI/180)); 
} 
context.restore(); 

context.fillStyle="white"; 
context.fillRect(38,101,123,75); 

context.save(); 
context.fillStyle = "#00a1de"; 
context.font = "22px Orbitron"; 
context.textAlign = "center"; 
context.fillText(defer, 100, 90); 
context.restore(); 

context.save(); 
context.fillStyle = "#000000"; 
context.font = "10px arial"; 
context.textAlign = "center"; 
context.fillText(eenheid, 100, 115); 
context.restore(); 

} 
else 
{ 
clearTimeout(t); 
}; 
t=setTimeout("animate()",30-d); 
}; 

check example to better understand:

http://jsbin.com/ogEgURu/1/

I had it in a function but it remains the same problem so i think something is wrong with my code.

Can anyone see the problem i am not seeing ?

Upvotes: 0

Views: 158

Answers (1)

GameAlchemist
GameAlchemist

Reputation: 19294

Your code is way too complex, especially since there is no good reason for this complexity.
Copying a big (>200) lines block of code to duplicate a functionality is error-prone.
You'll be able to see easily the issue once you refactored your code.
Just a few hints :

  • Very easy one : beautify the code.
  • No redundancy : If a code lies here twice or more, make a function and factorize.
  • Break down the code into smaller parts. For example : drawText(context, text, x,y, font ) (to print eenheid and defer), drawNumbers(context), drawRotatingImage(context, angle), ...
  • use closePath() each time you beginPath();
  • load once the image when page loads, and wait for it to be loaded before animating.
  • do not define a function in a loop (drawnumbers).
  • use a single object to store the several parameters (context, angle, ...), or even switch to an object oriented style.
  • have only one animate() loop, that will call several draw(...) functions if need be.

after all this, your code will look much simpler, and the bug should vanish very quickly.

I did this work (partially), in this fiddle : http://jsfiddle.net/gamealchemist/ztczK/1/ (edited)

The code looks like :

// parameters : settings for one gauge display
var parameters1 = {
    data: data,
    defer: '520',
    context: context,
    left: 38,
    top: 30,
    d: 0,
    angle: 0,
    scale: 0.8,
    //... whatever parameter here
};
var parameters2 = ... ;

split the draw into many functions so it's much simpler to understand :

// draws a gauge
function drawGauge(param) {
    preDraw(param);
    drawBaseImage(param);
    drawArc(param);
    drawTheNumbers(param);
    writeDefer(param);
    writeEenheid(param);
    postDraw(param);
}

// translate and scales context, and updates some values for the gauge
function preDraw(param) {
    var minn = param.data.values[param.data.values.length - 1].amount;
    var maxn = data.values[0].amount;
    var angle = maxn - minn;
    var d = param.d;
    param.ang = ((((d - minn) * (180 / angle))) * (Math.PI / 180));
    var ctx = param.context;
    ctx.save();
    ctx.translate(param.left, param.top);
    ctx.scale(param.scale, param.scale);
    context.fillStyle = "white";
    context.fillRect(0, 60, 123, 75);
}

// restore context
function postDraw(param) {
    var ctx = param.context;
    ctx.restore();
    param.d++;
}

function drawBaseImage(param) {
    var ctx = param.context;
    var ang = param.ang;
    ctx.save();
    ctx.translate(base_image.width / 2, base_image.height / 2);
    ctx.rotate(ang);
    ctx.drawImage(base_image, -base_image.width / 2, -base_image.height / 2);
    ctx.restore();
}

function drawArc(param) {
    var ctx = param.context;
    ctx.save();
    ctx.beginPath();
    ctx.arc(base_image.width / 2, base_image.height / 2, 64, 1 * Math.PI, 2 * Math.PI, false);
    ctx.lineWidth = .4;
    ctx.strokeStyle = "#00A1DE";
    ctx.globalAlpha = 10.7;
    ctx.stroke();
    ctx.restore();
}

function writeDefer(param) {
    var ctx = param.context;
    var defer = param.defer;
    ctx.save();
    ctx.fillStyle = "#00a1de";
    ctx.font = "22px Orbitron";
    ctx.textAlign = "center";
    ctx.fillText(defer, base_image.width / 2, base_image.height / 2);
    ctx.restore();
}

function writeEenheid(param) {
    var ctx = param.context;
    ctx.save();
    ctx.fillStyle = "#000000";
    ctx.font = "10px arial";
    ctx.textAlign = "center";
    ctx.fillText(eenheid, base_image.width / 2, base_image.height / 2 + 20);
    ctx.restore();
}

function drawTheNumbers(param) {
    var ctx = param.context;
    var dataValues = param.data.values;
    var count = dataValues.length;
    ctx.save();
    ctx.translate(base_image.width / 2, base_image.height / 2);
    ctx.rotate(Math.PI / 180);
    ctx.strokeStyle = "#00A1DE";
    ctx.lineWidth = .7;
    ctx.fillStyle = "#000000";
    ctx.font = "10px Orbitron";
    ctx.textAlign = "center";
    ctx.globalAlpha = 0.7;
    for (var i = 0; i < count; i++) {
        ctx.beginPath();
        ctx.moveTo(62, 0);
        ctx.lineTo(67, 0);
        ctx.stroke();
        ctx.closePath();
        ctx.fillText(dataValues[i].amount, 60, 3);
        ctx.rotate(-Math.PI / count);
    }
    context.restore();
}

then animate becomes very simple, even with several gauges :

function animate() {
    context.clearRect(0, 0, canvasWidth, canvasHeight);
    drawGauge(parameters1);
    drawGauge(parameters2);
    setTimeout(animate, 15);
};
base_image.onload = animate();

Upvotes: 2

Related Questions