JavaScript - Image Pan and Zoom Demo

From NoskeWiki
Jump to navigation Jump to search
Demonstration of interface

About

NOTE: This page is a daughter page of: JavaScript


There is a lovely `draggable` label you can apply in HTML5, but doesn't actually do anything really. You need JavaScript with `dragstart` and `dragover` event listeners to actually have an image move. And you'll probably also want to put it inside a containing div of some sort (with or without scroll bars - up to you) so that it's pans nicely within this container. Finally, you might want it to zoom - which can be done using the `mousewheel` event listener, and a little bit of JavaScript to make sure it resizes around the mouse coordinates. Together this gives us the type of `pan` and `zoom` we have come to expect from products like Google Maps.


Notice with the `draggable` keyword, it likes to project a faded version of the image when you drag it. Sadly it's hard to get rid of, but we replaced it with this image here (which you can save as `drag_image.png` and use in code):

Image used for drag

The HTML:

<!doctype html>
<html lang="en">
<head>
  <title>Image Pan and Zoom Demo</title>

  <style>
.image-container {
  position:relative;
  width:700px;
  height:380px;
  overflow:hidden;  /* Most important. */
  background:#000;
  margin:auto;
  border:1px solid #555;
}
.draggable-image {
  position:absolute;  /* Most important. */
}
  </style>

<body>

  <div class="image-container">
    <img class="draggable-image" src="https://upload.wikimedia.org/wikipedia/commons/1/1c/1_The_Opera_House_in_Sydney.jpg"/>
  </div>
  <br>
  <div class="image-container">
    <img class="draggable-image" src="https://upload.wikimedia.org/wikipedia/commons/0/08/American_Fork_Canyon_from_Timpanogos_Cave_entrance.jpg" style="width:380px; height:283px"/>
  </div>

  <script type="text/javascript">

var imgDiv = null;  // Image being dragged and panned.
var prevX;          // Previous x position of mouse (starting with start pos).
var prevY;          // Previous y position of mouse (starting with start pos).

var dragIcon = document.createElement('img');
dragIcon.src = "drag_image.png";


/**
 * Handler for drag event on our draggable images.
 * @param {Event} e Event.
 */
function handleDragStart(e) {
  imgDiv = e.target;
  prevX = event.clientX;
  prevY = event.clientY;
  e.dataTransfer.setDragImage(dragIcon, 0, 0);
}


/**
 * Handler for dragging an image.
 * @param {Event} e Event.
 */
function handleDragOver(e) {
  if (!imgDiv) return;

  x = event.clientX;
  y = event.clientY;
  translateDiv(imgDiv, x - prevX, y - prevY);
  prevX = x;
  prevY = y;
}


/**
 * Handler for zooming an image by mouse wheel scrolling over it.
 * @param {Event} e Event.
 */
function handleMouseWheel(e) {
  if (!e.target || e.target.height == 0 || e.target.width == 0) return;

  imgDiv = e.target;
  var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
  var scaleAmount = 1.0 + (delta / 10.0);
  var maxWidth = 5000;
  var minWidth = 50;
  var relResizePosX = e.layerX / e.target.width;
  var relResizePosY = e.layerY / e.target.height;
  resizeDiv(imgDiv, scaleAmount, maxWidth, minWidth,
            relResizePosX, relResizePosY);
}

/**
 * Move a div tag (where div should be set with position:absolute).
 * @param {Element} e The HTML element to move.
 * @param {number} x The amount to translate the element in x
 *    (positive value moves right, negative value moves left).
 * @param {number} y The amount to translate the element in y
 *    (positive value moves up, negative value moves down).
 */
function translateDiv(div, x, y) {
  div.style.left = (div.offsetLeft + x) + 'px';
  div.style.top = (div.offsetTop + y) + 'px';
}


/**
 * Resizes a div tag about a particular point (scale and translate).
 * @param {Element} e The HTML element to resize.
 * @param {number} scaleAmount The amount to scale the element by
 *    (a value > 1 makes it bigger, a value < 1 makes it smaller).
 * @param {number} maxWidth The maxiumum width of the image in pixels
 *    (it won't scale larger than this).
 * @param {number} minWidth The minimum width of the image in pixels
 *    (it won't scale smaller than this).
 * @param {number} relResizePosX The relative position of the image,
 *    along x, to resize from. A value of 0.5 means it will resize
 *    about the very center in x, and 0, means it resizes from the
 *    left edge.
 * @param {number} relResizePosY The relative position of the image,
 *    along y, to resize from. A value of 0.5 means it will resize
 *    about the very center in y, and 0, means it resizes from the
 *    top edge.
 */
function resizeDiv(div, scaleAmount, maxWidth, minWidth,
                   relResizePosX, relResizePosY) {
  var aspect = div.width / div.height;  // Aspect ratio of this image.
  var oldWidth = div.width;
  var oldHeight = div.height;
  var newWidth = scaleAmount * oldWidth;
  if (newWidth > maxWidth) { newWidth = maxWidth; }
  if (newWidth < minWidth) { newWidth = minWidth; }
  var resizeFract = (newWidth - oldWidth) / oldWidth;

  // Scale:
  div.style.width = newWidth + 'px';
  div.style.height = (newWidth / aspect) + 'px';

  // Translate:
  div.style.left = ((-oldWidth * resizeFract * relResizePosX) + div.offsetLeft) + 'px';
  div.style.top = ((-oldHeight * resizeFract * relResizePosY) + div.offsetTop) + 'px';
}


/**
 * Adds pan and zoom event listeners to all div elements matching this
 * CSS class.
 * @param {string} className Class name to match.
 */
function addPanAndZoomToImagesByClass(className) {
  var dragMeElements = document.getElementsByClassName(className);
  for (var i=0; i<dragMeElements.length; i++) {
    imgDiv = dragMeElements[i];
    imgDiv.addEventListener('dragstart', handleDragStart, false);
    imgDiv.addEventListener('dragover', handleDragOver, false);
    imgDiv.addEventListener("mousewheel", handleMouseWheel, false);
  }
}

addPanAndZoomToImagesByClass('draggable-image');

  </script>

</body>
</html>


Code license
For all of the code on my site... if there are specific instruction or licence comments please leave them in. If you copy my code with minimum modifications to another webpage, or into any code other people will see I would love an acknowledgment to my site.... otherwise, the license for this code is more-or-less WTFPL (do what you want)! If only copying <20 lines, then don't bother. That said - if you'd like to add a web-link to my site www.andrewnoske.com or (better yet) the specific page with code, that's a really sweet gestures! Links to the page may be useful to yourself or your users and helps increase traffic to my site. Hope my code is useful! :)



See Also