Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Using <code>transform</code> to get a <strong>google maps zooming</strong> behavior on a <strong><code>div</code> element</strong> seemed like an interesting idea, so I payed with it a little =)</p> <p>I would use <code>transform-origin</code> (and its sister attributes for browser compatibility) to adjust the zooming to the mouse location on the div that you are scaling. I think this could do what you want. I put some examples on fiddle for illustration:</p> <ul> <li>example 1: <a href="http://jsfiddle.net/mturjak/2R763/">zoom in and out on transform-origin</a></li> <li>example 2: <a href="http://jsfiddle.net/mturjak/d2epQ/">zoom on transform-origin &amp; shift zooming frame with translation</a></li> <li>example 3: <a href="http://jsfiddle.net/mturjak/NthUz/">example 2 + zoom-out limited to original frame borders</a></li> <li>example 4: <a href="http://jsfiddle.net/mturjak/xM3P9/">example 3 + parent frame with hidden overflow</a></li> </ul> <p><strong>Adjusting the <code>transform-origin</code></strong></p> <p>So in the <code>applyTransformations</code> function of yours we could adjust the <code>transform-origin</code> dynamically from the <code>imageX</code> and <code>imageY</code>, if we pass this values from the <code>MouseZoom</code> (mouse listener) function.</p> <pre><code> var orig = t.getTranslateX().toFixed() + "px " + t.getTranslateY().toFixed() + "px"; elem.css("transform-origin", orig); elem.css("-ms-transform-origin", orig); elem.css("-o-transform-origin", orig); elem.css("-moz-transform-origin", orig); elem.css("-webkit-transform-origin", orig); </code></pre> <p>(In this <a href="http://jsfiddle.net/mturjak/NthUz/">first fiddle example</a> I just used your <code>translateX</code> and <code>translateY</code> in <code>Transformations</code> to pass the location of the mouse on the div element - in the second example I renamed it to <code>originX</code> and <code>originY</code> to differentiate from the translation variables.)</p> <p><strong>Calculating the transform origin</strong></p> <p>In your <code>MouseZoom</code> we can calculate origin location simply with <code>imageX/previousScale</code>.</p> <pre><code> MouseZoom.prototype.zoom = function(){ var previousScale = this.current.getScale(); var newScale = previousScale + this.delta/10; if(newScale&lt;1){ newScale = 1; } var ratio = newScale / previousScale; var imageX = this.mouseX - this.offsetLeft; var imageY = this.mouseY - this.offsetTop; var newTx = imageX/previousScale; var newTy = imageY/previousScale; return new Transformations(newTx, newTy, newScale); } </code></pre> <p>So this will work perfectly if you zoom out completely before zooming in on a different position. But to be able to change zoom origin at any zoom level, we can combine the origin and translation functionality.</p> <p><strong>Shifting the zooming frame</strong> (extending my original answer)</p> <p>The transform origin on the image is still calculated the same way but we use a separate translateX and translateY to shift the zooming frame (here I introduced two new variables that help us do the trick - so now we have <code>originX</code>, <code>originY</code>, <code>translateX</code> and <code>translateY</code>).</p> <pre><code> MouseZoom.prototype.zoom = function(){ // current scale var previousScale = this.current.getScale(); // new scale var newScale = previousScale + this.delta/10; // scale limits var maxscale = 20; if(newScale&lt;1){ newScale = 1; } else if(newScale&gt;maxscale){ newScale = maxscale; } // current cursor position on image var imageX = (this.mouseX - this.offsetLeft).toFixed(2); var imageY = (this.mouseY - this.offsetTop).toFixed(2); // previous cursor position on image var prevOrigX = (this.current.getOriginX()*previousScale).toFixed(2); var prevOrigY = (this.current.getOriginY()*previousScale).toFixed(2); // previous zooming frame translate var translateX = this.current.getTranslateX(); var translateY = this.current.getTranslateY(); // set origin to current cursor position var newOrigX = imageX/previousScale; var newOrigY = imageY/previousScale; // move zooming frame to current cursor position if ((Math.abs(imageX-prevOrigX)&gt;1 || Math.abs(imageY-prevOrigY)&gt;1) &amp;&amp; previousScale &lt; maxscale) { translateX = translateX + (imageX-prevOrigX)*(1-1/previousScale); translateY = translateY + (imageY-prevOrigY)*(1-1/previousScale); } // stabilize position by zooming on previous cursor position else if(previousScale != 1 || imageX != prevOrigX &amp;&amp; imageY != prevOrigY) { newOrigX = prevOrigX/previousScale; newOrigY = prevOrigY/previousScale; } return new Transformations(newOrigX, newOrigY, translateX, translateY, newScale); } </code></pre> <p>For this example I adjusted the your original script a little more and added the <a href="http://jsfiddle.net/mturjak/d2epQ/">second fiddle example</a>.</p> <p>Now we zoom in and out on the mouse cursor from any zoom level. But because of the frame shift we end up moving the original div around ("measuring the earth") ... which looks funny if you work with an object of limited width and hight (zoom-in at one end, zoom-out at another end, and we moved forward like an inchworm).</p> <p><strong>Avoiding the "inchworm" effect</strong></p> <p>To avoid this you could for example add limitations so that the left image border can not move to the right of its original x coordinate, the top image border can not move lower than its original y position, and so on for the other two borders. But then the zoom/out will not be completely bound to the cursor, but also by the edge of the image (you will notice the image slide into place) in <a href="http://jsfiddle.net/mturjak/NthUz/">example 3</a>.</p> <pre><code> if(this.delta &lt;= 0){ var width = 500; // image width var height = 350; // image height if(translateX+newOrigX+(width - newOrigX)*newScale &lt;= width){ translateX = 0; newOrigX = width; } else if (translateX+newOrigX*(1-newScale) &gt;= 0){ translateX = 0; newOrigX = 0; } if(translateY+newOrigY+(height - newOrigY)*newScale &lt;= height){ translateY = 0; newOrigY = height; } else if (translateY+newOrigY*(1-newScale) &gt;= 0){ translateY = 0; newOrigY = 0; } } </code></pre> <p>Another (a bit crappy) option would be to simply reset the frame translate when you zoom out completely (scale==1).</p> <p>However, you would not have this problem if you will be dealing with continuous elements (left and right edge and top and bottom edge bound together) or just with extremely big elements.</p> <p>To finish everything off with a nice touch - we can add a parent frame with hidden overflow around our scaling object. So the image area does not change with zooming. See <a href="http://jsfiddle.net/mturjak/xM3P9/">jsfiddle example 4</a>.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

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