Fixed point scaling in KineticJS

I'm having problems scaling the container to a fixed point.
In my case, I am trying to scale (enlarge) a scene with a mouse cursor.

Here's how to make a blank canvas: http://phrogz.net/tmp/canvas_zoom_to_cursor.html (as discussed in Zoom Canvas to Mouse Cursor )

I just can't figure out how to apply the same logic when using the KineticJS API.

Code example:

var position = this.stage.getUserPosition(); var scale = Math.max(this.stage.getScale().x + (0.05 * (scaleUp ? 1 : -1)), 0); this.stage.setScale(scale); // Adjust scale to position...? this.stage.draw(); 
+8
javascript html5 kineticjs canvas scaling
source share
4 answers

After many attempts, searching and trying using the @Eric Rowell tooltip and the code posted in the SO question Zoom in (using scale and translation) Finally, I got the zoom in and out of a fixed point using KineticJS .

This is where DEMO works.

And here is the code:

 var ui = { stage: null, scale: 1, zoomFactor: 1.1, origin: { x: 0, y: 0 }, zoom: function(event) { event.preventDefault(); var evt = event.originalEvent, mx = evt.clientX /* - canvas.offsetLeft */, my = evt.clientY /* - canvas.offsetTop */, wheel = evt.wheelDelta / 120; var zoom = (ui.zoomFactor - (evt.wheelDelta < 0 ? 0.2 : 0)); var newscale = ui.scale * zoom; ui.origin.x = mx / ui.scale + ui.origin.x - mx / newscale; ui.origin.y = my / ui.scale + ui.origin.y - my / newscale; ui.stage.setOffset(ui.origin.x, ui.origin.y); ui.stage.setScale(newscale); ui.stage.draw(); ui.scale *= zoom; } }; $(function() { var width = $(document).width() - 2, height = $(document).height() - 5; var stage = ui.stage = new Kinetic.Stage({ container: 'container', width: width, height: height }); var layer = new Kinetic.Layer({ draggable: true }); var rectX = stage.getWidth() / 2 - 50; var rectY = stage.getHeight() / 2 - 25; var box = new Kinetic.Circle({ x: 100, y: 100, radius: 50, fill: '#00D200', stroke: 'black', strokeWidth: 2, }); // add cursor styling box.on('mouseover', function() { document.body.style.cursor = 'pointer'; }); box.on('mouseout', function() { document.body.style.cursor = 'default'; }); layer.add(box); stage.add(layer); $(stage.content).on('mousewheel', ui.zoom); });​ 
+16
source share

You need to compensate for the scene so that its center point is at a fixed point. Here's an example, because the center point of the scene is by default in the upper left corner of the canvas. Say your scene has a width of 600 pixels and a height of 400 pixels, and you want the scene to increase from the center. You will need to do this:

 var stage = new Kinetic.Stage({ container: 'container', width: 600, height: 400, offset: [300, 200] }; 
+3
source share

updated @ juan.facorro demo to scale figure instead of stage

jsFiddle

 var ui = { stage: null, box: null, scale: 1, zoomFactor: 1.1, zoom: function(event) { event.preventDefault(); var evt = event.originalEvent, mx = evt.offsetX, my = evt.offsetY, wheel = evt.wheelDelta / 120; //n or -n var zoom = (ui.zoomFactor - (evt.wheelDelta < 0 ? 0.2 : 0)); var newscale = ui.scale * zoom; var origin = ui.box.getPosition(); origin.x = mx - (mx - origin.x) * zoom; origin.y = my - (my - origin.y) * zoom; ui.box.setPosition(origin.x, origin.y); ui.box.setScale(newscale); ui.stage.draw(); ui.scale *= zoom; } }; $(function() { var width = $(document).width() - 2, height = $(document).height() - 5; var stage = ui.stage = new Kinetic.Stage({ container: 'container', width: width, height: height }); var layer = new Kinetic.Layer(); var rectX = stage.getWidth() / 2 - 50; var rectY = stage.getHeight() / 2 - 25; var box = ui.box = new Kinetic.Circle({ x: 100, y: 100, radius: 50, fill: '#00D200', stroke: 'black', strokeWidth: 2, draggable: true }); // add cursor styling box.on('mouseover', function() { document.body.style.cursor = 'pointer'; }); box.on('mouseout', function() { document.body.style.cursor = 'default'; }); layer.add(box); stage.add(layer); $(stage.content).on('mousewheel', ui.zoom); }); 
+3
source share

The demonstration above only works if the x and y coordinates of the stage are 0. If, for example, the stage is dragged, it will change these coordinates when dragging, so they must be included in the calculation of the offset. This can be achieved by subtracting them from the displacements of the canvas:

jsfiddle

 zoom: function(event) { event.preventDefault(); var evt = event.originalEvent, mx = evt.offsetX - ui.scale.getX(), my = evt.offsetY - ui.scale.getY(), var zoom = (ui.zoomFactor - (evt.wheelDelta < 0 ? 0.2 : 0)); var newscale = ui.scale * zoom; var origin = ui.box.getPosition(); origin.x = mx - (mx - origin.x) * zoom; origin.y = my - (my - origin.y) * zoom; ui.box.setPosition(origin.x, origin.y); ui.box.setScale(newscale); ui.stage.draw(); ui.scale *= zoom; } 
+2
source share

All Articles