Basj
Basj

Reputation: 46463

Zoom on a <div> container with CSS transform

In the project bigpicture.js / live demo, I replace every element when zooming (by moving them, and changing their font size). It works.

Now I want to test CSS' nice transform: scale(...); feature instead.

In the following test, I would like to :

The problem is that regardless where we click, the zoom is done the same way. How to zoom on the point that has been clicked instead? (like it already works with my current implementation of bigpicture.js).

var container = document.getElementById("container"), wrapper = document.getElementById("wrapper");
var zoom = 1;

wrapper.onclick = function (e) {
    zoom *= e.ctrlKey ? 1/1.2 : 1.2;    
    container.style.transform = "scale(" + zoom + ")";
}
<style>
#wrapper { position:absolute; top:0px; left:0px; width:1000px; height:600px; background-color: #AAAABB; }
#container { position:absolute; top:100px; left:100px; width:600px; height:400px; background-color: grey; transition-duration: 0.3s; }
#text { position:absolute; top:100px; left:100px; font-size:30px; }
</style>
<div id="wrapper">
  <div id="container">
    <div id="text">Test<div>
  </div>
</div>  

Important: You absolutely need to go Full Page to understand what it is about.

Note: I tried a few things with transform-origin, unsuccessfuly.

Upvotes: 6

Views: 2560

Answers (2)

Basj
Basj

Reputation: 46463

Here is a working snippet: you can try by clicking in the parrot's eye, and then cliking somewhere else: it will always be zoomed with the clicked point as center of the scaling.

enter image description here

var current = {x: 0, y: 0, zoom: 1}, c = document.getElementById('container');
window.onclick = function(e) {
  wx = current.x + e.clientX / current.zoom;
  wy = current.y + e.clientY / current.zoom;
  var coef = e.ctrlKey ? 0.5 : 2;
  current.zoom *= coef;    
  current.x = wx - e.clientX / current.zoom; 
  current.y = wy - e.clientY / current.zoom; 
  c.style.transform = 'scale(' + current.zoom +') translate(' + (-current.x) + 'px,' + (-current.y) + 'px)';
};
html, body { margin: 0; padding: 0; overflow: hidden; min-height: 100%; }
#container { position: absolute; transform-origin: 0 0;}
#item { position: absolute; left:0px; top:0px; }
<div id="container"><div id="item"><img src="https://i.sstatic.net/BRgdq.png"></img></div></div>

Upvotes: 0

vp_arth
vp_arth

Reputation: 14982

You need also to apply out your current zoom to screen coords:

var container = document.getElementById("container"), wrapper = document.getElementById("wrapper"), marker = document.getElementById("marker");
var zoom = 1;

wrapper.onclick = function (e) {
    var x = e.clientX - container.getBoundingClientRect().left;
    var y = e.clientY - container.getBoundingClientRect().top;
    console.log(x,y)
    x /= zoom;
    y /= zoom;
    zoom *= e.ctrlKey ? 1/1.2 : 1.2;
    container.style.transform = "scale(" + zoom + ")";
    container.style.transformOrigin = x+"px "+y+"px";
    marker.style.top = (y-2)+'px';
    marker.style.left = (x-2)+'px';
}
<style>
#wrapper { position:absolute; top:0px; left:0px; width:1000px; height:600px; background-color: #AAAABB; }
#container { position:absolute; top:100px; left:100px; width:600px; height:400px; background-color: grey; transition-duration: 0.3s; }
#text { position:absolute; top:100px; left:100px; font-size:30px; }
#marker { position:absolute; width:4px; height:4px; background-color:red; }
</style>
<div id="wrapper">
  <div id="container">
    <div id="marker"></div>
    <div id="text">Test<div>
  </div>
</div>  

Upvotes: 2

Related Questions