PROBLEM: ProgressiveImageSequence Breaks in chrome but not other browsers
BACKGROUND: I am building an interactive web page that takes a jpg sequence and plays through it as the user scroll up or down the page. the page that inspired this and that I am using to base my code off of is http://360langstrasse.srf.ch/page/. using 360lang's beautifully built ProgressiveImageSequence Created by Hinderling Volkart AG. There is a turtorial that goes over the basics of it, Though the demos they give dont respond to touch screens and if the jpg sequence is large enough will begin to break in browsers, specially chrome.
The link to my webpage is http://blackbirdstudio5.com/videoscroll2/
DETAILS: I have gotten the page to work on touch screens and all browsers except for CHROME. (I believe it works on IE but my testing has been limited). If you open my webpage the page will work for a bit and then about half way down will crash and I will get the "AWW SNAP" message from chrome. If you scroll SLOWLY down the page, you will see this happen.(emphasize slowly because it seems to break faster when you scroll slow)(Also the text boxes will stick in firefox if used enough but I believe that because they overlap. But if not I would love to know the answer)
HELP: Can someone please help me fix this page so it works in Chrome.
- (not important: I would also like to have a loading overlay page till 10% of the image sequence is loaded)
- (not important: Fire fox seems to freeze some of the text divs. i believe its because they overlap but if its because another reason it would be great to know)
I am mediocre at best with jquery so please act like im a newbie and explain your answers.
NOTES:
- If I take out all text the page will last longer but will still
- break If I take out all text and replace it with images the page will last longer but still break
- In reaserching people said chrome has an issue with cache-ing ajax requests
- there is allot of code here that I know I dont need but every time i try to take it away it breaks my sequence. I would love to have the jquery bare bones.
CODE:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=780,user-scalable=no"/>
<title>video scroll</title>
<meta name="viewport" content="width=1024,user-scalable=no"/>
<link rel="stylesheet" href="css/makingcigar.css" type="text/css">
<script src="js/jquery-1.11.1.min.js"></script>
<script src="js/modernizr.js"></script>
</head>
<div id="main" style="height: 10000px;">
<div class="navigation">
<ul>
<li><a href="#cigar">Art Form</a></li>
<li><a href="#nursery">Start Small</a></li>
<li><a href="#nursery2">Nursery</a></li>
<li><a href="#nursery3">Nursery Cont.</a></li>
<li><a href="#fields1">Fields</a></li>
<li><a href="#fields2">Wrapper, Binder, Filler</a></li>
</ul>
</div>
<div class="street-view"><img src="making_images/vid-0001.jpg"></div>
<div id="cigar" class="hotspot left" data-day="14" data-night="16" data-speed="2.8">
<div class="content">
<div class="title">
<h3>Cigar as an Art Form</h3>
</div>
<div class="description">
<p>Great cigars are more...</p>
<h6>DISCOVER HOW CIGARS ARE CREATED</h6>
<div class="clearfix"> </div>
<h4>SCROLL TO DISCOVER MORE</h4>
</div>
</div>
</div>
<div id="nursery" class="hotspot right" data-day="16.8" data-night="17.2" data-speed="1.8">
<div class="content">
<div class="title">
<h3>Nursery</h3>
<h5>Think Big. Start Small.</h5>
<div class="divider"></div>
</div>
<div class="description">
<p>All great ideas start out small...</p>
</div>
</div>
</div>
<div id="nursery2" class="hotspot left" data-day="19" data-night="18.5" data-speed="2">
<div class="content">
<div class="title">
<h3>NURSERY</h3>
<div class="divider"></div>
</div>
<div class="description">
<p>At our main ...</p>
</div>
</div>
</div>
<div id="nursery3" class="hotspot right" data-day="21.15" data-night="21" data-speed="3">
<div class="content">
<div class="title">
<h3>NURSERY</h3>
<h5>Only the best. No exceptions.</h5>
<div class="divider"></div>
</div>
<div class="description">
<p>Before leaving the mai...</p>
</div>
</div>
</div>
<div id="fields1" class="hotspot left" data-day="25.5" data-night="22.25" data-speed="2.2">
<div class="content">
<div class="title">
<h3>FIELDS</h3>
<h5>From the ground up</h5>
<div class="divider"></div>
</div>
<div class="description">
<p>Prior to each ...</p>
</div>
</div>
</div>
<div id="fields2" class="hotspot right" data-day="28" data-night="24.25" data-speed="2.5">
<div class="content">
<div class="title">
<h3>CIGAR'S CONSTRUCTION </h3>
<h5>Wrapper, Binder, & Filler</h5>
<div class="divider"></div>
</div>
<div class="description">
<p>Our cigars are p... AND A BUNCH MORE OF THESE DESCRIPTION DIVS ALL IN THE SAME FORMAT</p>
</div>
</div>
</div>
</div>
<script src="js/jquery-migrate-1.2.1.min.js"></script>
<script src="js/ProgressiveImageSequence.class.js"></script>
<script>
$(document).ready(function(){
var $doc = $(document);
var $win = $(window);
var isTouch = 'ontouchstart' in window;
var isChrome = navigator.userAgent.indexOf('Chrome') > 0;
// dimensions
var windowHeight, windowWidth;
var fullHeight, scrollHeight;
var bgImgWidth = 512, bgImgHeight = 320;
calculateDimensions();
// states
var isNight = false;
var currentPosition = getScrollTop() / scrollHeight;
var targetPosition = currentPosition;
// collect timeline elements
var $videoImage = $('.street-view > img');
var $allNavAnchors = $('#main .navigation a');
var $timeElements = $('[data-day]');
var timeElements = [];
var hotspots = {};
$timeElements.each(function(){
var $view = $(this);
var id = $view.attr('id');
var elem = new TimeElement(this);
timeElements.push( elem );
if ( id ) hotspots[id] = elem;
// console.log(timeElements);
var offset = $view.offset();
$view.css({position: 'fixed' , top: offset.top });
});
// handle anchor links
$('a[href^="#"]').click(function(event){
event.preventDefault();
var target = $(this).attr('href').substr(1);
console.log(target);
var hotspot = hotspots[target];
if ( hotspot ) {
var pos = hotspot.getPosition();
setScrollTop( pos * scrollHeight );
}
});
function setScrollTop(value) {
$win.scrollTop(value);
}
function getScrollTop() {
return $win.scrollTop() || (document.documentElement && document.documentElement.scrollTop);
}
function calculateDimensions() {
windowWidth = $win.width();
windowHeight = $win.height();
fullHeight = $('#main').height();
scrollHeight = fullHeight - windowHeight;
}
function setTargetPosition( position , immediate ) {
targetPosition = position;
if ( immediate ) currentPosition = targetPosition;
}
function handleResize() {
calculateDimensions();
renderBackgroundImage();
renderTimeline( currentPosition );
renderNavigation();
handleScroll();
}
function handleScroll() {
setTargetPosition( getScrollTop() / scrollHeight );
activateElement( $('.navigation') , targetPosition < 0.001 );
}
// rendering
var scrollActivateTimeout;
function renderTimeline( position ) {
var minY = -500, maxY = windowHeight + 500;
// element position
$.each(timeElements,function(index,element){
var elemPosition = element.getPosition();
var elemY = windowHeight/2 + element.speed * (elemPosition-position) * scrollHeight;
var active = false;
if ( elemY < minY ||elemY > maxY ) {
element.view.css({'visiblity':'none', top: '-1000px','webkitTransform':'none'});
} else {
element.view.css('visiblity','visible');
positionElement(element.view,null,elemY);
if ( elemY < windowHeight/2 ) {
var x = (windowHeight/2 - elemY)/100;
x = x*x * 20;
if ( element.view.hasClass('hotspot') ) {
if ( element.view.hasClass('right') ) {
element.view.css('margin-right',-x);
} else
if ( element.view.hasClass('left') ) {
element.view.css('margin-left',-x);
}
}
} else
if ( element.view.hasClass('hotspot') ) {
element.view.css({'margin-left':0,'margin-right':0});
}
if ( element.view.is('.twitter') ) {
var sinMargin = Math.sin(elemY/300)*100;
element.view.css({'margin-left':sinMargin,'margin-right':sinMargin});
}
active = Math.abs(windowHeight/2 - elemY) < Math.max(windowHeight/5,100);
}
if ( getElementActive(element.view) != active ) {
clearTimeout( element.scrollActivateTimeout );
setElementActive(element.view,active);
function doit() {
activateElement( element.view , active );
}
if ( active ) {
if (active) playSound(element.view.attr('id'));
element.scrollActivateTimeout = setTimeout( doit , 1000 );
} else {
doit();
}
activateElement( element.anchor , active );
}
});
// video
showImage( currentPosition );
}
function renderNavigation() {
var MINGAP = 30;
var $navigation = $('#main > .navigation');
var scrollThumbHeight = Math.max( 30 , (windowHeight/fullHeight)*windowHeight );
var availableHeight = windowHeight - scrollThumbHeight;
var all = [];
// put all hotspots in array and sort by position
$.each(hotspots,function(k,v){ all.push(v); });
all.sort(function(a,b){return a.getPosition()-b.getPosition();});
var y = 0;
$.each(all,function(index,element){
if ( !element.anchor ) return;
var $anchor = $(element.anchor);
var pos = element.getPosition();
y = Math.max( y + MINGAP , pos * availableHeight + scrollThumbHeight/2 );
$anchor.css('top',y);
});
}
function positionElement( elem , x , y ) {
if ( Modernizr.csstransforms ) {
var xpos = ( x === null ? $.data(elem,'x') : x ) || 0;
var ypos = ( y === null ? $.data(elem,'y') : y ) || 0;
$.data(elem,'x',xpos);
$.data(elem,'y',ypos);
}
if ( $.browser.safari) { //&& !isTouch && !isChrome ) {
elem.css({top:-1000,webkitTransform:'translate3d('+(xpos)+'px,'+(ypos+1000)+'px,0px)'});
} else
if ( Modernizr.csstransforms ) {
var transform = 'translate('+(xpos)+'px,'+(ypos+1000)+'px)';
elem.css({
'-webkit-transform':transform,
'-moz-transform':transform,
'-o-transform':transform,
'-ms-transform':transform
});
} else
{
if ( x !== null ) {
elem.css('left',x);
}
if ( y !== null ) {
elem.css('top',y);
}
}
}
function activateElement( elem , active ) {
$.data( elem , 'active' , active );
active ? elem.addClass('active') : elem.removeClass('active');
}
function setElementActive( elem , active ) {
$.data( elem , 'active' , active );
}
function getElementActive( elem ) {
return $.data( elem , 'active' );
}
function renderBackgroundImage(){
// get image container size
var scale = Math.max( windowHeight/bgImgHeight , windowWidth/bgImgWidth );
var width = scale * bgImgWidth , height = scale * bgImgHeight;
var left = (windowWidth-width)/2, top = (windowHeight-height)/2;
if ( ($.browser.safari || isTouch) && !isChrome ) {
var transform = 'translate3d('+[-bgImgWidth/2,-bgImgHeight/2,0].join('px,')+'px) scale3d('+scale+','+scale+',1) translate3d('+[windowWidth/2/scale,windowHeight/2/scale,0].join('px,')+')';
$videoImage
.width(bgImgWidth).height(bgImgHeight)
.css('-webkit-transform',transform)
.css({'position':'fixed', top: 0, left: 0});
} else
if ( Modernizr.csstransforms ) {
console.log('Using 2D transforms');
var transform = 'translate('+[-bgImgWidth/2,-bgImgHeight/2].join('px,')+'px) scale('+scale+') translate('+[windowWidth/2/scale,windowHeight/2/scale].join('px,')+'px)';
$videoImage
.width(bgImgWidth).height(bgImgHeight)
.css({
'-webkit-transform':transform,
'-moz-transform':transform,
'-o-transform':transform,
'-ms-transform':transform
})
.css({'position':'fixed', top: 0, left: 0});
} else {
$videoImage
.width(width).height(height)
.css('position','fixed')
.css('left',left+'px')
.css('top',top+'px');
}
}
// main render loop
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
function animloop(){
requestAnimFrame(animloop);
if ( Math.floor(currentPosition*5000) != Math.floor(targetPosition*5000) ) {
var deaccelerate = Math.max( Math.min( Math.abs(targetPosition-currentPosition)*5000 , 10 ) , 2 );
currentPosition += (targetPosition - currentPosition) / deaccelerate;
renderTimeline(currentPosition);
}
}
animloop();
// video handling
var daySeqLoader = new ProgressiveImageSequence( "making_images/vid-{index}.jpg", 633, {
indexSize: 4,
onProgress: handleLoadProgress,
onComplete: handleLoadComplete,
stopAt: isSlowBrowser() ? (isTouch?4:8) : 1
} );
var imageSeqLoader = daySeqLoader;
var loadCounterForIE = 0; // there seems to be a problem with ie calling the callback several times
imageSeqLoader.loadPosition(currentPosition,function(){
loadCounterForIE++;
if ( loadCounterForIE == 1 ) {
showImage(currentPosition);
imageSeqLoader.load();
imageSeqLoader.load();
imageSeqLoader.load();
imageSeqLoader.load();
}
});
var nightSeqLoader = new ProgressiveImageSequence( "making_images/vid-{index}.jpg", 633, {
indexSize: 3,
onProgress: handleLoadProgress,
onComplete: handleLoadComplete,
stopAt: isSlowBrowser() ? 4 : 1
} );
var currentSrc, currentIndex;
var highresTimeout;
function showImage(position) {
var index = Math.round( currentPosition * (imageSeqLoader.length-1) );
var img = imageSeqLoader.getNearest( index );
var nearestIndex = imageSeqLoader.nearestIndex;
if ( nearestIndex < 0 ) nearestIndex = 0;
var $img = $(img);
var src;
if ( !!img ) {
src = img.src;
if ( src != currentSrc ) {
$videoImage[0].src = src;
currentSrc = src;
}
}
clearTimeout(highresTimeout);
highresTimeout = setTimeout(function(){
if ( !!src ) {
$('#debug').text( nearestIndex + ' / ' + index + ' / ' + (Math.round( index / imageSeqLoader.length * 10000 ) / 100) );
var highSrc = src.split('/xs/').join('/l/');
loadHighres(highSrc);
}
},isSlowBrowser()?500:150);
}
window.switchStreetMode = function() {
switchToMode( isNight ? 'day' : 'night' );
};
window.switchToMode = function( mode ) {
$videoImage.fadeOut(function(){
var prevHotspot, nextHotspot;
var all = [];
// put all hotspots in array and sort by position
$.each(hotspots,function(k,v){ all.push(v); });
all.sort(function(a,b){return a.getPosition()-b.getPosition();});
$.each(all,function(k,v){
if ( v.getPosition() > currentPosition ) {
nextHotspot = v;
prevHotspot = all[k-1];
return false;
}
});
if ( nextHotspot == null ) {
prevHotspot = all[all.length-1];
}
var prevPos = prevHotspot ? prevHotspot.getPosition() : 0;
var nextPos = nextHotspot ? nextHotspot.getPosition() : 1;
var intermediatePosition = (currentPosition-prevPos) / (nextPos-prevPos);
// let's make the switch
isNight = mode == 'night';
$('.toggle[rel="mode"]')[ isNight ? 'addClass' : 'removeClass' ]('active');
prevPos = prevHotspot ? prevHotspot.getPosition() : 0;
nextPos = nextHotspot ? nextHotspot.getPosition() : 1;
targetPosition = currentPosition = intermediatePosition * (nextPos-prevPos) + prevPos;
imageSeqLoader.stop(); imageSeqLoader.reset();
imageSeqLoader = isNight ? nightSeqLoader : daySeqLoader;
var loadCounterForIE = 0; // there seems to be a problem with ie calling the callback several times
imageSeqLoader.loadPosition( currentPosition , function() {
loadCounterForIE++;
if ( loadCounterForIE == 1 ) {
setTimeout(function(){
imageSeqLoader.load();
imageSeqLoader.load();
imageSeqLoader.load();
imageSeqLoader.load();
},10);
$(window).scrollTop(targetPosition*scrollHeight);
renderNavigation();
renderTimeline( currentPosition );
showImage( currentPosition );
$videoImage.fadeIn();
}
});
});
};
var loadHighresCounter = 0;
function loadHighres(src) {
var videoImage = $videoImage[0];
videoImage.src = src;
}
$('body').append('<div id="loading-bar" style="position:fixed; bottom:0; left:0; background-color: #DF0012; background-color: rgba(223,0,18,0.5); height: 1px;"></div>');
function handleLoadProgress() {
var progress = imageSeqLoader.getLoadProgress() * 100;
$('#loading-bar').css({width:progress+'%',opacity:1});
}
function handleLoadComplete() {
$('#loading-bar').css({width:'100%',opacity:0});
}
$win.resize( handleResize );
$win.scroll( handleScroll );
handleResize();
// helper classes
$('.sound .toggle').click(function(event){
event.preventDefault();
var $toggle = $(this);
var isActive = $toggle.hasClass('active');
if ( isActive ) {
$toggle.removeClass('active');
} else {
$toggle.addClass('active');
}
});
$('.night a').click(function(event){
event.preventDefault();
switchStreetMode();
});
function TimeElement( view , options ) {
options = options || {};
var $view = $(view);
this.id = $view.attr('id');
this.view = $view;
this.anchor = $allNavAnchors.filter('[href="#'+$view.attr('id')+'"]');
this.anchor = this.anchor.closest('li');
this.getPosition = function() { return isNight? this.nightPosition : this.dayPosition; };
this.dayPosition = options.dayPosition || Number( $view.attr('data-day')/100 );
this.nightPosition = options.nightPosition || Number( $view.attr('data-night')/100 );
this.speed = options.speed || Number( $view.attr('data-speed') ) || 1;
this.align = options.align || $view.attr('data-align') || 'left';
}
function easeCos(t) {
return Math.cos( (x*Math.PI+Math.PI)+1 ) / 2;
}
function isSlowBrowser() {
return isTouch || ($.browser.msie && Number($.browser.version) <= 8) ? true : false;
}
// sound control
var soundMuted = false;
(function(){
var ambi = document.getElementById('ambi-audio');
if ( ambi && ambi.play ) {
$('.mute').show();
$('.mute > .toggle').click(function(){
soundMuted = ambi.muted = !ambi.muted;
$(this)[ ambi.muted ? 'addClass' : 'removeClass' ]('active');
$(this).parent()[ ambi.muted ? 'addClass' : 'removeClass' ]('active');
});
}
})();
function playSound( name ) {
var snd = document.getElementById(name+'-audio');
if ( !soundMuted && snd && snd.play && Math.random() < 0.3 ) {
if ( snd.currentTime == 0 || snd.ended ) {
snd.volume = 0.4;
snd.currentTime = 0;
snd.play();
}
}
}
function addSounds( sounds ) {
var $body = $('body');
$.each( sounds , function(i,name) {
var $audio = $('<audio id="'+name+'-audio" preload="auto" autobuffer><source src="/img/'+name+'.mp3"><source src="/img/'+name+'.ogg"></audio>').hide();
$body.append( $audio );
});
}
setTimeout(function(){
addSounds(['host','zkft','kita','hohl','zapo']);
},1000);
// touch override
if ( isTouch ) {
(function(){
$('#main').css('height',1);
var scrollPos = 0;
var MAXSCROLL = 10000;
var oldCalculateDimensions = calculateDimensions;
calculateDimensions = function() {
oldCalculateDimensions();
scrollHeight = MAXSCROLL - windowHeight;
};
var oldGetScrollTop = getScrollTop;
getScrollTop = function() {
return scrollPos;
};
var oldSetScrollTop = setScrollTop;
setScrollTop = function(value) {
scrollPos = value;
dispatchScroll();
};
function dispatchScroll() {
targetPosition = scrollPos / scrollHeight;
}
var d = document;
var touchMoved, touchDown, touchBeginPosition, isLinkTouch;
function onTouchStart(event) {
var isNavigation = $(event.target).filter('a');
if ( isNavigation.length ) {
isNavigation = isNavigation.parents('.navigation').length >= 1;
return;
}
if ( $(event.target).parents('a').length == 0 ) {
event.preventDefault();
}
touchDown = true;
var touch = event.touches[0];
touchX = touch.clientX;
touchY = touch.clientY;
touchBeginPosition = { x: touchX , y: touchY , scroll: scrollPos };
d.addEventListener('touchmove', onTouchMove, false);
d.addEventListener('touchend', onTouchEnd, false);
}
function onTouchMove(event) {
event.preventDefault();
var touch = event.touches[0];
touchX = touch.clientX;
touchY = touch.clientY;
var dy = (touchY-touchBeginPosition.y);
if ( Math.abs(dy) > 3 ) {
touchMoved = true;
}
scrollPos = touchBeginPosition.scroll - dy * 2;
scrollPos = Math.min( MAXSCROLL , Math.max( 0 , scrollPos ) );
dispatchScroll();
}
function onTouchEnd(event) {
if ( touchMoved ) {
event.preventDefault();
}
d.removeEventListener('touchmove', onTouchMove, false);
d.removeEventListener('touchend', onTouchEnd, false);
touchDown = false;
}
d.addEventListener('touchstart', onTouchStart, false);
//d.getElementsByClassName('street-view')[0].addEventListener('touchstart', onTouchStart, false);
})();
}
});
</script>
</body></html>