// Christmas Light Smashfest // Adapted from XLSF 2007 as originally used on http://schillmania.com/?theme=2007&christmas=1 var Y = { // shortcuts A: YAHOO.util.Anim, D: YAHOO.util.Dom, E: YAHOO.util.Event, UE: YAHOO.util.Easing, CA: YAHOO.util.ColorAnim, BG: YAHOO.util.BgPosAnim } function XLSF(oTarget) { var writeDebug = soundManager._wD; writeDebug('XLSF()'); var IS_MOON_COMPUTER = false; var isIE = navigator.userAgent.match(/msie/i); var isTouchDevice = navigator.userAgent.match(/ipad|ipod|iphone/i); var self = this; var xlsf = self; var useAngle = window.location.href.match(/angle/i); var useFollow = window.location.toString().match(/follow/i); var classBase = 'xlsf-light'+(useAngle?' xlsf-angled':''); var animDuration = 1; var lastMouseX = 0; var lastMouseY = 0; var mmhTimer = null; var activeLights = []; var testDiv = document.createElement('div'); var transforms = { ie: (typeof testDiv.style['-ms-transform'] !== 'undefined' ? '-ms-transform' : null), moz: (typeof testDiv.style.MozTransform !== 'undefined' ? 'MozTransform' : null), opera: (typeof testDiv.style['OTransform'] !== 'undefined' ? 'OTransform' : null), webkit: (typeof testDiv.style.webkitTransform !== 'undefined' ? 'webkitTransform' : null), prop: null } transforms.prop = (transforms.moz || transforms.webkit || transforms.ie || transforms.opera); this.oFrag = document.createDocumentFragment(); this.oExplosionTarget = document.getElementById('explosion-box'); this.oTarget = (oTarget?oTarget:document.documentElement); this.oExplosionBox = document.createElement('div'); this.oExplosionBox.className = 'xlsf-fragment-box'; this.oExplosionFrag = document.createElement('div'); this.oExplosionFrag.className = 'xlsf-fragment'; this.lights = []; this.lightClasses = { pico: 32, tiny: 50, small: 64, medium: 72, large: 96 } this.lightClass = 'tiny'; // kind of light to show (32px to 96px square) if (window.location.href.match(/size=/i)) { this.lightClass = window.location.href.substr(window.location.href.indexOf('size=')+5); if (this.lightClass.indexOf('#') !== -1) { this.lightClass = this.lightClass.substr(0,this.lightClass.indexOf('#')); } } this.lightXY = this.lightClasses[this.lightClass]; // shortcut to w/h function rnd(n) { return parseInt(Math.random()*n); } function plusMinus(n) { return (parseInt(rnd(2),10)===1?n*-1:n); } this.lightGroups = { left: [], top: [], right: [], bottom: [] } this.lightSmashCounter = 0; this.lightIndex = 0; this.lightInterval = 250; this.timer = null; this.bgBaseX = 0; this.bgBaseY = 0; this.soundIDs = 0; this.soundPan = { panValue: 75, left: 0, mid: 481, right: 962 } // this.beavis = null; this.cover = document.createElement('div'); this.cover.className = 'xlsf-cover'; document.documentElement.appendChild(this.cover); this.initSounds = function() { if (!soundManager.supported()) { return false; } for (var i=0; i<6; i++) { soundManager.createSound({ id: 'smash'+i, url: 'sound/glass'+i+'.mp3', autoLoad: true, multiShot: true, volume:50 }); } self.initSounds = function() {} // safety net } this.appendLights = function() { writeDebug('xlsf.appendLights()'); self.oTarget.appendChild(self.oFrag); // self.oFrag = document.createDocumentFragment(); } function ExplosionFragment(nType,sClass,x,y,vX,vY) { var self = this; this.o = xlsf.oExplosionFrag.cloneNode(true); this.nType = nType; this.sClass = sClass; this.x = x; this.y = y; this.w = 50; this.h = 50; this.bgBaseX = 0; this.bgBaseY = this.h*this.nType; this.vX = vX*(1.5+Math.random()); this.vY = vY*(1.5+Math.random()); this.oA = null; this.oA2 = null; this.burstPhase = 1; // starting background offset point this.burstPhases = 4; // 1+offset (ignore large size) this.o.style.backgroundPosition = ((this.w*-this.burstPhase)+'px '+(this.h*-nType)+'px'); // boundary checks if (self.sClass == 'left') { this.vX = Math.abs(this.vX); } else if (self.sClass == 'right') { this.vX = Math.abs(this.vX)*-1; } this.burstTween = function() { // determine frame to show var phase = 1+Math.floor((this.currentFrame/this.totalFrames)*self.burstPhases); if (phase != self.burstPhase) { self.burstPhase = phase; self.o.style.backgroundPosition = ((self.w*-self.burstPhase)+'px '+(self.h*-nType)+'px'); } } this.burst = function() { self.oA = new Y.A(self.o,{marginLeft:{to:(self.vX*(5+Math.random()*10))},marginTop:{to:(self.vY*(5+Math.random()*10))}},animDuration*0.75+(0.5*Math.random()),Y.UE.easeOutStrong); self.oA.onTween.subscribe(self.burstTween); // self.oA.onComplete.subscribe(self.hide); self.oA.animate(); } this.hide = function() { if (!isIE) self.o.style.opacity = 0; } this.reset = function() { self.o.style.left = '0px'; self.o.style.top = '0px'; self.o.style.marginLeft = '0px'; self.o.style.marginTop = '0px'; if (!isIE) self.o.style.opacity = 1; } this.animate = function() { self.reset(); self.burst(); } } function Explosion(nType,sClass,x,y) { var oParent = this; var self = this; this.o = null; this.nType = nType; this.sClass = sClass; this.x = x; this.y = y; this.boxVX = 0; this.boxVY = 0; this.o = xlsf.oExplosionBox.cloneNode(true); this.o.style.left = x+'px'; this.o.style.top = y+'px'; // this.oFrag = document.createDocumentFragment(); this.fragments = []; var mX = x; var mY = y; var type = typeMap[nType+sClass]; var scale = 7.5 var shift = 2; this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,-rnd(scale),-rnd(scale))); this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,plusMinus(rnd(shift)),-rnd(scale))); this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),-rnd(scale))); this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,-rnd(scale),plusMinus(rnd(shift)))); this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,plusMinus(rnd(shift)),plusMinus(rnd(shift)))); this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),plusMinus(rnd(shift)))); this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),-rnd(scale))); this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),plusMinus(rnd(shift)))); this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),rnd(scale))); this.init = function() { for (var i=self.fragments.length; i--;) { self.o.appendChild(self.fragments[i].o); } if (!IS_MOON_COMPUTER) { // faster rendering, particles get cropped xlsf.oExplosionTarget.appendChild(self.o); } else { // slower rendering, can overlay body xlsf.oExplosionTarget.appendChild(self.o); } } this.reset = function() { // clean-up // self.o.parentNode.removeChild(self.o); self.o.style.display = 'none'; self.o.style.marginLeft = '0px'; self.o.style.marginTop = '0px'; self.o.style.left = self.x+'px'; self.o.style.top = self.y+'px'; if (!isIE) self.o.style.opacity = 1; for (var i=self.fragments.length; i--;) { self.fragments[i].reset(); } } this.trigger = function(boxVX,boxVY) { self.o.style.display = 'block'; self.boxVX = boxVX; self.boxVY = boxVY; // boundary checks if (self.sClass == 'right') { self.boxVX = Math.abs(self.boxVX)*-1; } else if (self.sClass == 'left') { self.boxVX = Math.abs(self.boxVX); } for (var i=self.fragments.length; i--;) { self.fragments[i].animate(); } if (!isIE && (IS_MOON_COMPUTER)) { var oAExplode = new Y.A(self.o,{marginLeft:{to:100*self.boxVX},marginTop:{to:150*self.boxVY},opacity:{to:0.01}},animDuration,Y.UE.easeInStrong); } else { // even IE 7 sucks w/alpha-transparent PNG + CSS opacity. Boourns. var oAExplode = new Y.A(self.o,{marginLeft:{to:100*self.boxVX},marginTop:{to:150*self.boxVY}},animDuration,Y.UE.easeInStrong); } oAExplode.onComplete.subscribe(self.reset); oAExplode.animate(); // setTimeout(self.reset,animDuration*1000*1.5); } this.init(); } function Light(sSizeClass,sClass,nType,x,y,row,col) { var self = this; this.o = document.createElement('div'); this.sClass = sClass; this.sSizeClass = sSizeClass; this.nType = (nType||0); this.useY = (sClass == 'left' || sClass == 'right'); this.state = null; this.broken = 0; this.w = xlsf.lightClasses[sSizeClass]; this.h = xlsf.lightClasses[sSizeClass]; this.x = x; this.y = y; this.row = row; this.col = col; this.bg = 'image/bulbs-'+this.w+'x'+this.h+'-'+this.sClass+'.png'; this.o.style.width = this.w+'px'; this.o.style.height = this.h+'px'; this.o.style.background = 'url('+this.bg+') no-repeat 0px 0px'; this.bgBaseX = (self.useY?-self.w*this.nType:0); this.bgBaseY = (!self.useY?-self.h*this.nType:0); this.glassType = parseInt(Math.random()*6); // this.bonusSounds = ['griffin-laugh','bblaff','bblaff2']; // this.bonusSound = null; this.oExplosion = null; this.soundID = 'smash'+this.glassType; var panValue = xlsf.soundPan.panValue; // eg. +/- 80% this.pan = parseInt(this.x<=xlsf.soundPan.mid?-panValue+((this.x/xlsf.soundPan.mid)*panValue):(this.x-xlsf.soundPan.mid)/(xlsf.soundPan.right-xlsf.soundPan.mid)*panValue); this.setBGPos = function(x,y) { self.o.style.backgroundPosition = ((self.bgBaseX+x)+'px '+(self.bgBaseY+y)+'px'); } this.setLight = function(bOn) { if (self.broken || self.state == bOn) return false; if (!self.w || !self.h) self.getDimensions(); self.state = bOn; if (self.useY) { self.setBGPos(0,-this.h*(bOn?0:1)); } else { self.setBGPos(-this.w*(bOn?0:1),0); } } this.getDimensions = function() { self.w = self.o.offsetWidth; self.h = self.o.offsetHeight; self.bgBaseX = (self.useY?-self.w*self.nType:0); self.bgBaseY = (!self.useY?-self.h*self.nType:0); } this.on = function() { self.setLight(1); } this.off = function() { self.setLight(0); } this.flickr = function() { self.setLight(Math.random()>=0.5?1:0); } this.toggle = function() { self.setLight(!self.state?1:0); } this.explode = function(e) { self.oExplosion.trigger(0,1); // boooom! } this.smash = function(e) { if (self.broken) return false; self.broken = true; if (soundManager && soundManager.supported()) { soundManager.play(self.soundID,{pan:self.pan}); // soundManager.sounds[self.soundID].play({pan:self.pan}); // if (self.bonusSound != null) window.setTimeout(self.smashBonus,1000); } self.explode(e); var rndFrame = 2; // +parseInt(Math.random()*3); if (self.useY) { self.setBGPos(0,self.h*-rndFrame); } else { self.setBGPos(self.w*-rndFrame,0); } if (!useFollow && !useAngle && transforms.prop) { self.o.style[transforms.prop] = 'rotate('+Math.random()*plusMinus(20)+'deg)'; } xlsf.lightSmashCounter++; for (var i=activeLights.length; i--;) { // find this in the active array, and take it out if (activeLights[i] === self) { activeLights.splice(i,1); break; } } // xlsf.doNukeCheck(); // window.setTimeout(self.reset,3000); // respawn } this.smashBonus = function() { // soundManager.play(self.bonusSounds[self.bonusSound],urlBase+'sound/'+self.bonusSounds[self.bonusSound]+'.mp3'); } this.reset = function() { if (!self.broken) return false; self.broken = false; self.state = null; xlsf.lightSmashCounter--; // self.oExplosion.reset(); // may not be necessary self.flickr(); } this.init = function() { self.o.className = classBase+' '+this.sizeClass+' '+this.sClass; self.o.style.left = self.x+'px'; self.o.style.top = self.y+'px'; self.o.style.width = self.w+'px'; self.o.style.height = self.h+'px'; self.flickr(); xlsf.oFrag.appendChild(self.o); self.oExplosion = new Explosion(self.nType,self.sClass,self.x,self.y); } this.init(); } // Light() this.createLight = function(sClass,nType,x,y,row,col) { var oLight = new Light(self.lightClass,sClass,nType,x,y,row,col); activeLights.push(oLight); self.lightGroups[sClass].push(oLight); self.lights.push(oLight); return oLight; } this.rotateLights = function() { self.lights[self.lightIndex==self.lights.length?self.lights.length-1:self.lightIndex].off(); self.lightIndex++; if (self.lightIndex == self.lights.length) { self.lightIndex = 0; } self.lights[self.lightIndex].on(); } this.randomLights = function() { self.lights[parseInt(Math.random()*self.lights.length)].toggle(); } this.destroyLights = function() { // reset counter self.lightSmashCounter = 0; self.startSequence(Math.random()>0.75?self.destroyLight:self.destroyRandom,33); } this.destroyRandom = function() { for (var i=2; i--;) { if (activeLights.length) { activeLights[parseInt(Math.random()*activeLights.length)].smash(); } } } this.destroyLight = function() { var groupSize = 2; // # to smash at a time if (self.lightSmashCounter2) bsCounter = 0; // hack - loop through sounds } */ this.appendLights(); function followMouseMove(e) { if (!self.lights.length) { return false; } var x = lastMouseX; var y = lastMouseY; var x2 = null; var y2 = null; var angle = 0; var light = null; for (var i=self.lights.length; i--;) { light = self.lights[i]; if (light && !light.broken) { x2 = light.x; y2 = light.y; angle = Math.atan2((y-y2),(x-x2))*(180/Math.PI); if (light.col%2 === 0) { angle += (270*180/Math.PI); } if (transforms.prop) { light.o.style[transforms.prop] = 'rotate('+angle+'deg)'; } } } mmhTimer = null; } function mouseOrTouchMove(e) { // coordinate -> row/col check, smashy smash var x, y, lightIndex; if (e.targetTouches) { if (e.targetTouches.length === 1) { x = e.targetTouches[0].clientX; y = e.targetTouches[0].clientY; } } else { x = e.clientX; y = e.clientY; } lightCol = Math.floor((x/(self.lightClasses[self.lightClass]*jMax)*jMax)), lightRow = Math.floor((y/(self.lightClasses[self.lightClass]*iMax)*iMax)) lightIndex = (jMax*lightRow)+lightCol; if (self.lights[lightIndex]) { self.lights[lightIndex].smash(); } if (useFollow) { lastMouseX = x; lastMouseY = y; if (!mmhTimer) { mmhTimer = window.setTimeout(followMouseMove, 33); // try to be nice and throttle this call, which may be expensive } } } if (isTouchDevice && self.oTarget !== document.documentElement) { self.oTarget.addEventListener('touchstart', function(e) { self.oTarget.addEventListener('touchmove', mouseOrTouchMove, false); self.oTarget.addEventListener('touchend', function(e) { self.oTarget.removeEventListener('touchMove', mouseOrTouchMove); }); mouseOrTouchMove(e); // initial touch might be a smashy one, too e.preventDefault(); return false; }, false); } else { if (document.addEventListener) { document.addEventListener('mousemove', mouseOrTouchMove, false); } else if (document.attachEvent) { document.attachEvent('onmousemove', mouseOrTouchMove); } } this.startSequence(self.randomLights); } // --- XLSF2007() var xlsf = null; function smashInit() { xlsf = new XLSF(document.getElementById('lights')); xlsf.initSounds(); document.getElementById('loading').style.display = 'none'; } soundManager.url = '../../swf/'; soundManager.flashVersion = 9; soundManager.useHighPerformance = true; soundManager.wmode = 'transparent'; soundManager.debugMode = false; // start in either case soundManager.onready(smashInit); soundManager.ontimeout(smashInit);