tags:

views:

21

answers:

2

I'm running into a problem with the HTML5 Canvas tag and adjusting the scale several times. After zooming twice, the canvas only uses a fraction of the available canvas height & width, even though I'm adjusting for the zoom level.

<html>
<head>
<script>

var ctx;
var nScale = 1.00;

function pageLoad() {
    ctx=document.getElementById('cnvUni').getContext('2d');

    // canvas on page load is 500x500
    drawGrid(); // 5 boxes across & 5 down

    zoom(0.5);  // canvas should be now zoomed out to 1000x1000
    drawGrid(); // 10 boxes across & 10 down

    zoom(0.5);  // effective zoom is now 0.25 = 2000x2000
    drawGrid(); // should be 20 boxes across & 20 down

    // NOTE: At this point, the grid is drawing boxes @ 20x20 but only using 1/4 of the 
    // canvas size.
}

function zoom(nZoomLevel) {
    nScale = nZoomLevel * nScale
    ctx.scale(nScale,nScale);
}

function drawGrid() {
    var nWidth, nHeight;
    nWidth = Math.floor(ctx.canvas.width / nScale);
    nHeight = Math.floor(ctx.canvas.height / nScale);   

    var nGridSize = 100;
    var nGridY = 0;
    var nGridX = 0;

    // sets a random colour each time grid is drawn.
    ctx.strokeStyle = 'rgb(' + Math.floor(Math.random()*256) + ',' + Math.floor(Math.random()*256) + ',' + Math.floor(Math.random()*256) + ')';

    for (nGridY=0;nGridY < nHeight;nGridY+=nGridSize) {

    for (nGridX=0;nGridX < nWidth;nGridX+=nGridSize) {
        // draw the box;
        ctx.strokeRect(nGridX, nGridY, nGridSize, nGridSize);
    }
    }
}

</script>
</head>
<body onload="pageLoad();">
<canvas id="cnvUni" width="500" height="500">
Canvas doesn't work.
</canvas>
</body>
</html>

If I were to multiply the height & width by 2 when drawing the grid for the last time it'll draw out the entire canvas size, but I can't figure out why that would be required.

What I'm wondering is:

  1. Is there a way to query a canvas context to find out what the scale value (or the calculated height/width) is? Or am I approaching this correctly and keeping track of values myself?

  2. If so, then I assume it must be something with my math that's messing this up; I just can't pinpoint it. I'm sure I'm just too close to this problem and not seeing the issue. Another set of eyes would help.

Any suggestions would be appreciated.

Thanks!

A: 

I've got a version working on http://jsfiddle.net/sBXTn/5/ without using save/restore. This is the code change:

nScale = nZoomLevel * nScale
ctx.scale(nZoomLevel, nZoomLevel);

Previously using ctx.scale(nScale, nScale) meant that when you zoomed by 0.25 (0.5 twice) you were zooming by 0.25 on a context that was 1000x1000. This meant it increased the size to 4000x4000. Using nZoomLevel means you are zooming in relation to the dimensions of the current context.

Castrohenge
Hi Kieranmaine - thanks for the comment; I think, though I'm looking for a way to calculate the scale/height/width without using the save/restore functionality. This is more of trying to figure out the formula more than getting the result.
michaely
I've figured out the problem; my answer is below. Thanks!
michaely
A: 

I was way on the wrong track with this one and I feel silly for it. My math was correct in calculating the effective scale value (1 * 0.5 = 0.5, then scaling it by 0.5 again does = 0.25), but what I was doing was calculating the effective width & height by the original width & height, not the updated width & height.

So if I've scaled the original down to 0.5, the dimensions of the original 500x500 would be 1000x1000. Scaling it further by 0.5, the effective scale is 0.25, but the new width & height should be 4000x4000 (found by scaling 1000 by 0.25 and NOT 500 by 0.25).

Here's the updated code:

var ctx;
var nScale = 1.00;
var nEffWidth, nEffHeight;

function pageLoad() {
    ctx=document.getElementById('cnvUni').getContext('2d');

    nEffWidth = ctx.canvas.width;
    nEffHeight = ctx.canvas.height;

    // canvas on page load is 500x500
    drawGrid(); // 5 boxes across & 5 down

    zoom(0.5);  // canvas should be now zoomed out to 1000x1000
    drawGrid(); // 10 boxes across & 10 down

    zoom(0.5);  // effective zoom is now 0.25 = 4000x4000 based on new scaled width/height
    drawGrid(); // should be 40 boxes across & 40 down


}

function zoom(nZoomLevel) {
    nScale = nZoomLevel * nScale
    nEffHeight = nEffHeight / nScale;
    nEffWidth = nEffWidth / nScale;
    ctx.scale(nScale,nScale);
}

function drawGrid() {

    var nGridSize = 100;
    var nGridY = 0;
    var nGridX = 0;

    // sets a random colour each time grid is drawn.
    ctx.strokeStyle = 'rgb(' + Math.floor(Math.random()*256) + ',' + Math.floor(Math.random()*256) + ',' + Math.floor(Math.random()*256) + ')';

    for (nGridY=0;nGridY < nEffHeight;nGridY+=nGridSize) {

    for (nGridX=0;nGridX < nEffWidth;nGridX+=nGridSize) {
        // draw the box;
        ctx.strokeRect(nGridX, nGridY, nGridSize, nGridSize);
    }
    }
}

</script>
</head>
<body onload="pageLoad();">
<canvas id="cnvUni" width="500" height="500">
Canvas doesn't work.
</canvas>
</body>
</html>

Thanks for everyone who took a peek!

michaely