It seems that I lost myself between cancelAnimationFrame and clearTimeout. Don't know how to stop Snake game. Here is snippet of my code that start animation:
window.addEventListener( "load", function gameLoop() {
globalTimer = setTimeout( function() {
snakeObj.update();
requestAnimationFrame( gameLoop );
}, 100 );
});
in this way I tried to stop my game:
if ( parseInt(this.snakeHead.style.top) == fieldObj.h ||
parseInt(this.snakeHead.style.left) == fieldObj.w ) {
gameObj.stopGame();// stop game message
clearTimeout(globalTimer);
}
but it doesn't work - stop game message appears, but animation continuing.
here all my code:
// field object
var globalTimer;
var fieldObj = {
field: document.getElementById( "field" ),
w: 480,
h: 580
},
gameObj = {
pastCoord: [],
getRandomCoord: function( num ) { // 20 is width of one body segment
return Math.round( Math.floor(( Math.random() * num)) / 20 ) * 20;
},
createSnakeTarget: function() {
var t = document.createElement( "div" );
t.id = "snake-target";
t.style.top = this.getRandomCoord( fieldObj.h ) + "px";
t.style.left = this.getRandomCoord( fieldObj.w ) + "px";
fieldObj.field.appendChild( t );
},
stopGame: function() {
var stopMessage = document.createElement("div");
stopMessage.className = "stop-message";
stopMessage.style.background = "white";
fieldObj.field.appendChild( stopMessage );
//TODO: write message to stopGame
}
};
gameObj.createSnakeTarget();
// snake object
snakeObj = {
snakeHead: document.getElementById("head"),
snakeBody: document.getElementsByClassName( "snake-body" ),// there must be one element
p: {
x: 0, // position x
y: 0 // position y
},
v: {
x: 20, // velocity ( one loop move one unit of snake body)
y: 20
},
keys: {
up: null,
l: null,
r: null,
down: null
},
stepInSnakeBody: 0,// go through snakeBody
stepInPastCoord: 0,// go through pastCoord
addBodySegment: function() {
var seg = document.createElement( "div" );
seg.className = "snake-body";
fieldObj.field.appendChild( seg );
seg.style.top = this.p.x + "px";// receive current position
seg.style.left = this.p.y + "px";
},
update: function() {
var snakeTarget = document.getElementById("snake-target");
if ( this.keys.down ) {
this.p.x += this.v.x;
} else if ( this.keys.up ) {
this.p.x -= this.v.x;
} else if ( this.keys.r ) {
this.p.y += this.v.y;
}else if ( this.keys.l ) {
this.p.y -= this.v.y;
}
this.snakeHead.style.top = this.p.x + "px";
this.snakeHead.style.left = this.p.y + "px";
gameObj.pastCoord.push([this.p.x, this.p.y]);// create and push coord of snake head
//every step index in snakeBody receive coords from pastCoord
this.snakeBody[this.stepInSnakeBody].style.top = gameObj.pastCoord[this.stepInPastCoord][0] + "px";
this.snakeBody[this.stepInSnakeBody].style.left = gameObj.pastCoord[this.stepInPastCoord][1] + "px";
this.stepInSnakeBody++; // increment index every step
this.stepInPastCoord++;
if ( this.stepInSnakeBody === this.snakeBody.length ) {
this.stepInSnakeBody = 0; // when stepInSnakeBody equal length of snake go to zero
//and apply coords
}
// detect collision with target
if ( this.snakeHead.style.top === snakeTarget.style.top &&
this.snakeHead.style.left === snakeTarget.style.left ) {
fieldObj.field.removeChild( snakeTarget );
gameObj.createSnakeTarget();
snakeObj.addBodySegment();
}
if ( parseInt(this.snakeHead.style.top) == fieldObj.h ||
parseInt(this.snakeHead.style.left) == fieldObj.w ) {
gameObj.stopGame();
clearTimeout(globalTimer);
}
}
};
// Crome works only with keydown and keyup
window.addEventListener('keydown', function() {
// before changing direction you have to put previous direction to false
if ( event.keyCode == 38 ) {
snakeObj.keys.up = true;
snakeObj.keys.down = false;
} else if ( event.keyCode == 40 ) {
snakeObj.keys.down = true;
snakeObj.keys.up = false;
} else if ( event.keyCode == 39 ) {
snakeObj.keys.r = true;
snakeObj.keys.up = false;
snakeObj.keys.down = false;
} else if ( event.keyCode == 37 ) {
snakeObj.keys.l = true;
snakeObj.keys.r = false;
snakeObj.keys.up = false;
snakeObj.keys.down = false;
}
}, false);
//TODO: add event hendler to click to some button
window.addEventListener( "load", function gameLoop() {
globalTimer = setTimeout( function() {
snakeObj.update();
requestAnimationFrame( gameLoop );
}, 100 );
});
here is codepen (works in CHROME only ) http://codepen.io/Kuzyo/pen/pamzC
Thanks for the help.
You need to call cancelAnimationFrame.
However you need to make sure you call requestAnimationFrame before update. Currently you're calling stopGame, but then after stopGame/update finishes, requestAnimationFrame schedules another loop so even if your stopGame calls cancelAnimationFrame it will not stop the animation.
An alternative is to use a boolean flag that you check in your gameLoop function.
Related
I have modified DragControls.js by adding a constraint to move only the line on the y axis.
The line I use is this:
material = new THREE.LineBasicMaterial( { color: 0xFF0000 } );
geometry.vertices.push(new THREE.Vector3( 0, 0, 0) );
geometry.vertices.push(new THREE.Vector3( 10, 0, 0) );
scene.add( redline );
dragControls = new THREE.DragControls( objects, camera, renderer.domElement );
Here is my modification of Dragcontrols.js
I have added constraints to the THREE.Dragcontrols function.
this.constrains = function(xyz) {
if (xyz === undefined)
xyz = 'xyz';
moveX = moveY = moveZ = false;
if (xyz.indexOf('x') > -1) {
moveX = true;
}
if (xyz.indexOf('y') > -1) {
moveY = true;
}
if (xyz.indexOf('z') > -1) {
moveZ = true;
}
return this;
};
That's how I apply it in the onDocumentMouseMove(event):
if ( _selected && scope.enabled ) {
if (event.altKey === true) {
rotationDrag = true;
}
//TODO: somewhere here should be a rotationDrag check and if it's true
than rotate the line instead of moving it
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
/**
* Constrain feature added
*/
_intersection.sub( _offset );
//_selected.position.copy( _intersection.sub( _offset ) );
if (!rotationDrag) {
if (moveX) _selected.position.x = _intersection.x;
if (moveY) _selected.position.y = _intersection.y;
if (moveZ) _selected.position.z = _intersection.z;
} else {
debugger;
}
}
scope.dispatchEvent( { type: 'drag', object: _selected } );
return;
}
Where the debugger is I want to achive that if altKey is pressed and the mouse moved, the left end of the line is moving on the y axis while the right end point stays in the X and Y coordinates.
Basically the line rotates around its endpoint like a clock's hand.
Any idea how to achive this?
Well the answer happens to be pretty simple, only need to figure out, how to calculate angle and directions.
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
/**
* Constrain feature added
*/
_intersection.sub( _offset );
//_selected.position.copy( _intersection.sub( _offset ) );
if (!rotationDrag) {
if (moveX) _selected.position.x = _intersection.x;
if (moveY) _selected.position.y = _intersection.y;
if (moveZ) _selected.position.z = _intersection.z;
} else {
_selected.rotateZ();
}
}
I have a website that uses smooth scroll which works great.. But once I added the following code:
var $ = jQuery.noConflict();
$(document).ready(function() {
$(function() {
var $ticker = $('#news-ticker'),
$first = $('.news-ticket-class li:first-child', $ticker);
// put an empty space between each letter so we can
// use break word
$('.news-ticket-class li', $ticker).each(function() {
var $this = $(this),
text = $this.text();
$this.html(text.split('').join(''));
});
// begin the animation
function tick($el) {
$el.addClass('tick')
.one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function() {
$el.removeClass('tick');
var $next = $el.next('li');
$next = $next.length > 0 ? $next : $first;
tick($next);
});
}
tick($first);
});
});
It breaks the smooth scroll. I have tried using the noconflict and that doesn't help as you can see.
The template I use is here that has the smooth scrolling option.
I am stuck with either the above code or my menus working. If you have any other suggestions that mimic someone typing, like this website, please send over my way.
EDIT: This is the smooth scroll script:
//
// SmoothScroll for websites v1.4.0 (Balazs Galambosi)
// http://www.smoothscroll.net/
//
// Licensed under the terms of the MIT license.
//
// You may use it in your theme if you credit me.
// It is also free to use on any individual website.
//
// Exception:
// The only restriction is to not publish any
// extension for browsers or native application
// without getting a written permission first.
//
(function () {
// Scroll Variables (tweakable)
var defaultOptions = {
// Scrolling Core
frameRate : 150, // [Hz]
animationTime : 500, // [ms]
stepSize : 100, // [px]
// Pulse (less tweakable)
// ratio of "tail" to "acceleration"
pulseAlgorithm : true,
pulseScale : 4,
pulseNormalize : 1,
// Acceleration
accelerationDelta : 50, // 50
accelerationMax : 3, // 3
// Keyboard Settings
keyboardSupport : true, // option
arrowScroll : 50, // [px]
// Other
touchpadSupport : false, // ignore touchpad by default
fixedBackground : true,
excluded : ''
};
var options = defaultOptions;
// Other Variables
var isExcluded = false;
var isFrame = false;
var direction = { x: 0, y: 0 };
var initDone = false;
var root = document.documentElement;
var activeElement;
var observer;
var refreshSize;
var deltaBuffer = [];
var isMac = /^Mac/.test(navigator.platform);
var key = { left: 37, up: 38, right: 39, down: 40, spacebar: 32,
pageup: 33, pagedown: 34, end: 35, home: 36 };
/***********************************************
* INITIALIZE
***********************************************/
/**
* Tests if smooth scrolling is allowed. Shuts down everything if not.
*/
function initTest() {
if (options.keyboardSupport) {
addEvent('keydown', keydown);
}
}
/**
* Sets up scrolls array, determines if frames are involved.
*/
function init() {
if (initDone || !document.body) return;
initDone = true;
var body = document.body;
var html = document.documentElement;
var windowHeight = window.innerHeight;
var scrollHeight = body.scrollHeight;
// check compat mode for root element
root = (document.compatMode.indexOf('CSS') >= 0) ? html : body;
activeElement = body;
initTest();
// Checks if this script is running in a frame
if (top != self) {
isFrame = true;
}
/**
* Please duplicate this radar for a Safari fix!
* rdar://22376037
* https://openradar.appspot.com/radar?id=4965070979203072
*
* Only applies to Safari now, Chrome fixed it in v45:
* This fixes a bug where the areas left and right to
* the content does not trigger the onmousewheel event
* on some pages. e.g.: html, body { height: 100% }
*/
else if (scrollHeight > windowHeight &&
(body.offsetHeight <= windowHeight ||
html.offsetHeight <= windowHeight)) {
var fullPageElem = document.createElement('div');
fullPageElem.style.cssText = 'position:absolute; z-index:-10000; ' +
'top:0; left:0; right:0; height:' +
root.scrollHeight + 'px';
document.body.appendChild(fullPageElem);
// DOM changed (throttled) to fix height
var pendingRefresh;
refreshSize = function () {
if (pendingRefresh) return; // could also be: clearTimeout(pendingRefresh);
pendingRefresh = setTimeout(function () {
if (isExcluded) return; // could be running after cleanup
fullPageElem.style.height = '0';
fullPageElem.style.height = root.scrollHeight + 'px';
pendingRefresh = null;
}, 500); // act rarely to stay fast
};
setTimeout(refreshSize, 10);
addEvent('resize', refreshSize);
// TODO: attributeFilter?
var config = {
attributes: true,
childList: true,
characterData: false
// subtree: true
};
observer = new MutationObserver(refreshSize);
observer.observe(body, config);
if (root.offsetHeight <= windowHeight) {
var clearfix = document.createElement('div');
clearfix.style.clear = 'both';
body.appendChild(clearfix);
}
}
// disable fixed background
if (!options.fixedBackground && !isExcluded) {
body.style.backgroundAttachment = 'scroll';
html.style.backgroundAttachment = 'scroll';
}
}
/**
* Removes event listeners and other traces left on the page.
*/
function cleanup() {
observer && observer.disconnect();
removeEvent(wheelEvent, wheel);
removeEvent('mousedown', mousedown);
removeEvent('keydown', keydown);
removeEvent('resize', refreshSize);
removeEvent('load', init);
}
/************************************************
* SCROLLING
************************************************/
var que = [];
var pending = false;
var lastScroll = Date.now();
/**
* Pushes scroll actions to the scrolling queue.
*/
function scrollArray(elem, left, top) {
directionCheck(left, top);
if (options.accelerationMax != 1) {
var now = Date.now();
var elapsed = now - lastScroll;
if (elapsed < options.accelerationDelta) {
var factor = (1 + (50 / elapsed)) / 2;
if (factor > 1) {
factor = Math.min(factor, options.accelerationMax);
left *= factor;
top *= factor;
}
}
lastScroll = Date.now();
}
// push a scroll command
que.push({
x: left,
y: top,
lastX: (left < 0) ? 0.99 : -0.99,
lastY: (top < 0) ? 0.99 : -0.99,
start: Date.now()
});
// don't act if there's a pending queue
if (pending) {
return;
}
var scrollWindow = (elem === document.body);
var step = function (time) {
var now = Date.now();
var scrollX = 0;
var scrollY = 0;
for (var i = 0; i < que.length; i++) {
var item = que[i];
var elapsed = now - item.start;
var finished = (elapsed >= options.animationTime);
// scroll position: [0, 1]
var position = (finished) ? 1 : elapsed / options.animationTime;
// easing [optional]
if (options.pulseAlgorithm) {
position = pulse(position);
}
// only need the difference
var x = (item.x * position - item.lastX) >> 0;
var y = (item.y * position - item.lastY) >> 0;
// add this to the total scrolling
scrollX += x;
scrollY += y;
// update last values
item.lastX += x;
item.lastY += y;
// delete and step back if it's over
if (finished) {
que.splice(i, 1); i--;
}
}
// scroll left and top
if (scrollWindow) {
window.scrollBy(scrollX, scrollY);
}
else {
if (scrollX) elem.scrollLeft += scrollX;
if (scrollY) elem.scrollTop += scrollY;
}
// clean up if there's nothing left to do
if (!left && !top) {
que = [];
}
if (que.length) {
requestFrame(step, elem, (1000 / options.frameRate + 1));
} else {
pending = false;
}
};
// start a new queue of actions
requestFrame(step, elem, 0);
pending = true;
}
/***********************************************
* EVENTS
***********************************************/
/**
* Mouse wheel handler.
* #param {Object} event
*/
function wheel(event) {
if (!initDone) {
init();
}
var target = event.target;
var overflowing = overflowingAncestor(target);
// use default if there's no overflowing
// element or default action is prevented
// or it's a zooming event with CTRL
if (!overflowing || event.defaultPrevented || event.ctrlKey) {
return true;
}
// leave embedded content alone (flash & pdf)
if (isNodeName(activeElement, 'embed') ||
(isNodeName(target, 'embed') && /\.pdf/i.test(target.src)) ||
isNodeName(activeElement, 'object')) {
return true;
}
var deltaX = -event.wheelDeltaX || event.deltaX || 0;
var deltaY = -event.wheelDeltaY || event.deltaY || 0;
if (isMac) {
if (event.wheelDeltaX && isDivisible(event.wheelDeltaX, 120)) {
deltaX = -120 * (event.wheelDeltaX / Math.abs(event.wheelDeltaX));
}
if (event.wheelDeltaY && isDivisible(event.wheelDeltaY, 120)) {
deltaY = -120 * (event.wheelDeltaY / Math.abs(event.wheelDeltaY));
}
}
// use wheelDelta if deltaX/Y is not available
if (!deltaX && !deltaY) {
deltaY = -event.wheelDelta || 0;
}
// line based scrolling (Firefox mostly)
if (event.deltaMode === 1) {
deltaX *= 40;
deltaY *= 40;
}
// check if it's a touchpad scroll that should be ignored
if (!options.touchpadSupport && isTouchpad(deltaY)) {
return true;
}
// scale by step size
// delta is 120 most of the time
// synaptics seems to send 1 sometimes
if (Math.abs(deltaX) > 1.2) {
deltaX *= options.stepSize / 120;
}
if (Math.abs(deltaY) > 1.2) {
deltaY *= options.stepSize / 120;
}
scrollArray(overflowing, deltaX, deltaY);
event.preventDefault();
scheduleClearCache();
}
/**
* Keydown event handler.
* #param {Object} event
*/
function keydown(event) {
var target = event.target;
var modifier = event.ctrlKey || event.altKey || event.metaKey ||
(event.shiftKey && event.keyCode !== key.spacebar);
// our own tracked active element could've been removed from the DOM
if (!document.body.contains(activeElement)) {
activeElement = document.activeElement;
}
// do nothing if user is editing text
// or using a modifier key (except shift)
// or in a dropdown
// or inside interactive elements
var inputNodeNames = /^(textarea|select|embed|object)$/i;
var buttonTypes = /^(button|submit|radio|checkbox|file|color|image)$/i;
if ( inputNodeNames.test(target.nodeName) ||
isNodeName(target, 'input') && !buttonTypes.test(target.type) ||
isNodeName(activeElement, 'video') ||
isInsideYoutubeVideo(event) ||
target.isContentEditable ||
event.defaultPrevented ||
modifier ) {
return true;
}
// spacebar should trigger button press
if ((isNodeName(target, 'button') ||
isNodeName(target, 'input') && buttonTypes.test(target.type)) &&
event.keyCode === key.spacebar) {
return true;
}
var shift, x = 0, y = 0;
var elem = overflowingAncestor(activeElement);
var clientHeight = elem.clientHeight;
if (elem == document.body) {
clientHeight = window.innerHeight;
}
switch (event.keyCode) {
case key.up:
y = -options.arrowScroll;
break;
case key.down:
y = options.arrowScroll;
break;
case key.spacebar: // (+ shift)
shift = event.shiftKey ? 1 : -1;
y = -shift * clientHeight * 0.9;
break;
case key.pageup:
y = -clientHeight * 0.9;
break;
case key.pagedown:
y = clientHeight * 0.9;
break;
case key.home:
y = -elem.scrollTop;
break;
case key.end:
var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
y = (damt > 0) ? damt+10 : 0;
break;
case key.left:
x = -options.arrowScroll;
break;
case key.right:
x = options.arrowScroll;
break;
default:
return true; // a key we don't care about
}
scrollArray(elem, x, y);
event.preventDefault();
scheduleClearCache();
}
/**
* Mousedown event only for updating activeElement
*/
function mousedown(event) {
activeElement = event.target;
}
/***********************************************
* OVERFLOW
***********************************************/
var uniqueID = (function () {
var i = 0;
return function (el) {
return el.uniqueID || (el.uniqueID = i++);
};
})();
var cache = {}; // cleared out after a scrolling session
var clearCacheTimer;
//setInterval(function () { cache = {}; }, 10 * 1000);
function scheduleClearCache() {
clearTimeout(clearCacheTimer);
clearCacheTimer = setInterval(function () { cache = {}; }, 1*1000);
}
function setCache(elems, overflowing) {
for (var i = elems.length; i--;)
cache[uniqueID(elems[i])] = overflowing;
return overflowing;
}
// (body) (root)
// | hidden | visible | scroll | auto |
// hidden | no | no | YES | YES |
// visible | no | YES | YES | YES |
// scroll | no | YES | YES | YES |
// auto | no | YES | YES | YES |
function overflowingAncestor(el) {
var elems = [];
var body = document.body;
var rootScrollHeight = root.scrollHeight;
do {
var cached = cache[uniqueID(el)];
if (cached) {
return setCache(elems, cached);
}
elems.push(el);
if (rootScrollHeight === el.scrollHeight) {
var topOverflowsNotHidden = overflowNotHidden(root) && overflowNotHidden(body);
var isOverflowCSS = topOverflowsNotHidden || overflowAutoOrScroll(root);
if (isFrame && isContentOverflowing(root) ||
!isFrame && isOverflowCSS) {
return setCache(elems, getScrollRoot());
}
} else if (isContentOverflowing(el) && overflowAutoOrScroll(el)) {
return setCache(elems, el);
}
} while (el = el.parentElement);
}
function isContentOverflowing(el) {
return (el.clientHeight + 10 < el.scrollHeight);
}
// typically for <body> and <html>
function overflowNotHidden(el) {
var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
return (overflow !== 'hidden');
}
// for all other elements
function overflowAutoOrScroll(el) {
var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
return (overflow === 'scroll' || overflow === 'auto');
}
/***********************************************
* HELPERS
***********************************************/
function addEvent(type, fn) {
window.addEventListener(type, fn, false);
}
function removeEvent(type, fn) {
window.removeEventListener(type, fn, false);
}
function isNodeName(el, tag) {
return (el.nodeName||'').toLowerCase() === tag.toLowerCase();
}
function directionCheck(x, y) {
x = (x > 0) ? 1 : -1;
y = (y > 0) ? 1 : -1;
if (direction.x !== x || direction.y !== y) {
direction.x = x;
direction.y = y;
que = [];
lastScroll = 0;
}
}
var deltaBufferTimer;
if (window.localStorage && localStorage.SS_deltaBuffer) {
deltaBuffer = localStorage.SS_deltaBuffer.split(',');
}
function isTouchpad(deltaY) {
if (!deltaY) return;
if (!deltaBuffer.length) {
deltaBuffer = [deltaY, deltaY, deltaY];
}
deltaY = Math.abs(deltaY)
deltaBuffer.push(deltaY);
deltaBuffer.shift();
clearTimeout(deltaBufferTimer);
deltaBufferTimer = setTimeout(function () {
if (window.localStorage) {
localStorage.SS_deltaBuffer = deltaBuffer.join(',');
}
}, 1000);
return !allDeltasDivisableBy(120) && !allDeltasDivisableBy(100);
}
function isDivisible(n, divisor) {
return (Math.floor(n / divisor) == n / divisor);
}
function allDeltasDivisableBy(divisor) {
return (isDivisible(deltaBuffer[0], divisor) &&
isDivisible(deltaBuffer[1], divisor) &&
isDivisible(deltaBuffer[2], divisor));
}
function isInsideYoutubeVideo(event) {
var elem = event.target;
var isControl = false;
if (document.URL.indexOf ('www.youtube.com/watch') != -1) {
do {
isControl = (elem.classList &&
elem.classList.contains('html5-video-controls'));
if (isControl) break;
} while (elem = elem.parentNode);
}
return isControl;
}
var requestFrame = (function () {
return (window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback, element, delay) {
window.setTimeout(callback, delay || (1000/60));
});
})();
var MutationObserver = (window.MutationObserver ||
window.WebKitMutationObserver ||
window.MozMutationObserver);
var getScrollRoot = (function() {
var SCROLL_ROOT;
return function() {
if (!SCROLL_ROOT) {
var dummy = document.createElement('div');
dummy.style.cssText = 'height:10000px;width:1px;';
document.body.appendChild(dummy);
var bodyScrollTop = document.body.scrollTop;
var docElScrollTop = document.documentElement.scrollTop;
window.scrollBy(0, 3);
if (document.body.scrollTop != bodyScrollTop)
(SCROLL_ROOT = document.body);
else
(SCROLL_ROOT = document.documentElement);
window.scrollBy(0, -3);
document.body.removeChild(dummy);
}
return SCROLL_ROOT;
};
})();
/***********************************************
* PULSE (by Michael Herf)
***********************************************/
/**
* Viscous fluid with a pulse for part and decay for the rest.
* - Applies a fixed force over an interval (a damped acceleration), and
* - Lets the exponential bleed away the velocity over a longer interval
* - Michael Herf, http://stereopsis.com/stopping/
*/
function pulse_(x) {
var val, start, expx;
// test
x = x * options.pulseScale;
if (x < 1) { // acceleartion
val = x - (1 - Math.exp(-x));
} else { // tail
// the previous animation ended here:
start = Math.exp(-1);
// simple viscous drag
x -= 1;
expx = 1 - Math.exp(-x);
val = start + (expx * (1 - start));
}
return val * options.pulseNormalize;
}
function pulse(x) {
if (x >= 1) return 1;
if (x <= 0) return 0;
if (options.pulseNormalize == 1) {
options.pulseNormalize /= pulse_(1);
}
return pulse_(x);
}
/***********************************************
* FIRST RUN
***********************************************/
var userAgent = window.navigator.userAgent;
var isEdge = /Edge/.test(userAgent); // thank you MS
var isChrome = /chrome/i.test(userAgent) && !isEdge;
var isSafari = /safari/i.test(userAgent) && !isEdge;
var isMobile = /mobile/i.test(userAgent);
var isIEWin7 = /Windows NT 6.1/i.test(userAgent) && /rv:11/i.test(userAgent);
var isEnabledForBrowser = (isChrome || isSafari || isIEWin7) && !isMobile;
var wheelEvent;
if ('onwheel' in document.createElement('div'))
wheelEvent = 'wheel';
else if ('onmousewheel' in document.createElement('div'))
wheelEvent = 'mousewheel';
if (wheelEvent && isEnabledForBrowser) {
addEvent(wheelEvent, wheel);
addEvent('mousedown', mousedown);
addEvent('load', init);
}
/***********************************************
* PUBLIC INTERFACE
***********************************************/
function SmoothScroll(optionsToSet) {
for (var key in optionsToSet)
if (defaultOptions.hasOwnProperty(key))
options[key] = optionsToSet[key];
}
SmoothScroll.destroy = cleanup;
if (window.SmoothScrollOptions) // async API
SmoothScroll(window.SmoothScrollOptions)
if (typeof define === 'function' && define.amd)
define(function() {
return SmoothScroll;
});
else if ('object' == typeof exports)
module.exports = SmoothScroll;
else
window.SmoothScroll = SmoothScroll;
})();
I believe the purpose of noConflict is to relinquish control of the $ global variable for external libraries, so doing var $ = jQuery.noConflict(); just sets the global $ to what noConflict returns, which is the jQuery object. In other words, it doesn't buy you anything - it's simply setting $ to what $ would be, even without the noConflict() method.
Change the $ to $j like the following:
var $j = jQuery.noConflict();
$j(document).ready(function() {
$j(function() {
var $ticker = $j('#news-ticker'),
$first = $j('.news-ticket-class li:first-child', $ticker);
// put an empty space between each letter so we can
// use break word
$j('.news-ticket-class li', $ticker).each(function() {
var $this = $j(this),
text = $this.text();
$this.html(text.split('').join(''));
});
// begin the animation
function tick($el) {
$el.addClass('tick')
.one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function() {
$el.removeClass('tick');
var $next = $el.next('li');
$next = $next.length > 0 ? $next : $first;
tick($next);
});
}
tick($first);
});
});
I am trying to turn my code into a working library. (My first)
Currently you simply call GridNav() and it sets up and executes.
I am currently refactoring out all the necessary variables
The trouble I am having is the animations property. I want users to be able to over ride the property.
(function(window, document, $, undefined) {
'use strict';
var fixOutOfBoundCordinates = function(pos, max) {
if (pos < 1) {
pos = max;
} else if (pos > max) {
pos = 1
}
return pos;
};
var calculateDestination = function(position, direction, columns) {
var directions = {
1: [-1,-1],
2: [0,-1],
3: [1,-1],
4: [-1,0],
6: [1,0],
7: [-1,1],
8: [0,1],
9: [1,1]
};
direction = directions[direction];
var y = Math.ceil(position/columns);
var x = position - ((y-1) * columns);
x = fixOutOfBoundCordinates((x+direction[0]), columns);
y = fixOutOfBoundCordinates((y+direction[1]), columns);
return (x + ((y-1)*columns)) -1;
};
var GridNav = function(params) {
return new Library(params);
};
var Library = function(params) {
//var $main = document.querySelectorAll( '#pt-main' ),
var $main = $('#pt-main'),
$pages = $main.children( 'section.pt-page' ),
$iterate = $( '.panel' ),
pagesCount = $pages.length,
isAnimating = false,
endCurrPage = false,
endNextPage = false,
animEndEventNames = {
'WebkitAnimation' : 'webkitAnimationEnd',
'OAnimation' : 'oAnimationEnd',
'msAnimation' : 'MSAnimationEnd',
'animation' : 'animationend'
},
// animation end event name
animEndEventName = animEndEventNames[ 'animation'],
keys = {
BACKSPACE: 8,
DOWN: 40,
ENTER: 13,
LEFT: 37,
UP: 38,
RIGHT: 39,
SPACE: 32,
PAGE_DOWN: 34,
PAGE_UP: 33
};
function nextPage(outpage, direction ) {
if( isAnimating ) {
return false;
}
var cols = $main.data("col");
var inpage = calculateDestination(outpage, direction, cols);
isAnimating = true;
var $currPage = $pages.eq( outpage-1 ),
// Done early so element visible during animation
$nextPage = $pages.eq( inpage ).addClass( 'pt-page-current' ),
outClass = '', inClass = '';
$currPage.addClass( Library.animation[direction]["outClass"] ).on( animEndEventName, function() {
$currPage.off( animEndEventName );
endCurrPage = true;
if( endNextPage ) {
onEndAnimation( $currPage, $nextPage );
}
} );
$nextPage.addClass( Library.animation[direction]["inClass"] ).on( animEndEventName, function() {
$nextPage.off( animEndEventName );
endNextPage = true;
if( endCurrPage ) {
onEndAnimation( $currPage, $nextPage );
}
} );
}
function onEndAnimation( $outpage, $inpage ) {
endCurrPage = false;
endNextPage = false;
resetPage( $outpage, $inpage );
isAnimating = false;
}
function resetPage( $outpage, $inpage ) {
$outpage.attr( 'class', $outpage.data( 'originalClassList' ) );
$inpage.attr( 'class', $inpage.data( 'originalClassList' ) + ' pt-page-current' );
}
$pages.each( function() {
var $page = $( this );
$page.data( 'originalClassList', $page.attr( 'class' ) );
} );
// Use start class as begining
var start = $pages.index($pages.filter(".start"));
if (start == -1) {
start = Math.ceil(pagesCount/2)-1
} else {
}
$pages.eq(start).addClass('pt-page-current');
$( "body" ).keyup(function(event) {
var key = event.which;
var cur;
if ( key == keys.DOWN || key == keys.PAGE_DOWN ) {
cur = $('section.pt-page').filter(".pt-page-current").index() + 1;
nextPage( cur, 8);
}
if ( key == keys.UP || key == keys.PAGE_UP ) {
cur = $('section.pt-page').filter(".pt-page-current").index() + 1;
nextPage( cur, 2);
}
if ( key == keys.RIGHT || key == keys.SPACE || key == keys.ENTER ) {
cur = $('section.pt-page').filter(".pt-page-current").index() + 1;
nextPage( cur, 6);
}
if ( key == keys.LEFT || key == keys.BACKSPACE ) {
cur = $('section.pt-page').filter(".pt-page-current").index() + 1;
nextPage( cur, 4);
}
});
$iterate.on( 'click', function() {
var cur = $('section.pt-page').filter(".pt-page-current").index() + 1;
var direction = $iterate.index($(this)) + 1;
if (direction > 4) {
direction+= 1;
}
nextPage(cur, direction);
} );
return this;
};
Library.animation = {
1:
// Move UP and Left
{outClass: 'pt-page-moveToBottomRight',inClass: 'pt-page-moveFromTopLeft'},
2:
// Move UP
{outClass: 'pt-page-moveToBottom', inClass: 'pt-page-moveFromTop'},
3:
// Move UP and Right
{outClass: 'pt-page-moveToBottomLeft', inClass: 'pt-page-moveFromTopRight'},
4:
// Move Left
{outClass: 'pt-page-moveToRight', inClass: 'pt-page-moveFromLeft'},
6:
// Move Right
{outClass: 'pt-page-moveToLeft', inClass: 'pt-page-moveFromRight'},
7:
// Move Down and Left
{outClass: 'pt-page-moveToTopRight', inClass: 'pt-page-moveFromBottomLeft'},
8:
// Move Down
{outClass: 'pt-page-moveToTop', inClass: 'pt-page-moveFromBottom'},
9:
// Move Down and Right
{outClass: 'pt-page-moveToTopLeft', inClass: 'pt-page-moveFromBottomRight'}
};
//define globally if it doesn't already exist
if(!window.GridNav){
window.GridNav = GridNav;
}
else{
console.log("Library already defined.");
}
})(window, document, jQuery);
Here it is working:
codepen
Any other library recommendations/tips welcome.
Was sent here from code review
I'm trying to implement a codrops plugin I found and it's working quite well but I have trouble when it comes to improve it.
http://tympanus.net/codrops/2013/12/30/svg-drawing-animation/
My page is divided into three sections, when you click on one of the three sections on the menu, the content fades in.
http://alexandrebeaumont.com/so/layout.png
When you scroll down my animations load perfectly but I would like them to be reloaded each time you click on the menu because now, if I scroll in one section, the animations are launched in everyone of them...
EDIT I pasted the whole code since after reading again the script I'm not sure at all what could giver me my solution
(function() {
'use strict';
var docElem = window.document.documentElement;
window.requestAnimFrame = function(){
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback){
window.setTimeout(callback, 1000 / 60);
}
);
}();
window.cancelAnimFrame = function(){
return (
window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.oCancelAnimationFrame ||
window.msCancelAnimationFrame ||
function(id){
window.clearTimeout(id);
}
);
}();
function SVGEl( el ) {
this.el = el;
this.image = this.el.previousElementSibling;
this.current_frame = 0;
this.total_frames = 60;
this.path = new Array();
this.length = new Array();
this.handle = 0;
this.init();
}
SVGEl.prototype.init = function() {
var self = this;
[].slice.call( this.el.querySelectorAll( 'path' ) ).forEach( function( path, i ) {
self.path[i] = path;
var l = self.path[i].getTotalLength();
self.length[i] = l;
self.path[i].style.strokeDasharray = l + ' ' + l;
self.path[i].style.strokeDashoffset = l;
} );
};
SVGEl.prototype.render = function() {
if( this.rendered ) return;
this.rendered = true;
this.draw();
};
SVGEl.prototype.draw = function() {
var self = this,
progress = this.current_frame/this.total_frames;
if (progress > 1) {
window.cancelAnimFrame(this.handle);
this.showImage();
} else {
this.current_frame++;
for(var j=0, len = this.path.length; j<len;j++){
this.path[j].style.strokeDashoffset = Math.floor(this.length[j] * (1 - progress));
}
this.handle = window.requestAnimFrame(function() { self.draw(); });
}
};
SVGEl.prototype.showImage = function() {
classie.add( this.image, 'show' );
classie.add( this.el, 'hide' );
};
function getViewportH() {
var client = docElem['clientHeight'],
inner = window['innerHeight'];
if( client < inner )
return inner;
else
return client;
}
function scrollY() {
return window.pageYOffset || docElem.scrollTop;
}
// http://stackoverflow.com/a/5598797/989439
function getOffset( el ) {
var offsetTop = 0, offsetLeft = 0;
do {
if ( !isNaN( el.offsetTop ) ) {
offsetTop += el.offsetTop;
}
if ( !isNaN( el.offsetLeft ) ) {
offsetLeft += el.offsetLeft;
}
} while( el = el.offsetParent )
return {
top : offsetTop,
left : offsetLeft
};
}
function inViewport( el, h ) {
var elH = el.offsetHeight,
scrolled = scrollY(),
viewed = scrolled + getViewportH(),
elTop = getOffset(el).top,
elBottom = elTop + elH,
// if 0, the element is considered in the viewport as soon as it enters.
// if 1, the element is considered in the viewport only when it's fully inside
// value in percentage (1 >= h >= 0)
h = h || 0;
return (elTop + elH * h) <= viewed && (elBottom) >= scrolled;
}
function init() {
var svgs = Array.prototype.slice.call( document.querySelectorAll( '#main svg' ) ),
svgArr = new Array(),
didScroll = false,
resizeTimeout;
// the svgs already shown...
svgs.forEach( function( el, i ) {
var svg = new SVGEl( el );
svgArr[i] = svg;
setTimeout(function( el ) {
return function() {
if( inViewport( el.parentNode ) ) {
svg.render();
}
};
}( el ), 250 );
} );
var scrollHandler = function() {
if( !didScroll ) {
didScroll = true;
setTimeout( function() { scrollPage(); }, 60 );
}
},
scrollPage = function() {
svgs.forEach( function( el, i ) {
if( inViewport( el.parentNode, 0.5 ) ) {
svgArr[i].render();
}
});
didScroll = false;
},
resizeHandler = function() {
function delayed() {
scrollPage();
resizeTimeout = null;
}
if ( resizeTimeout ) {
clearTimeout( resizeTimeout );
}
resizeTimeout = setTimeout( delayed, 200 );
};
window.addEventListener( 'scroll', scrollHandler, false );
window.addEventListener( 'resize', resizeHandler, false );
}
init();
})();
Can't something like this be working ?
$('.trigger').click(function(){
init();
})
I have a custom image slideshow that I am having to modify. I am trying to make the first slide timeout longer, basically I want it to be visible 2 seconds longer than the others. What would be the best way to go about? Here is the code:
(function($) {
var settings = {
'promoid': 'promo',
'selectorid': 'promoselector',
'promoanimation': 'fade',
'timeout': 4500,
'speed': 'slow',
'go': 'true',
'timeoutname': 'promotimeout'
};
$.fn.promofade = function(options) {
settings.promoid = $(this).attr("id");
return this.each(function() {
$.promofade(this, options);
});
};
$.promofade = function(container, options) {
if ( options ) {
$.extend( settings, options );
}
var elements = $("#" + settings.promoid).children();
var selectors = $("#" + settings.selectorid).children();
if ( elements.length != selectors.length ) { alert("Selector length does not match."); }
if ( settings.go == 'true' )
{
settings.timeoutname = setTimeout(function() {
$.promofade.next(elements, selectors, 1, 0);
}, settings.timeout);
} else {
clearTimeout( settings.timeoutname );
}
};
$.promofade.next = function( elements, selectors, current, last ) {
if ( settings.promoanimation == 'fade' )
{
//$(elements[last]).fadeOut( settings.speed );
//$(elements[current]).fadeIn( settings.speed );
$(elements[last]).hide();
$(elements[current]).show();
} else if ( settings.promoanimation == 'slide' ) {
// This creates a 'slide gap', where they havent crossed yet, causing a blank spot
// TODO: fix!
$(elements[last]).slideUp( settings.speed );
$(elements[current]).slideDown( settings.speed );
}
$(selectors[last]).removeClass("on");
$(selectors[current]).addClass("on");
//$(selectors[current]).attr("class", "on");
// They are both the same length so we only calculate for one
if ( (current + 1) < elements.length ) {
current = current + 1;
last = current - 1;
} else {
current = 0;
last = elements.length - 1;
}
if ( settings.go == 'true' )
{
settings.timeoutname = setTimeout( function() {
$.promofade.next( elements, selectors, current, last );
}, settings.timeout );
} else {
clearTimeout( settings.timeoutname );
}
};
})(jQuery);
My html is built out like so:
<div id="fader">
<img src="#" alt='#'/>
<img src="#" alt='#'/>
<img src="#" alt='#'/>
</div>
You could solve it by specifying a separate first slide timeout that's assigned during initialization, then use the standard timeout on promofade.next.
(function($) {
var settings = {
'promoid': 'promo',
'selectorid': 'promoselector',
'promoanimation': 'fade',
'firstslidetimeout':2000, //apply this during $.promofade only
'timeout': 4500,
'speed': 'slow',
'go': 'true',
'timeoutname': 'promotimeout'
};
$.fn.promofade = function(options) {
settings.promoid = $(this).attr("id");
return this.each(function() {
$.promofade(this, options);
});
};
$.promofade = function(container, options) {
if ( options ) {
$.extend( settings, options );
}
var elements = $("#" + settings.promoid).children();
var selectors = $("#" + settings.selectorid).children();
if ( elements.length != selectors.length ) { alert("Selector length does not match."); }
if ( settings.go == 'true' )
{
settings.timeoutname = setTimeout(function() {
$.promofade.next(elements, selectors, 1, 0);
}, settings.timeout + settings.firstslidetimeout);
} else {
clearTimeout( settings.timeoutname );
}
};
$.promofade.next = function( elements, selectors, current, last ) {
if ( settings.promoanimation == 'fade' )
{
//$(elements[last]).fadeOut( settings.speed );
//$(elements[current]).fadeIn( settings.speed );
$(elements[last]).hide();
$(elements[current]).show();
} else if ( settings.promoanimation == 'slide' ) {
// This creates a 'slide gap', where they havent crossed yet, causing a blank spot
// TODO: fix!
$(elements[last]).slideUp( settings.speed );
$(elements[current]).slideDown( settings.speed );
}
$(selectors[last]).removeClass("on");
$(selectors[current]).addClass("on");
//$(selectors[current]).attr("class", "on");
// They are both the same length so we only calculate for one
if ( (current + 1) < elements.length ) {
current = current + 1;
last = current - 1;
} else {
current = 0;
last = elements.length - 1;
}
if ( settings.go == 'true' )
{
settings.timeoutname = setTimeout( function() {
$.promofade.next( elements, selectors, current, last );
}, settings.timeout);
} else {
clearTimeout( settings.timeoutname );
}
};
})(jQuery);
You might need to make changes in two places to get what you wanted.
(function ($) {
var settings = {
'promoid': 'promo',
'selectorid': 'promoselector',
'promoanimation': 'fade',
'timeout': 4500,
'firstAdditionalTimeout': 4500,
'speed': 'slow',
'go': 'true',
'timeoutname': 'promotimeout'
};
$.fn.promofade = function (options) {
settings.promoid = $(this).attr("id");
return this.each(function () {
$.promofade(this, options);
});
};
$.promofade = function (container, options) {
if (options) {
$.extend(settings, options);
}
var elements = $("#" + settings.promoid).children();
var selectors = $("#" + settings.selectorid).children();
//if (elements.length != selectors.length) {
// alert("Selector length does not match.");
//}
if (settings.go == 'true') {
settings.timeoutname = setTimeout(function () {
$.promofade.next(elements, selectors, 1, 0);
}, settings.timeout + settings.firstAdditionalTimeout); // here
} else {
clearTimeout(settings.timeoutname);
}
};
$.promofade.next = function (elements, selectors, current, last) {
if (settings.promoanimation == 'fade') {
//$(elements[last]).fadeOut( settings.speed );
//$(elements[current]).fadeIn( settings.speed );
$(elements[last]).hide();
$(elements[current]).show();
} else if (settings.promoanimation == 'slide') {
// This creates a 'slide gap', where they havent crossed yet, causing a blank spot
// TODO: fix!
$(elements[last]).slideUp(settings.speed);
$(elements[current]).slideDown(settings.speed);
}
//$(selectors[last]).removeClass("on");
//$(selectors[current]).addClass("on");
//$(selectors[current]).attr("class", "on");
// They are both the same length so we only calculate for one
if ((current + 1) < elements.length) {
current = current + 1;
last = current - 1;
} else {
current = 0;
last = elements.length - 1;
}
if (settings.go == 'true') {
settings.timeoutname = setTimeout(function () {
$.promofade.next(elements, selectors, current, last);
}, current == 1 ? (settings.timeout + settings.firstAdditionalTimeout) : settings.timeout); // and here
} else {
clearTimeout(settings.timeoutname);
}
};
})(jQuery);
DEMO