// SpryPanAndZoomPlugin.js - version 0.2 - Spry Pre-Release 1.7 // // Copyright (c) 2008. Adobe Systems Incorporated. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of Adobe Systems Incorporated nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. (function() { // BeginSpryComponent if (typeof Spry == "undefined" || !Spry.Widget || !Spry.Widget.ImageSlideShow) { alert("SpryPanAndZoomPlugin.js requires SpryImageSlideShow.js!"); return; } var gPZP = Spry.Widget.ImageSlideShow.PanAndZoomPlugin = { config: { defaultPanZoomSettings: [ [ 50, 50, 200, 50, 50, 100 ], // Zoom out from center. [ 0, 0, 200, 100, 100, 100 ], // Pan from upper-left to lower-right. [ 100, 100, 200, 0, 0, 100 ], // Pan from lower-right to upper-left. [ 0, 100, 200, 100, 0, 100 ], // Pan from lower-left to upper-right. [ 100, 0, 200, 0, 100, 100 ], // Pan from upper-right to lower-left. [ 50, 0, 200, 50, 100, 100 ], // Pan from top to bottom. [ 50, 100, 200, 50, 0, 100 ], // Pan from bottom to top. [ 0, 50, 200, 100, 50, 100 ], // Pan from left to right. [ 100, 50, 200, 0, 50, 100 ] // Pan from right to left. ] }, initialize: function(ss) { ss.panAndZoomInfo = { animations: [], pzSettings: [] }; ss.addObserver(this); }, fitAtoBRatio: function(aW, aH, bW, bH) { return Math.max(bW/aW, bH/aH); }, onPostAttachViewBehaviors: function(ss,evt) { var clip = Spry.$$("." + ss.clipClass, ss.element)[0]; ss.makePositioned(clip); Spry.$$("." + ss.clipClass + " img", ss.element).forEach(function(n){ n.style.top = n.style.left = 0; n.style.position = "absolute"; }); }, onPostExtractImageInfo: function(ss, evt) { var re = evt.repeatingElements; var pzs = ss.panAndZoomInfo.pzSettings; for (var i = 0; i < re.length; i++) { var e = re[i]; var v = e.getAttribute("rel"); if (!v) v = e.getAttribute("alt"); var p = pzs[i] = new Object; if (v && v.search(/\[(\s*\d+\s*,){5}\s*\d+\s*\]/) != -1) { var m = v.match(/\[(\s*\d+\s*,){5}\s*\d+\s*\]/); if (m) { var pz = m[0].replace(/\[|\|\s*]/g, "").split(","); p.x1 = parseFloat(pz[0]); p.y1 = parseFloat(pz[1]); p.z1 = parseFloat(pz[2]); p.x2 = parseFloat(pz[3]); p.y2 = parseFloat(pz[4]); p.z2 = parseFloat(pz[5]); } } } }, onPostStartSlideShow: function(ss, evt) { var slideIndex = ss.getCurrentSlideIndex(); if (slideIndex >= 0) gPZP.setupSlide(ss, ss.getCurrentSlide(), slideIndex); }, onPostStopSlideShow: function(ss, evt) { gPZP.stopAnimations(ss); }, addAnimation: function(ss, anim) { ss.panAndZoomInfo.animations.push(anim); anim.addObserver({ onAnimationComplete: function(){ gPZP.removeAnimation(ss, anim); } }); }, removeAnimation: function(ss, anim) { var anims = ss.panAndZoomInfo.animations; if (anims) { for (var i = 0; i < anims.length; i++) if (anims[i] == anim) { anims.splice(i, 1); return; } } }, stopAnimations: function(ss) { var anims = ss.panAndZoomInfo.animations; while (anims && anims.length) anims.pop().stop(); }, getPanZoomSettings: function(ss, slideIndex) { var result = {}; var info = ss.imageInfo[slideIndex]; result.width = info.width; result.height = info.height; // Get any pan and zoom settings from the specified element. Spry.Widget.setOptions(result, ss.panAndZoomInfo.pzSettings[slideIndex]); // If the element had no pan and zoom settings, pick a random // set from the defaults. if (typeof result.x1 == "undefined") { var pzs = gPZP.config.defaultPanZoomSettings[Math.round(Math.random() * (gPZP.config.defaultPanZoomSettings.length - 1))]; result.x1 = pzs[0]; result.y1 = pzs[1]; result.z1 = pzs[2]; result.x2 = pzs[3]; result.y2 = pzs[4]; result.z2 = pzs[5]; } return result; }, getCenteredClippedViewRect: function(x, y, iw, ih, vw, vh) { var hvw = vw / 2; var hvh = vh / 2; var vx = x - hvw; var vy = y - hvh; var vx2 = x + hvw; var vy2 = y + hvh; var pos = { x: vx, y: vy }; if (vx < 0) pos.x = 0; else if (vx2 > iw) pos.x = iw - vw; if (vy < 0) pos.y = 0; else if (vy2 > ih) pos.y = ih - vh; return { x: pos.x, y: pos.y, w: vw, h: vh }; }, setupSlide: function(ss, slide, slideIndex) { if (!ss || !slide) return; // Get the dimensions of the clip view. var clip = Spry.$$("." + ss.clipClass, ss.element)[0]; var cw = clip.offsetWidth; var ch = clip.offsetHeight; // Now get the original dimensions of the image // in the current slide and calculate the ratio // that will cause the image to minimally fill up // the clip view area. var ele = Spry.$$("img", slide)[0]; var kb = gPZP.getPanZoomSettings(ss, slideIndex); var iw = kb.width; var ih = kb.height; var ratio = gPZP.fitAtoBRatio(iw, ih, cw, ch); if (ss.isInPlayMode()) { var startZoom = ratio * kb.z1 / 100; var endZoom = ratio * kb.z2 / 100; var sw = iw * startZoom; var sh = ih * startZoom; var sx = sw * kb.x1 / 100; var sy = sh * kb.y1 / 100; var startRect = gPZP.getCenteredClippedViewRect(sx, sy, sw, sh, cw, ch); var ew = iw * endZoom; var eh = ih * endZoom; var ex = ew * kb.x2 / 100; var ey = eh * kb.y2 / 100; var endRect = gPZP.getCenteredClippedViewRect(ex, ey, ew, eh, cw, ch); ele.style.width = sw + "px"; ele.style.height = sh + "px"; ele.style.left = -startRect.x + "px"; ele.style.top = -startRect.y + "px"; var anim = new Spry.Effect.CSSAnimator(ele, "top: " + (-endRect.y) + "px; left: " + (-endRect.x) + "px; width: " + ew + "px; height: " + eh + "px;", { dropFrames: ss.dropFrames, duration: ss.displayInterval + (ss.transitionDuration) }); gPZP.addAnimation(ss, anim); anim.start(); } else { if (iw > cw || ih > ch) { var ratio = gPZP.fitAtoBRatio(cw, ch, iw, ih); iw = Math.round(iw / ratio); ih = Math.round(ih / ratio); } ele.style.width = iw + "px"; ele.style.height = ih + "px"; ele.style.left = Math.round((cw - iw) / 2) + "px"; ele.style.top = Math.round((ch - ih) / 2) + "px"; } }, onPostShowSlide: function(ss, evt) { if (evt.slideIndex >= 0) gPZP.setupSlide(ss, evt.target, evt.slideIndex); } }; })(); // EndSpryComponent