Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Finally solved it:</p> <p><div class="snippet" data-lang="js" data-hide="false" data-console="false" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>var zoomIntensity = 0.2; var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); var width = 600; var height = 200; var scale = 1; var originx = 0; var originy = 0; var visibleWidth = width; var visibleHeight = height; function draw(){ // Clear screen to white. context.fillStyle = "white"; context.fillRect(originx,originy,800/scale,600/scale); // Draw the black square. context.fillStyle = "black"; context.fillRect(50,50,100,100); } // Draw loop at 60FPS. setInterval(draw, 1000/60); canvas.onmousewheel = function (event){ event.preventDefault(); // Get mouse offset. var mousex = event.clientX - canvas.offsetLeft; var mousey = event.clientY - canvas.offsetTop; // Normalize wheel to +1 or -1. var wheel = event.wheelDelta/120; // Compute zoom factor. var zoom = Math.exp(wheel*zoomIntensity); // Translate so the visible origin is at the context's origin. context.translate(originx, originy); // Compute the new visible origin. Originally the mouse is at a // distance mouse/scale from the corner, we want the point under // the mouse to remain in the same place after the zoom, but this // is at mouse/new_scale away from the corner. Therefore we need to // shift the origin (coordinates of the corner) to account for this. originx -= mousex/(scale*zoom) - mousex/scale; originy -= mousey/(scale*zoom) - mousey/scale; // Scale it (centered around the origin due to the trasnslate above). context.scale(zoom, zoom); // Offset the visible origin to it's proper position. context.translate(-originx, -originy); // Update scale and others. scale *= zoom; visibleWidth = width / scale; visibleHeight = height / scale; }</code></pre> <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;canvas id="canvas" width="600" height="200"&gt;&lt;/canvas&gt;</code></pre> </div> </div> </p> <p>The key, as @Tatarize pointed out, is to compute the axis position such that the zoom point (mouse pointer) remains in the same place after the zoom. </p> <p>Originally the mouse is at a distance <code>mouse/scale</code> from the corner, we want the point under the mouse to remain in the same place after the zoom, but this is at <code>mouse/new_scale</code> away from the corner. Therefore we need to shift the <code>origin</code> (coordinates of the corner) to account for this.</p> <pre><code>originx -= mousex/(scale*zoom) - mousex/scale; originy -= mousey/(scale*zoom) - mousey/scale; scale *= zomm </code></pre> <p>The remaining code then needs to apply the scaling and translate to the draw context so it's origin coincides with the canvas corner.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload