1

Chrome and Firefox handle the following code fine when rendered at 100%.

<!DOCTYPE html>
<html>
    <head>
        <script type="application/x-javascript">
            function draw() {
                var canvas = document.getElementById("canvas");
                if (canvas.getContext) {
                    var ctx = canvas.getContext("2d");
                    ctx.beginPath();
                    ctx.arc(50,50,25,0,2*Math.PI);
                    ctx.stroke();
                }
            }
        </script>
    </head>
    <body onload="draw();">
        <canvas id="canvas" width="100" height="100">
            <p>This example requires a browser that supports the
                <a href="http://www.w3.org/html/wg/html5/">HTML5</a> 
                &lt;canvas&gt; feature.</p>
        </canvas>
    </body>
</html>

But if someone magnifies my page a little, the canvas is sampled, not repainted. It's only a little ugly at 150%, but by the time the viewer reaches 300%, it will look very ugly:

enter image description here

How do I rewrite the code above so that the circle is repainted at the new magnification, not resampled?

This answer leads me to believe that it can be easily done. My attempt

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">
            html, body {
                width:  100%;
                height: 100%;
                margin: 0px;
            }
        </style>

        <script type="application/x-javascript">
            function draw() {
                var canvas = document.getElementById("canvas");
                if (canvas.getContext) {
                    var ctx = canvas.getContext("2d");

                    ctx.canvas.width  = window.innerWidth;
                    ctx.canvas.height = window.innerHeight;

                    ctx.beginPath();
                    ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2,
                            ctx.canvas.height/4,0,2*Math.PI);
                    ctx.stroke();
                }
            }
        </script>
    </head>
    <body onload="draw();">
        <canvas id="canvas">
            <p>This example requires a browser that supports the
                <a href="http://www.w3.org/html/wg/html5/">HTML5</a> 
                &lt;canvas&gt; feature.</p>
        </canvas>
    </body>
</html>

is no good. The circle is still resampled when the user magnifies. Can you do better?

(Chrome and Firefox behave differently when one magnifies. The effect I'm aiming for is for the circle to stay put with its center in the middle of the canvas and its radius a quarter of the window's height.)

Community
  • 1
  • 1
Calaf
  • 8,037
  • 8
  • 46
  • 96
  • Sounds like you are trying to [catch a browser zoom event](http://stackoverflow.com/questions/995914/catch-browsers-zoom-event-in-javascript). I don't think there is a reliable way to do this at present. – Andrew Johnston Nov 27 '14 at 16:59
  • @AndrewJohnston You may be right for the first half of my question. My point in the second half is that if the circle is already magnified within the current canvas, the user will hopefully have no need to magnify manually. – Calaf Nov 27 '14 at 17:56

1 Answers1

0

Try doing the onload combined with the window resize event to redraw the canvas (zooming triggers the resize event):

window.addEventListener('resize', draw);

CANVAS REDRAWING

Example: http://jsfiddle.net/ksvyndwp/

function draw() {
                var canvas = document.getElementById("canvas");
                if (canvas.getContext) {
                    var ctx = canvas.getContext("2d");

                    ctx.canvas.width  = window.innerWidth;
                    ctx.canvas.height = window.innerHeight;

                    ctx.beginPath();
                    ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2,
                            ctx.canvas.height/4,0,2*Math.PI);
                    ctx.stroke();
                }
            }

draw();
window.addEventListener('resize', draw);
html, body {
                width:  100%;
                height: 100%;
                margin: 0px;
            }
<canvas id="canvas">
            <p>This example requires a browser that supports the
                <a href="http://www.w3.org/html/wg/html5/">HTML5</a> 
                &lt;canvas&gt; feature.</p>
        </canvas>

If you're still worried about pixelization at higher zoom levels, I'm afraid there's nothing you can do about it directly on the canvas, because canvas' pixels scale with the window, and although you enter the sub-pixel rendering stage, there's nothing you can do to make it look better.


CSS SCALING

However, if you don't want to do it purely inside the canvas, you can do a simple CSS transformation that will make your circle look correctly on all zoom levels. Setting the width and the height to 100% will keep the canvas (as in canvas, the DOM element; not the actual canvas.width and canvas.height) the size of the window, so it's basically "immune" to zooming.

See it here (actually works much better when zooming the jsfiddle: http://jsfiddle.net/406h7xm0/ than the Stack Overflow iframe):

function draw() {
                var canvas = document.getElementById("canvas");
                if (canvas.getContext) {
                    var ctx = canvas.getContext("2d");

                    ctx.canvas.width  = window.innerWidth;
                    ctx.canvas.height = window.innerHeight;

                    ctx.beginPath();
                    ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2,
                            ctx.canvas.height/4,0,2*Math.PI);
                    ctx.stroke();
                }
  console.log(window.innerWidth);
            }

draw();
html, body {
                width:  100%;
                height: 100%;
                margin: 0px;
            }

canvas {
  width: 100%;
  height: 100%;
}
<canvas id="canvas"></canvas>

The final solution of what you're trying to do probably lies somewhere between the two approaches I've shown you.

Shomz
  • 36,161
  • 3
  • 52
  • 81