/* * MojoZoom 0.1.4 - JavaScript Image Zoom * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/ * Licensed under the MPL License [http://www.nihilogic.dk/licenses/mpl-license.txt] */ var MojoZoom = (function() { var $ = function(id) {return document.getElementById(id);}; var dc = function(tag) {return document.createElement(tag);}; var defaultWidth = 256; var defaultHeight = 256; function addEvent(element, ev, handler) { var doHandler = function(e) { return handler(e||window.event); } if (element.addEventListener) { element.addEventListener(ev, doHandler, false); } else if (element.attachEvent) { element.attachEvent("on" + ev, doHandler); } } function getElementPos(element) { var x = element.offsetLeft; var y = element.offsetTop; var parent = element.offsetParent; while (parent) { x += parent.offsetLeft; y += parent.offsetTop; parent = parent.offsetParent; } return { x : x, y : y } } function getEventMousePos(element, e) { var scrollX = document.body.scrollLeft || document.documentElement.scrollLeft; var scrollY = document.body.scrollTop || document.documentElement.scrollTop; if (e.currentTarget) { var pos = getElementPos(element); return { x : e.clientX - pos.x + scrollX, y : e.clientY - pos.y + scrollY } } return { x : e.offsetX, y : e.offsetY } } function makeZoomable(img, zoomSrc, zoomImgCtr, zoomWidth, zoomHeight, alwaysShow) { // make sure the image is loaded, if not then add an onload event and return if (!img.complete && !img.__mojoZoomQueued) { addEvent(img, "load", function() { img.__mojoZoomQueued = true; setTimeout(function() { makeZoomable(img, zoomSrc, zoomImgCtr, zoomWidth, zoomHeight, alwaysShow); }, 1); }); return; } img.__mojoZoomQueued = false; // Wrap everything in a timeout. // this fixes a problem where, if makeZoomable is called a second time after changing the src, // FF would not have figured out the new offsetHeight of the image yet. A small timeout helps though it's rather hackish. setTimeout(function(){ // sorry var isIE = !!document.all && !!window.attachEvent && !window.opera; var w = img.offsetWidth; var h = img.offsetHeight; var oldParent = img.parentNode; if (oldParent.nodeName != "A") { var linkParent = dc("a"); linkParent.setAttribute("href", zoomSrc); oldParent.replaceChild(linkParent, img); linkParent.appendChild(img); } else { var linkParent = oldParent; } linkParent.style.position = "relative"; linkParent.style.display = "block"; linkParent.style.width = w+"px"; linkParent.style.height = h+"px"; var imgLeft = img.offsetLeft; var imgTop = img.offsetTop; var zoom = dc("div"); zoom.className = "mojozoom_marker"; var zoomImg = dc("img"); zoomImg.className = "mojozoom_img"; zoomImg.style.position = "absolute"; zoomImg.style.left = "-9999px"; zoomImg.style.top = "-9999px"; document.body.appendChild(zoomImg); var parent = img.parentNode; var ctr = dc("div"); with (ctr.style) { position = "absolute"; left = imgLeft+"px"; top = imgTop+"px"; width = w+"px"; height = h+"px"; overflow = "hidden"; display = "none"; } ctr.appendChild(zoom); parent.appendChild(ctr); var zoomInput = parent; // clear old overlay if (img.__mojoZoomOverlay) parent.removeChild(img.__mojoZoomOverlay); img.__mojoZoomOverlay = ctr; // clear old high-res image if (img.__mojoZoomImage && img.__mojoZoomImage.parentNode) img.__mojoZoomImage.parentNode.removeChild(img.__mojoZoomImage); img.__mojoZoomImage = zoomImg; var useDefaultCtr = false; if (!zoomImgCtr) { zoomImgCtr = dc("div"); zoomImgCtr.className = "mojozoom_imgctr"; var imgPos = getElementPos(img); zoomImgCtr.style.left = w + imgPos.x + "px"; zoomImgCtr.style.top = imgPos.y + "px"; zoomImgCtr.style.width = (zoomWidth ? zoomWidth : defaultWidth) +"px"; zoomImgCtr.style.height = (zoomHeight ? zoomHeight : defaultHeight) +"px"; document.body.appendChild(zoomImgCtr); useDefaultCtr = true; } zoomImgCtr.style.overflow = "hidden"; if (!alwaysShow) { zoomImgCtr.style.visibility = "hidden"; } addEvent(zoomImg, "load", function() { // bail out if img has been removed from dom if (!zoomImg.parentNode) return; var zoomWidth = zoomImg.offsetWidth; var zoomHeight = zoomImg.offsetHeight; var ctrWidth = zoomImgCtr.offsetWidth; var ctrHeight = zoomImgCtr.offsetHeight; var ratioW = zoomWidth / w; var ratioH = zoomHeight / h; var markerWidth = Math.round(ctrWidth / ratioW); var markerHeight = Math.round(ctrHeight / ratioH); document.body.removeChild(zoomImg); zoomImgCtr.appendChild(zoomImg); var zoomFill = dc("div"); zoomFill.className = "mojozoom_fill"; zoom.appendChild(zoomFill); var zoomBorder = dc("div"); zoomBorder.className = "mojozoom_border"; zoom.appendChild(zoomBorder); zoom.style.width = markerWidth+"px"; zoom.style.height = markerHeight+"px"; if (alwaysShow) { zoom.style.left = "0px"; zoom.style.top = "0px"; zoomImg.style.left = "0px"; zoomImg.style.top = "0px"; } var isInImage = false; if (!alwaysShow) { addEvent(zoomInput, "mouseout", function(e) { var target = e.target || e.srcElement; if (!target) return; if (target.nodeName != "DIV") return; var relTarget = e.relatedTarget || e.toElement; if (!relTarget) return; while (relTarget != target && relTarget.nodeName != "BODY" && relTarget.parentNode) { relTarget = relTarget.parentNode; } if (relTarget != target) { isInImage = false; ctr.style.display = "none"; zoomImgCtr.style.visibility = "hidden"; } } ); // a bit of a hack, mouseout is sometimes not caught if moving mouse really fast addEvent(document.body, "mouseover", function(e) { if (isInImage && !(e.toElement == zoomBorder || e.target == zoomBorder)) { ctr.style.display = "none"; zoomImgCtr.style.visibility = "hidden"; isInImage = false; } } ); } addEvent(zoomInput, "mousemove", function(e) { isInImage = true; var imgPos = getElementPos(img); if (useDefaultCtr) { zoomImgCtr.style.left = w + imgPos.x + "px"; zoomImgCtr.style.top = imgPos.y + "px"; } ctr.style.display = "block"; zoomImgCtr.style.visibility = "visible"; var pos = getEventMousePos(zoomInput, e); if (e.srcElement && isIE) { if (e.srcElement == zoom) return; if (e.srcElement != zoomInput) { var zoomImgPos = getElementPos(e.srcElement); pos.x -= (imgPos.x - zoomImgPos.x); pos.y -= (imgPos.y - zoomImgPos.y); } } var x = markerWidth/2; var y = markerHeight/2; if (!isIE) { pos.x -= imgLeft; pos.y -= imgTop; } if (pos.x < x) pos.x = x; if (pos.x > w-x) pos.x = w-x; if (pos.y < y) pos.y = y; if (pos.y > h-y) pos.y = h-y; var left = ((pos.x - x)|0); var top = ((pos.y - y)|0); zoom.style.left = left + "px"; zoom.style.top = top + "px"; zoomImg.style.left = -((pos.x*ratioW - ctrWidth/2)|0)+"px"; zoomImg.style.top = -((pos.y*ratioH - ctrHeight/2)|0)+"px"; } ); }); // I've no idea. Simply setting the src will make IE screw it self into a 100% CPU fest. In a timeout, it's ok. setTimeout(function() { zoomImg.src = zoomSrc; }, 1); }, 1); } function init() { var images = document.getElementsByTagName("img"); for (var i=0;i