views:

105

answers:

2

I'm trying to work out how to enlarge all elements on a page, but keep the centre of enlargement in the centre of the window.

Example Page (up and down arrows to resize the image, you can also drag the image around)

On this page, once the image reaches the top or the left side of the window the centre of enlargement changes. It also changes when you move the image. (exactly what you would expect)

I'm thinking I'd need to take a completely different approach to achieve what I want. But I'm not sure what that approach is..

Any ideas?

+3  A: 

This is what I came up, it works as you say except the image will always go to the center after zooming in or out:

$('document').ready(function() {
    zoomimg=$('#zoomimg'); // we store this in a variable since we don't need to traverse the DOM every time -- this is faster

    var viewportWidth = $(window).width();
    var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height(); // this is to work with Opera
    zoomimg.css({'position': 'absolute', 'left': (viewportWidth/2)-(zoomimg.width()/2), 'top' : (viewportHeight/2)-(zoomimg.height()/2)}).draggable();


    $(document).keydown(function(event) {
        event = event || window.event;

        var viewportWidth = $(window).width();
        var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height(); // this is to work with Opera

        if (event.keyCode == 38) {

            width = zoomimg.width();
            height = zoomimg.height();

            zoomimg.width(width*1.2).height(height*1.2);

            var viewportWidth = $(window).width();
            var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height();
            zoomimg.css({'left': (viewportWidth/2)-(zoomimg.width()/2), 'top' : (viewportHeight/2)-(zoomimg.height()/2)});


        } else if (event.keyCode == 40) {

            width = zoomimg.width();
            height = zoomimg.height();

            zoomimg.width(width*0.8).height(height*0.8);

            var viewportWidth = $(window).width();
            var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height();
            zoomimg.css({'left': (viewportWidth/2)-(zoomimg.width()/2), 'top' : (viewportHeight/2)-(zoomimg.height()/2)});

        } else {

            return

        }
    });

});

You should put an ID 'zoomimg' on the tag for it to work, and overflow:hidden on the #container . Also ditch that display:table and display:table-cell they're useless now that we center with Javascript. Also, pressing the down arrow key will cause the container to scroll down, so you should use other keys, as the arrows are reserved by the browser for scrolling the viewport.

stagas
This is amazing! I'm going through the code now trying to get my head around everything.
Acorn
+3  A: 

Well, here's my take.

Only thing is that I ditched the containers you were using. Is that cheating? Seems like they were only there to get the image centered. No need.

This works as expected with no side effects.

Here's a working demo you can test:

http://jsfiddle.net/dEhgV/14/

(You need to click on the pane with the baboon first.)

HTML

<body>

<img src="http://growl.cz.cc/drag/baboon.png" />

</body>

CSS

html, body {
    width: 100%;
    height: 100%;
    overflow: hidden;
}​

jQuery

EDIT: Thanks to @stagas for the reminder to clean up redundancies.

 var $img = $('img');  // Cache the image. Better for performance.

  $img.draggable();


  $img.css({left: ($('body').width() / 2) - ($img.width() / 2)})
      .css({top: ($('body').height() / 2) - ($img.height() / 2)})


  $(document).keydown(function(event) {

      if (event.keyCode == 38) {
          var adjustment = 1.25;
      } else if (event.keyCode == 40)  {
          var adjustment = 0.8;
      } else {
          return;
      }

      var offset = $img.offset();  

      var width = $img.width();
      var height = $img.height();

      var newWidth = width * adjustment;
      var newHeight = height * adjustment;

      var diffWidth = newWidth - width;
      var diffHeight = newHeight - height;

      var hcenter = $('body').width() / 2;
      var vcenter = $('body').height() / 2;

      var leftPercent = (hcenter - offset.left) / width;
      var topPercent = (vcenter - offset.top) / height;

      $img.offset({top: offset.top - (diffHeight * topPercent), left: offset.left - (diffWidth * leftPercent)});

      $img.width(newWidth).height(newHeight);

    });​
patrick dw
Ah, lovely working demo. I actually just worked this out before looking at your example! Right now I'm trying to work out what calculation you'd need to do to keep whatever point on the image that's in the centre of the window in the centre of the window after zooming in or out. So basically to keep track of the centre of enlargement.
Acorn
@Acorn - Ah, I see. I would assume that it is based on the percentage of the image that is off center as to how much of the position should shift left/right or top/bottom. Just a guess though. Is that the direction you're going?
patrick dw
@patrick - That sounds like what I'm going for. The result I'm aiming for is for the image to zoom around the centre of the window rather than the centre of the image.
Acorn
@Acorn - Well, I updated my answer (and the jsFiddle) with a partial solution. It seems to work until the image goes off the page. Then it gets off a bit. Hope it helps a little anyway.
patrick dw
@patrick - Great! I was doing something similar, but mine gave me crazy coordinates. I thought you could actually just calculate the new absolute position of the image from the left and top percentage and the new height and width. Why do you think this isn't working? http://jsfiddle.net/dEhgV/7/
Acorn
@Acorn: Try using $(window).width() and $(window).height() instead of $(document) as $(document) uses the entire browsing area dimensions instead of the dimensions of the visible area.
stagas
@stagas - Doesn't seem to help.. http://jsfiddle.net/dEhgV/9/
Acorn
@Acorn - I was getting a little better result in a regular page instead of jsFiddle. In all honesty, I'm not quite grasping your code, but then again, my mind is a little fried right now. :o) I'll have another look, though.
patrick dw
It's quite tricky to always zoom relatively to the centered pixel. I've been trying for some time now...
stagas
@Acorn - Part of the trouble is this line `xr = (cx-width)/width;` (as well as the height version). The value will be the same every time as all the values are constant. `(cx-width)` is effectively the remainder space to the left of the image when the right side of the image is on the center line. And dividing that remainder by the width of the image just tells us how much of the image (or white space) would be visible if we effectively moved the image over by the amount of its width. I think what I had was on the right track, but the calculations became skewed when it went off page.
patrick dw
@patrick - Sorry, that's supposed to be xr = (cx-x)/width; with x being the left position of the image. So basically cx-x to get the distance from the center, and then /width to get it as a percentage of the width. The idea was then to multiply the new width by that percentage to get the new x coordinate. Here's what I was doing with a couple more comments. http://growl.cz.cc/drag/gogobab.html
Acorn
patrick dw
@patrick - Wow, you did it! Fantastic! Now to work out why what you did works, and why what I did doesn't :)
Acorn
@Acorn - Glad it works. You were close. Just the final calculation against the percentage (or something). :o)
patrick dw
That is not working. It doesn't zoom with the centered pixel static.
stagas
@stagas - Works perfectly when I do it. I haven't tested it on many browsers though. What are you using? Are you testing it on a page you created? Or in jsFiddle? http://jsfiddle.net/dEhgV/11/
patrick dw
@patrick: On a new page in Firefox 3.6.3 Windows.
stagas
@patrick: Hmm it works now. Strange! :)
stagas
@stagas - I do think there may be a small issue, actually. If you zoom in and out a lot, the center point does start to shift a little. (Likely because positioning is percentage based, and needs to round sometimes. Solution would probably be to update a stored reference point any time the user drags the image. That could then be used to "recalibrate" the center when zooming. I'll probably do an update sometime today.
patrick dw
@patrick - This is what I came up with this morning building on what you did. It now uses the scroll wheel and uses the mouse position as the centre of enlargement. http://growl.cz.cc/zoom/
Acorn
@Acorn - Looks great! There was a small issue with the center point (see comment above yours), but it is probably not relevant if you're going to use the mouse pointer as the center. Great job! :o)
patrick dw
@Acorn: Just a little bit of clean up, you don't need to use the same code twice, and also added a return false; to stop the default mousewheel behaviour because in my browser it also scrolled down/up the page if the image went too large. http://gist.github.com/419764 . Nice work guys!
stagas
@stagas: Ah fantastic, thanks. Although, I'm curious as to why you have scrollbars. Do you not have `overflow: hidden` set on the body?
Acorn
@Acorn: Yes, the scrollbars are invisible, but still the body expands when the image is rendered too big and mousewheel or up/down keys tell it to scroll anyways. I guess it's Firefox's behaviour. You should probably bind those arrow keys with a return false; also plus you could assign them to move the image around for a better user experience.
stagas
@stagas - Good point. Cleaned up my code too. Thanks for the reminder.
patrick dw
@stagas: Oh, I see what you mean, although I only get that happening with the arrow buttons, not the scroll wheel. I suppose I'll have to just return false then.
Acorn