1(function($){ 2 3 var layeranimation = function(rootNode) { 4 var self = this; 5 6 this.scrollTime = 500; 7 this.waitTime = 4000; 8 this.stepWidth = 20; 9 this.nextItemIntverall = 0.7; 10 this.zIndex = 100; 11 this.offsetWidth = 0; 12 this.isPlaying = true; 13 this.itemButtonClicked = false; 14 this.layerPlayingTimeOut = null; 15 16 this.root = rootNode; 17 rootNode[0].layerAnimation = self; 18 19 this.layerList = null; 20 this.layer = new Array(); 21 this.currentLayer = 1; 22 this.currentItem = 0; 23 this.isRunning = false; 24 25 this.run = function(itemNrNew, layerNew) { 26 27 // Set Current Item 28 var itemNr = self.currentItem; 29 if ( typeof itemNrNew == 'number' ) itemNr = itemNrNew; 30 31 // Set Current Layer 32 var layerNr = self.currentLayer; 33 if ( typeof layerNew == 'number' ) layerNr = layerNew; 34 35 // If it does not exist, return 36 if ( !self.layer[layerNr] || !self.layer[layerNr].items[itemNr] ) { self.isRunning = false; return; } 37 38 self.isRunning = true; 39 40 // Get the Item 41 var item = self.layer[layerNr].items[itemNr]; 42 if ( itemNr == 0 && self.isPlaying ) { 43 self.setActive(self.layerList.children().get(layerNr), true, false); 44 } 45 46 // Calc Position + Timeout Step 47 var currentLeft = parseInt(item.elem.css('left')); 48 49 var timeout = item.currentTime / (currentLeft * item.direction) * self.stepWidth; 50 51 if ( itemNr == 0 && currentLeft == self.offsetWidth * item.direction ) { 52 var number = layerNr-1 < 0 ? self.layer.length-1 : layerNr-1; 53 self.layer[number].elem.filter(':not(:animated)').css('opacity', 0)/*fadeTo(self.scrollTime, 0, function(){ 54 self.layer[number].elem.css('z-index', self.zIndex); 55 console.log("animation done " + itemNr + " " + number); 56 })*/; 57 } 58 59 currentLeft -= (self.stepWidth * item.direction); 60 if ( ( currentLeft <= 0 && item.direction > 0 ) || ( currentLeft >= 0 && item.direction < 0 ) ) { currentLeft = 0; } 61 62 // Set new Position and Timeout 63 item.elem.css('left', currentLeft); 64 if ( itemNr == 0 ) { 65 self.layer[layerNr].elem.css('left', currentLeft); 66 } 67 68 // Start next Item in Layer after Intervall 69 if ( item.currentTime <= (self.scrollTime * self.nextItemIntverall) ) { 70 window.setTimeout( function() { self.run(itemNr +1, layerNr); }, timeout); 71 72 // Reset previous if next Layer comes 73 // if ( this.layer.length > 1 && firstStep) 74 // this.resetLayer(layerNr -1 ); 75 self.layer[layerNr].elem.css('z-index', self.zIndex); 76 } 77 78 item.currentTime -= timeout; 79 80 // If this is not the current layer, but an intervalled layer, return 81 if ( itemNrNew || layerNew ) { return; } 82 83 // scrolling done ? 84 if ( itemNr == self.currentItem && (( currentLeft <= 0 && item.direction > 0 ) || ( currentLeft >= 0 && item.direction < 0 )) ) { 85 86 if ( self.currentItem < self.layer[layerNr].items.length -1 ) { 87 88 self.currentItem++; 89 90 } else { 91 92 if ( self.layer.length > 1 ) 93 self.resetLayer(layerNr -1 ); 94 self.layer[layerNr].elem.css('z-index', self.zIndex); 95 96 if ( layerNr < self.layer.length-1 ) { 97 self.currentLayer++; 98 } else { 99 self.currentLayer = 0; 100 } 101 102 self.currentItem = 0; 103 timeout = self.layer[layerNr].waitTime || self.waitTime; 104 105 $(document).trigger("layeranimation.layerDone", self.layer); 106 107 if ( ! self.isPlaying || self.layer.length == 1 ) { 108 self.isRunning = false; 109 return; 110 } 111 } 112 } 113 114 // next run routine; 115 self.layerPlayingTimeOut = window.setTimeout( self.run, timeout); 116 }; 117 118 this.resetLayer = function(layer, alsoCurrent) { 119 120 if ( layer < 0 ) { layer = self.layer.length-1; } 121 if ( !self.layer[layer] ) { return; } 122 123 var currentLayer = alsoCurrent ? ( self.currentLayer-1 < 0 ? self.layer.length-1 : self.currentLayer-1 ) : self.currentLayer; 124 var offset = layer == currentLayer ? 0 : self.offsetWidth; 125 126 $(self.layer[layer].items).each(function(){ 127 this.elem.css({'left': this.direction * offset}); 128 this.currentTime = self.scrollTime; 129 }); 130 131 // Special for layer one 132 self.layer[layer].elem.css({ 133 'z-index': self.zIndex +100, 134 'left' : self.layer[layer].items[0].direction * offset 135 }).fadeTo(0, 1); 136 }; 137 138 /* ***************************************************************************** 139 140 Build Structure 141 142 ***************************************************************************** */ 143 144 this.layerStruct = function() { 145 this.items = new Array(); 146 this.elem = null; 147 this.waitTime = self.waitTime; 148 }; 149 150 this.itemStruct = function() { 151 this.elem = null; 152 this.direction = +1; 153 this.currentTime = 0; 154 this.next = null; 155 }; 156 157 this.layerClick = function(elem) { 158 159 this.Toggle = function(e) { 160 161 this.elem = $(this); 162 if (e.target) this.elem = $(e.target); 163 else if (e.srcElement) this.elem = $(e.srcElement); 164 165 this.isPlayPause = this.elem.hasClass('play-pause'); 166 this.active = !this.elem.hasClass('active'); 167 168 this.playPauseToggle = function(e) { 169 if ( this.active ) { 170 // pause playing 171 self.Pause(); 172 self.itemButtonClicked = true; 173 } else { 174 // start playing 175 self.itemButtonClicked = false; 176 self.Resume(); 177 } 178 }; 179 180 this.layerToggle = function(e) { 181 self.setActive( this.elem, this.active, this.isPlayPause); 182 if ( this.active ) { 183 184 if ( self.layer.length == 1 ) return; 185 // stop all animation 186 self.Pause(); 187 var resetLayer = self.currentLayer-1; 188 if ( self.isRunning ) { 189 window.clearTimeout(self.layerPlayingTimeOut); 190 self.resetLayer(self.currentLayer); 191 } 192 193 // self.layer[self.currentLayer].elem.style.zIndex = self.zIndex; 194 // var resetLayer = self.currentLayer-1; 195 if ( resetLayer < 0 ) resetLayer = self.layer.length -1; 196 197 // reset Layer for position calculation 198 self.currentItem = 0; 199 200 // get current Position 201 self.currentLayer = this.elem.parent().children().index(this.elem); 202 203 // Set Playmode to pause 204 self.setActive( this.elem.parent().children().last(), true, true ); 205 206 // Reset Layers manually to 0px 207 // Set zIndex and reset previous entry 208 self.layer[self.currentLayer].elem.css({'z-index': self.zIndex, 'left':0}); 209 self.layer[self.currentLayer].elem.children().css('left', 0); 210 211 var timeout = self.layer[self.currentLayer].waitTime; 212 213 self.resetLayer(self.currentLayer-1); 214 if ( resetLayer != self.currentLayer ) self.resetLayer(resetLayer); 215 216 // prepare next Layer for animation 217 if ( self.currentLayer < self.layer.length-1 ) { 218 self.currentLayer++; 219 } else { 220 self.currentLayer = 0; 221 } 222 223 // disable hover re-enable function 224 self.itemButtonClicked = true; 225 window.setTimeout(function() { 226 // start playing 227 self.Resume(); 228 }, timeout); 229 230 $(document).trigger("layeranimation.layerDone", self.layer); 231 } else { 232 233 // start playing 234 self.itemButtonClicked = false; 235 self.Resume(); 236 } 237 }; 238 239 return this.isPlayPause ? this.playPauseToggle() : this.layerToggle(); 240 }; 241 242 elem.click(this.Toggle); 243 }; 244 245 this.setActive = function(elem, active, isPlayPause) { 246 247 elem = $(elem); 248 249 // Reset "active" on each 250 if ( !isPlayPause ) { 251 elem.parent().children().removeClass('active'); 252 } 253 254 // set "active" on current 255 if ( active ) { 256 elem.addClass('active'); 257 } else if ( isPlayPause ) { 258 elem.removeClass('active'); 259 } 260 }; 261 262 // Pause all animation if still playing 263 this.Pause = function() { 264 265 if ( ! self.isPlaying ) return; 266 if ( self.itemButtonClicked ) return; 267 268 self.isPlaying = false; 269 if ( !self.isRunning ) window.clearTimeout(self.layerPlayingTimeOut); 270 self.setActive( self.layerList.children().last(), true, true ); 271 }; 272 273 // resume animation if not playing 274 this.Resume = function() { 275 276 if ( self.isPlaying ) return; 277 if ( self.itemButtonClicked ) return; 278 if ( self.layer.length == 1 ) return; 279 280 self.setActive( self.layerList.children().last(), false, true ); 281 self.isPlaying = true; 282 if ( !self.isRunning ) self.layerPlayingTimeOut = window.setTimeout( self.run, 2000); 283 }; 284 285 this.togglePlayState = function( active ) { 286 if ( active ) { 287 self.itemButtonClicked = false; 288 self.Resume(); 289 } else { 290 self.Pause(); 291 // do not re-enable automatically 292 self.itemButtonClicked = true; 293 } 294 }; 295 296 this.init = function() { 297 298 if ( !self.root || (document.documentMode && document.documentMode < 8) || self.root.find('div[type=layer]').length < 1) 299 { 300 return; 301 } 302 303 self.layerList = $('<ul/>').addClass('layeranimation_layer').css('display', 'inline-block').appendTo(self.root); 304 self.root.removeClass('noscripting').addClass('scripting'); 305 306 // make clean 307 self.layer = new Array(); 308 309 // Each Layer 310 self.root.find('div[type=layer]').each(function() 311 { 312 var innerLayer = new self.layerStruct(); 313 innerLayer.elem = $(this); 314 innerLayer.waitTime = innerLayer.elem.attr('timing') * 1000 || self.timeout; 315 innerLayer.elem.show().css({ 316 'z-index': self.zIndex + 100, 317 transitionDuration: (self.scrollTime / 1000 * 2) + 's' 318 }); 319 320 if ( self.offsetWidth == 0 ) { 321 self.offsetWidth = innerLayer.elem.width(); // Offset from the first layer. 322 } 323 324 if ( self.layer.length <= 1 && innerLayer.elem.hasClass('fixed') ) { 325 innerLayer.elem.css('z-index', 100); 326 } else { 327 innerLayer.elem.bind('mouseover', self.Pause); 328 innerLayer.elem.bind('mouseout', self.Resume); 329 330 self.layer.push(innerLayer); 331 332 var layerListItem = $('<li/>').text(self.layer.length).attr('title', 'skip to page ' + self.layer.length).addClass(self.layer.length <= 1 ? 'active' : ''); 333 334 new self.layerClick(layerListItem); 335 self.layerList.append(layerListItem); 336 self.layerList.width(self.layerList.width() + layerListItem.width() * 1.3); 337 } 338 339 innerLayer.elem.find('div.item').each(function(){ 340 341 var innerItem = new self.itemStruct(); 342 innerItem.elem = $(this); 343 innerItem.direction = innerItem.elem.hasClass('right') ? -1 : 1; 344 innerItem.currentTime = self.scrollTime; 345 346 if ( self.layer.length <= 1 || innerLayer.elem.hasClass('fixed') ) { 347 innerItem.elem.css('left', 0); 348 } else { 349 innerItem.elem.css('left', innerItem.direction * self.offsetWidth); 350 if ( innerLayer.items.length < 1 && !innerItem.elem.hasClass('first') ) { 351 innerLayer.elem.css('left', innerItem.direction * self.offsetWidth); 352 } 353 } 354 355 if ( innerLayer.items.length < 1 && !innerItem.elem.hasClass('first') ) { 356 innerItem.elem.addClass('first'); 357 } 358 359 innerLayer.items.push(innerItem); 360 innerItem.elem.find('img').on('load', function(e) { 361 e.currentTarget.loaded = true; 362 }); 363 }); 364 }); 365 366 var layerListItem = $('<li/>').addClass('play-pause').attr('title', 'pause animation').appendTo(self.layerList); 367 self.layerList.width(self.layerList.width() + layerListItem.width()); 368 self.layerList.css('display', ''); // This is not hide, it is remove inline-block from above 369 new self.layerClick(layerListItem, self); 370 371 this.layerPlayingTimeOut = window.setTimeout( self.run, self.layer[0].waitTime); 372 373 // Check if layeranimation is in viewport 374 var animationHeight = self.root.height(); 375 var originalAnimationTop = self.root.offset().top; 376 var onScroolResize = function() { 377 378 var scrollTop = $(window).scrollTop(); 379 var windowHeight = $(window).height(); 380 381 if ( (scrollTop >= originalAnimationTop+animationHeight || scrollTop+windowHeight <= originalAnimationTop ) && self.isPlaying ) 382 { 383 // stopPlaying 384 self.Pause(); 385 } 386 else if ( (scrollTop < originalAnimationTop+animationHeight && scrollTop+windowHeight > originalAnimationTop ) && !self.isPlaying ) 387 { 388 self.Resume(); 389 } 390 }; 391 392 $(document).bind('scroll resize touchmove touchend', onScroolResize); 393 }; 394 395 this.toggleCSSSaveState = function( $elem, save ) { 396 // Stow away or get the current css 397 398 var currentStyle = (save?'':'save-') + 'style'; 399 var saveStyle = (!save?'':'save-') + 'style'; 400 401 $elem.attr(saveStyle, $elem.attr(currentStyle)); 402 $elem.attr(currentStyle, ''); 403 }; 404 405 this.prevWidth = null; 406 this.resizeLayers = function() { 407 408 // Only on changes of the width. 409 var newWidth = this.root.width(); 410 if ( this.prevWidth == newWidth ) { return; } 411 this.prevWidth = newWidth; 412 413 // Each Layer 414 $.each(self.layer, function(index) 415 { 416 var currentLayer = this; 417 this.elem.css('height', ''); // Reset for new cycle 418 419 var setHeight = function() { 420 var layerHeight = 0; 421 $.each(currentLayer.items, function(){ 422 this.elem.css('height', ''); // Reset for new cycle 423 layerHeight = Math.max( layerHeight, this.elem.height() ); 424 }); 425 426 currentLayer.elem.height(layerHeight); 427 }; 428 429 var checkImageLoadedStatus = function() { 430 // check load status of images 431 var loaded = true; 432 $.each(currentLayer.items, function(){ 433 this.elem.find('img').each(function(){ 434 loaded = loaded && (this.loaded || self.IsImageOk(this)); 435 }); 436 }); 437 438 if ( !loaded ) { 439 window.setTimeout( checkImageLoadedStatus, 100 ); 440 } else { 441 setHeight(); 442 } 443 }; 444 445 checkImageLoadedStatus(); 446 }); 447 }; 448 449 this.IsImageOk = function(img) { 450 // http://stackoverflow.com/questions/1977871/check-if-an-image-is-loaded-no-errors-in-javascript 451 // During the onload event, IE correctly identifies any images that 452 // weren’t downloaded as not complete. Others should too. Gecko-based 453 // browsers act like NS4 in that they report this incorrectly. 454 if (!img.complete) { 455 return false; 456 } 457 458 // However, they do have two very useful properties: naturalWidth and 459 // naturalHeight. These give the true size of the image. If it failed 460 // to load, either of these should be zero. 461 462 if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) { 463 return false; 464 } 465 466 // No other way of checking: assume it’s ok. 467 return true; 468 }; 469 470 this.activationStatus = function(activate) { 471 472 if ( ! self.layerList ) { 473 return; 474 } 475 476 self.togglePlayState( activate ); 477 478 // Layer selection list 479 self.layerList.toggle( activate ); 480 self.root.removeClass( (activate?'no':'') + 'scripting').addClass( (!activate?'no':'') + 'scripting'); 481 482 // Each Layer 483 self.offsetWidth = activate ? 0 : self.offsetWidth; 484 $(self.layer).each(function(index) 485 { 486 self.toggleCSSSaveState( this.elem, !activate ); 487 $(this.items).each(function(){ 488 self.toggleCSSSaveState( this.elem, !activate ); 489 }); 490 491 if ( activate ) { 492 if ( self.offsetWidth == 0 ) { 493 self.offsetWidth = $(this.elem).width(); // Offset from the first layer. 494 } 495 self.resetLayer(index, true); 496 } 497 }); 498 499 self.resizeLayers(); 500 }; 501 }; 502 503 var initialize = function() { 504 $('div.layeranimation').each(function(){ 505 (new layeranimation($(this))).init(); 506 }).on('layeranimation.activate', function(e, activate){ 507 this.layerAnimation.activationStatus(activate); 508 }).on('layeranimation.resize', function(e, activate){ 509 this.layerAnimation.resizeLayers(); 510 }); 511 }; 512 513 // On load 514 $(initialize); 515 516})(jQuery); 517