1 | /*
|
---|
2 | * MojoMagnify 0.1.10 - JavaScript Image Magnifier
|
---|
3 | * Copyright (c) 2008-2010 Jacob Seidelin, [email protected], http://blog.nihilogic.dk/
|
---|
4 | * Licensed under the MPL License [http://www.nihilogic.dk/licenses/mpl-license.txt]
|
---|
5 | */
|
---|
6 |
|
---|
7 |
|
---|
8 | var MojoMagnify = (function() {
|
---|
9 |
|
---|
10 | var $ = function(id) {return document.getElementById(id);};
|
---|
11 | var dc = function(tag) {return document.createElement(tag);};
|
---|
12 |
|
---|
13 | var isIE = !!document.all && !!window.attachEvent && !window.opera;
|
---|
14 |
|
---|
15 | function addEvent(element, ev, handler)
|
---|
16 | {
|
---|
17 | if (element.addEventListener) {
|
---|
18 | element.addEventListener(ev, handler, false);
|
---|
19 | } else if (element.attachEvent) {
|
---|
20 | element.attachEvent("on" + ev, handler);
|
---|
21 | }
|
---|
22 | }
|
---|
23 |
|
---|
24 | function removeEvent(element, ev, handler) {
|
---|
25 | if (element.removeEventListener) {
|
---|
26 | element.removeEventListener(ev, handler, false);
|
---|
27 | } else if (element.detachEvent) {
|
---|
28 | element.detachEvent("on" + ev, handler);
|
---|
29 | }
|
---|
30 | }
|
---|
31 |
|
---|
32 |
|
---|
33 | function getElementPos(element)
|
---|
34 | {
|
---|
35 | var x = element.offsetLeft;
|
---|
36 | var y = element.offsetTop;
|
---|
37 | var parent = element.offsetParent;
|
---|
38 | while (parent) {
|
---|
39 | x += parent.offsetLeft - parent.scrollLeft;
|
---|
40 | y += parent.offsetTop - parent.scrollTop;
|
---|
41 | parent = parent.offsetParent;
|
---|
42 | }
|
---|
43 | return {
|
---|
44 | x : x,
|
---|
45 | y : y
|
---|
46 | }
|
---|
47 | }
|
---|
48 |
|
---|
49 | function getEventMousePos(element, e) {
|
---|
50 | var scrollX = document.body.scrollLeft || document.documentElement.scrollLeft;
|
---|
51 | var scrollY = document.body.scrollTop || document.documentElement.scrollTop;
|
---|
52 |
|
---|
53 | if (e.currentTarget) {
|
---|
54 | var pos = getElementPos(element);
|
---|
55 | return {
|
---|
56 | x : e.clientX - pos.x + scrollX,
|
---|
57 | y : e.clientY - pos.y + scrollY
|
---|
58 | }
|
---|
59 | }
|
---|
60 | return {
|
---|
61 | x : e.offsetX,
|
---|
62 | y : e.offsetY
|
---|
63 | }
|
---|
64 | }
|
---|
65 |
|
---|
66 | function setZoomPos(img, x, y, pos) {
|
---|
67 | var zoomImg = img.__mojoMagnifyImage;
|
---|
68 | if (!zoomImg) return;
|
---|
69 |
|
---|
70 | var full = img.__mojoMagnifyOptions.full;
|
---|
71 |
|
---|
72 | img.__mojoMagnifyX = x;
|
---|
73 | img.__mojoMagnifyY = y;
|
---|
74 | img.__mojoMagnifyPos = pos;
|
---|
75 |
|
---|
76 | var zoom = img.__mojoMagnifyZoomer;
|
---|
77 |
|
---|
78 | var maskWidth = zoom.offsetWidth;
|
---|
79 | var maskHeight = zoom.offsetHeight;
|
---|
80 |
|
---|
81 | var imgLeft = img.offsetLeft;
|
---|
82 | var imgTop = img.offsetTop;
|
---|
83 |
|
---|
84 | var w = img.offsetWidth ? img.offsetWidth : img.naturalWidth;
|
---|
85 | var h = img.offsetHeight ? img.offsetHeight : img.naturalHeight;
|
---|
86 |
|
---|
87 | if (full) {
|
---|
88 | var fx = x / w;
|
---|
89 | var fy = y / h;
|
---|
90 |
|
---|
91 | var dw = maskWidth - w;
|
---|
92 | var dh = maskHeight - h;
|
---|
93 |
|
---|
94 | var left = -dw * fx;
|
---|
95 | var top = -dh * fy;
|
---|
96 | } else {
|
---|
97 | var left = pos.x - maskWidth/2;
|
---|
98 | var top = pos.y - maskHeight/2;
|
---|
99 |
|
---|
100 | if (!isIE) {
|
---|
101 | left -= imgLeft;
|
---|
102 | top -= imgTop;
|
---|
103 | }
|
---|
104 | }
|
---|
105 |
|
---|
106 | zoom.style.left = left + "px";
|
---|
107 | zoom.style.top = top + "px";
|
---|
108 |
|
---|
109 | var zoomWidth = zoomImg.offsetWidth ? zoomImg.offsetWidth : zoomImg.naturalWidth;
|
---|
110 | var zoomHeight = zoomImg.offsetHeight ? zoomImg.offsetHeight : zoomImg.naturalHeight;
|
---|
111 |
|
---|
112 | if (full) {
|
---|
113 | var zx = 0;
|
---|
114 | var zy = 0;
|
---|
115 | } else {
|
---|
116 | var zoomXRatio = zoomWidth / w;
|
---|
117 | var zoomYRatio = zoomHeight / h;
|
---|
118 |
|
---|
119 | var zoomX = Math.round(x * zoomXRatio);
|
---|
120 | var zoomY = Math.round(y * zoomYRatio);
|
---|
121 |
|
---|
122 | var zx = -zoomX + maskWidth/2;
|
---|
123 | var zy = -zoomY + maskHeight/2;
|
---|
124 | }
|
---|
125 |
|
---|
126 | zoomImg.style.left = zx + "px";
|
---|
127 | zoomImg.style.top = zy + "px";
|
---|
128 | }
|
---|
129 |
|
---|
130 | function startAnimation(img) {
|
---|
131 | var options = img.__mojoMagnifyOptions;
|
---|
132 |
|
---|
133 | if (img.__mojoMagnifyAnimTimer)
|
---|
134 | clearTimeout(img.__mojoMagnifyAnimTimer);
|
---|
135 | var step = 1;
|
---|
136 |
|
---|
137 | var zoom = img.__mojoMagnifyZoomer;
|
---|
138 | var zoomImg = img.__mojoMagnifyImage;
|
---|
139 | var zoomBorder = img.__mojoMagnifyBorder;
|
---|
140 |
|
---|
141 | var imgWidth = img.offsetWidth ? img.offsetWidth : img.naturalWidth;
|
---|
142 | var imgHeight = img.offsetHeight ? img.offsetHeight : img.naturalHeight;
|
---|
143 |
|
---|
144 | var dw = img.__mojoMagnifyWidth - imgWidth;
|
---|
145 | var dh = img.__mojoMagnifyHeight - imgHeight;
|
---|
146 |
|
---|
147 | var next = function() {
|
---|
148 | var w = imgWidth + dw * (step/10);
|
---|
149 | var h = imgHeight + dh * (step/10);
|
---|
150 |
|
---|
151 | zoomBorder.style.width = w + "px";
|
---|
152 | zoomBorder.style.height = h + "px";
|
---|
153 | zoom.style.width = w + "px";
|
---|
154 | zoom.style.height = h + "px";
|
---|
155 | zoomImg.style.width = w + "px";
|
---|
156 | zoomImg.style.height = h + "px";
|
---|
157 |
|
---|
158 | if (img.__mojoMagnifyPos) {
|
---|
159 | setZoomPos(img, img.__mojoMagnifyX, img.__mojoMagnifyY, img.__mojoMagnifyPos);
|
---|
160 | }
|
---|
161 |
|
---|
162 | if (step < 10) {
|
---|
163 |
|
---|
164 | step += 1;
|
---|
165 | img.__mojoMagnifyAnimTimer = setTimeout(next, 60);
|
---|
166 | } else {
|
---|
167 | img.__mojoMagnifyAnimTimer = 0;
|
---|
168 | }
|
---|
169 | }
|
---|
170 | next();
|
---|
171 | }
|
---|
172 |
|
---|
173 |
|
---|
174 | function makeMagnifiable(img, zoomSrc, opt) {
|
---|
175 | // just set the new zoom src if this img already has the Mojo structure setup
|
---|
176 | if (img.__mojoMagnifyImage) {
|
---|
177 | img.__mojoMagnifyImage.src = zoomSrc;
|
---|
178 | return;
|
---|
179 | }
|
---|
180 |
|
---|
181 | var options = opt || {};
|
---|
182 |
|
---|
183 | img.__mojoMagnifyOptions = options;
|
---|
184 |
|
---|
185 | // make sure the image is loaded, if not then add an onload event and return
|
---|
186 | if (!img.complete && !img.__mojoMagnifyQueued) {
|
---|
187 | addEvent(img, "load", function() {
|
---|
188 | img.__mojoMagnifyQueued = true;
|
---|
189 | setTimeout(function() {
|
---|
190 | makeMagnifiable(img, zoomSrc);
|
---|
191 | }, 1);
|
---|
192 | });
|
---|
193 | return;
|
---|
194 | }
|
---|
195 |
|
---|
196 | var w = img.offsetWidth ? img.offsetWidth : img.naturalWidth;
|
---|
197 | var h = img.offsetHeight ? img.offsetHeight : img.naturalHeight;
|
---|
198 |
|
---|
199 | var oldParent = img.parentNode;
|
---|
200 | if (oldParent.nodeName.toLowerCase() != "a") {
|
---|
201 | var linkParent = dc("a");
|
---|
202 | linkParent.setAttribute("href", zoomSrc);
|
---|
203 | oldParent.replaceChild(linkParent, img);
|
---|
204 | linkParent.appendChild(img);
|
---|
205 | } else {
|
---|
206 | var linkParent = oldParent;
|
---|
207 | }
|
---|
208 |
|
---|
209 | linkParent.style.position = "relative";
|
---|
210 | linkParent.style.display = "block";
|
---|
211 | linkParent.style.width = w+"px";
|
---|
212 | linkParent.style.height = h+"px";
|
---|
213 |
|
---|
214 | var imgLeft = img.offsetLeft;
|
---|
215 | var imgTop = img.offsetTop;
|
---|
216 |
|
---|
217 | var zoom = dc("div");
|
---|
218 | zoom.className = "mojomagnify_zoom";
|
---|
219 | zoom.style.left = "-9999px";
|
---|
220 |
|
---|
221 | var parent = img.parentNode;
|
---|
222 | var zoomImg = dc("img");
|
---|
223 | zoomImg.className = "mojomagnify_img";
|
---|
224 | zoomImg.style.position = "absolute";
|
---|
225 | zoomImg.style.maxWidth = "none";
|
---|
226 | zoomImg.style.maxHeight = "none";
|
---|
227 |
|
---|
228 | if (isIE) {
|
---|
229 | // IE won't let the mouse click pass through properly to the link,
|
---|
230 | // so we clone the link and use it for the zoom image as well. Do for all browsers, perhaps?
|
---|
231 | var zoomLink = dc("a");
|
---|
232 | zoomLink.setAttribute("href", linkParent.getAttribute("href"));
|
---|
233 | zoomLink.setAttribute("onclick", linkParent.getAttribute("onclick"));
|
---|
234 | zoomLink.style.position = "absolute";
|
---|
235 | zoomLink.style.left = "0px";
|
---|
236 | zoomLink.style.top = "0px";
|
---|
237 | zoomLink.appendChild(zoomImg);
|
---|
238 | zoom.appendChild(zoomLink);
|
---|
239 | } else {
|
---|
240 | zoom.appendChild(zoomImg);
|
---|
241 | }
|
---|
242 |
|
---|
243 | var ctr = dc("div");
|
---|
244 | with (ctr.style) {
|
---|
245 | position = "absolute";
|
---|
246 | left = imgLeft+"px";
|
---|
247 | top = imgTop+"px";
|
---|
248 | width = w+"px";
|
---|
249 | height = h+"px";
|
---|
250 | overflow = "hidden";
|
---|
251 | display = "block";
|
---|
252 | }
|
---|
253 |
|
---|
254 |
|
---|
255 | ctr.appendChild(zoom);
|
---|
256 | parent.appendChild(ctr);
|
---|
257 |
|
---|
258 | var zoomBorder = dc("div");
|
---|
259 | zoomBorder.className = "mojomagnify_border";
|
---|
260 | zoom.appendChild(zoomBorder);
|
---|
261 |
|
---|
262 | var zoomInput = parent;
|
---|
263 |
|
---|
264 | // clear old overlay
|
---|
265 | if (img.__mojoMagnifyOverlay)
|
---|
266 | parent.removeChild(img.__mojoMagnifyOverlay);
|
---|
267 | img.__mojoMagnifyOverlay = ctr;
|
---|
268 |
|
---|
269 | // clear old high-res image
|
---|
270 | if (img.__mojoMagnifyImage && img.__mojoMagnifyImage.parentNode)
|
---|
271 | img.__mojoMagnifyImage.parentNode.removeChild(img.__mojoMagnifyImage);
|
---|
272 |
|
---|
273 | img.__mojoMagnifyImage = zoomImg;
|
---|
274 | img.__mojoMagnifyZoomer = zoom;
|
---|
275 | img.__mojoMagnifyBorder = zoomBorder;
|
---|
276 |
|
---|
277 | var isInImage = false;
|
---|
278 |
|
---|
279 | function onMouseOut(e) {
|
---|
280 | e = e || window.event;
|
---|
281 |
|
---|
282 | var target = e.target || e.srcElement;
|
---|
283 | if (!target) return;
|
---|
284 | if (target.nodeName != "DIV") return;
|
---|
285 | var relTarget = e.relatedTarget || e.toElement;
|
---|
286 | if (!relTarget) return;
|
---|
287 | while (relTarget != target && relTarget.nodeName != "BODY" && relTarget.parentNode) {
|
---|
288 | relTarget = relTarget.parentNode;
|
---|
289 | }
|
---|
290 | if (relTarget != target) {
|
---|
291 | isInImage = false;
|
---|
292 | ctr.style.display = "none";
|
---|
293 | }
|
---|
294 | };
|
---|
295 |
|
---|
296 | function onMouseMove(e) {
|
---|
297 | e = e || window.event;
|
---|
298 | if (!isInImage) {
|
---|
299 | if (options.animate) {
|
---|
300 | startAnimation(img);
|
---|
301 | }
|
---|
302 | }
|
---|
303 | isInImage = true;
|
---|
304 |
|
---|
305 | ctr.style.display = "block";
|
---|
306 |
|
---|
307 | var pos = getEventMousePos(zoomInput, e);
|
---|
308 |
|
---|
309 | if (e.srcElement && isIE) {
|
---|
310 | if (e.srcElement == zoom) return;
|
---|
311 | if (e.srcElement != zoomInput) {
|
---|
312 | var zoomImgPos = getElementPos(e.srcElement);
|
---|
313 | var imgPos = getElementPos(img);
|
---|
314 | pos.x -= (imgPos.x - zoomImgPos.x);
|
---|
315 | pos.y -= (imgPos.y - zoomImgPos.y);
|
---|
316 | }
|
---|
317 | }
|
---|
318 |
|
---|
319 | var x = e.clientX - (getElementPos(img).x - (document.body.scrollLeft||document.documentElement.scrollLeft));
|
---|
320 | var y = e.clientY - (getElementPos(img).y - (document.body.scrollTop||document.documentElement.scrollTop));
|
---|
321 |
|
---|
322 | setZoomPos(img, x, y, pos);
|
---|
323 | }
|
---|
324 |
|
---|
325 | addEvent(zoomImg, "load", function() {
|
---|
326 |
|
---|
327 | addEvent(ctr, "mouseout", onMouseOut);
|
---|
328 | addEvent(ctr, "mouseleave", onMouseOut);
|
---|
329 | if (isIE) {
|
---|
330 | addEvent(document.body, "mouseover",
|
---|
331 | function(e) {
|
---|
332 | e = e || window.event;
|
---|
333 |
|
---|
334 | if (isInImage && e.toElement != zoomImg) {
|
---|
335 | ctr.style.display = "none";
|
---|
336 | }
|
---|
337 | }
|
---|
338 | );
|
---|
339 | }
|
---|
340 |
|
---|
341 | // try removing the event first so we don't get multiple handlers firing
|
---|
342 | removeEvent(zoomInput, "mousemove", onMouseMove);
|
---|
343 | addEvent(zoomInput, "mousemove", onMouseMove);
|
---|
344 |
|
---|
345 | if (options.full) {
|
---|
346 | var maskWidth = zoomImg.offsetWidth;
|
---|
347 | var maskHeight = zoomImg.offsetHeight;
|
---|
348 | img.__mojoMagnifyWidth = maskWidth;
|
---|
349 | img.__mojoMagnifyHeight = maskHeight;
|
---|
350 | zoomBorder.style.width = maskWidth + "px";
|
---|
351 | zoomBorder.style.height = maskHeight + "px";
|
---|
352 | zoom.style.width = maskWidth + "px";
|
---|
353 | zoom.style.height = maskHeight + "px";
|
---|
354 | }
|
---|
355 |
|
---|
356 | ctr.style.display = "none";
|
---|
357 | });
|
---|
358 |
|
---|
359 | // 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.
|
---|
360 | setTimeout(function() {
|
---|
361 | zoomImg.src = zoomSrc;
|
---|
362 | }, 1);
|
---|
363 | }
|
---|
364 |
|
---|
365 | function setCoords(img, x, y) {
|
---|
366 | if (!img.__mojoMagnifyOverlay) return;
|
---|
367 | isInImage = true;
|
---|
368 | img.__mojoMagnifyOverlay.style.display = "block";
|
---|
369 | setZoomPos(img, x, y, { x : x, y : y });
|
---|
370 | }
|
---|
371 |
|
---|
372 | function init() {
|
---|
373 | var images = document.getElementsByTagName("img");
|
---|
374 | var imgList = [];
|
---|
375 | for (var i=0;i<images.length;i++) {
|
---|
376 | imgList.push(images[i]);
|
---|
377 | }
|
---|
378 | for (var i=0;i<imgList.length;i++) {
|
---|
379 | var img = imgList[i];
|
---|
380 | var zoomSrc = img.getAttribute("data-magnifysrc");
|
---|
381 | if (zoomSrc) {
|
---|
382 | var opt = {
|
---|
383 | full : img.getAttribute("data-magnifyfull") === "true",
|
---|
384 | animate : img.getAttribute("data-magnifyanimate") === "true"
|
---|
385 | };
|
---|
386 | makeMagnifiable(img, zoomSrc, opt);
|
---|
387 | }
|
---|
388 | }
|
---|
389 | }
|
---|
390 |
|
---|
391 | return {
|
---|
392 | addEvent : addEvent,
|
---|
393 | init : init,
|
---|
394 | makeMagnifiable : makeMagnifiable,
|
---|
395 | setCoords : setCoords
|
---|
396 | };
|
---|
397 |
|
---|
398 | })();
|
---|
399 |
|
---|
400 | MojoMagnify.addEvent(window, "load", MojoMagnify.init); |
---|