How can I do this dynamically? - javascript

I am working on writing my code this way, but I want to do it in a loop. I want to be dynamic. How can I do it?
$("#sound-player").attr("src",secilen[0]);
var x = document.getElementById("sound-player");
x.play();
x.onended = function() {
$("#sound-player").attr("src",secilen[1]);
var x = document.getElementById("sound-player");
x.play();
x.onended = function() {
$("#sound-player").attr("src",secilen[2]);
var x = document.getElementById("sound-player");
x.play();
x.onended = function() {
$("#sound-player").attr("src",secilen[3]);
var x = document.getElementById("sound-player");
x.play();
x.onended = function() {
alert("bitti");
}
}
}
}

You can use recursion:
/* Cache the player. */
var x = document.getElementById("sound-player");
/* Create an IIFE and execute it recursively. */
(function playRecursively (current, last) {
x.src = secilen[current];
x.play();
x.onended = function() {
/* Play the next, if the current is not the last. */
if (current < last) playRecursively(++current, last);
else alert("bitti");
};
})(0, secilen.length - 1);

Reuse your variable x, instead o redefining it.
var player = document.getElementById('sound-player');
var i = 0;
function playSource(src){
// change the src attribute and play.
if (secilen[scr] !== undefined) {
player.setAttribute('src', secilen[src]);
player.play();
}
else {
alert('bitti')
}
}
player.onended = function(){
i++;
playSource(i);
}
playSource(i); //start playing the first sound

Related

Reset animation to original position using javascript

using the following script i was able to move my picture right when clicked:
<script>
var myTimer = null;
function move(){
document.getElementById("fish").style.left =
parseInt(document.getElementById("fish").style.left)+1+'px';
}
window.onload=function(){
document.getElementById("fish").onclick=function(){
if(myTimer == null){
myTimer = setInterval("move();", 10);
}else{
clearInterval(myTimer);
myTimer = null;
}
}
}
</script>
I am having some trouble reseting the picture to original location without using jQuery.
If anyone can help that would be much appreciated.
If you capture the original position ahead of time you can reset later to the captured value:
var originalPosition = document.getElementById("fish").style.left;
function resetPosition() {
document.getElementById("fish").style.left = originalPosition;
}
Use external JavaScript. Some code to look at:
var pre = onload, E, doc, bod;// previous onload
onload = function(){
if(pre)pre();
doc = document; bod = doc.body;
E = function(id){
return doc.getElementById(id);
}
var fish = E('fish'), timer;
fish.onclick = function(){
if(!timer){
timer = setInterval(function(){
fish.style.left = parseInt(fish.style.left)+1+'px';
}, 10);
}
else{
clearInterval(timer); timer = false;
fish.style.left = '0'; // change '0' to what your CSS `left:`value is
}
}// end load
This should work fine,
var myTimer = null;
var startX = 0;
function move(){
document.getElementById("fish").style.left =
parseInt(document.getElementById("fish").style.left)+1+'px';
}
window.onload=function(){
document.getElementById("fish").onclick=function(){
if(myTimer == null){
startX = document.getElementById("fish").style.left;
myTimer = setInterval("move();", 10);
}else{
clearInterval(myTimer);
myTimer = null;
document.getElementById("fish").style.left = startX + "px";
}
}
}

How to pass unspecified number of parameters to setInterval

I need to create an interval wrapper to track if it has been cleared.
The number of parameters to pass to the interval callback should be variable. So this is the code (not working) I implemented to test it:
function MyInterval() {
var id = setInterval.apply(this, arguments); // NOT VALID!!
this.cleared = false;
this.clear = function() {
this.cleared = true;
clearInterval(id);
};
}
var x = 2;
var y = 3;
var fn = function() {
x = x + y;
console.log(x);
};
var interval = new MyInterval(fn, 5000, x, y);
Within the call to setInterval, this must refer to the global object, so instead of this, you want window in your constructor:
var id = setInterval.apply(window, arguments);
// here -------------------^
(or in loose mode you could use undefined or null.)
Then it works, at least on browsers where setInterval is a real JavaScript function and therefore has apply:
function MyInterval() {
var id = setInterval.apply(window, arguments);
this.cleared = false;
this.clear = function() {
this.cleared = true;
clearInterval(id);
};
}
var x = 2;
var y = 3;
var fn = function() {
x = x + y;
log(x);
};
var interval = new MyInterval(fn, 500, x, y);
setTimeout(function() {
interval.clear();
}, 3000);
function log(msg) {
var p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}
Note, though, that host-provided functions are only required to be callable, they are not required to inherit from Function.prototype and so they're not required/guaranteed to have apply. Modern browsers ensure they do, but earlier ones (IE8, for instance) did not. I can't speak to how well-supported apply is on setInterval.
If you need to support browsers that may not have it, just to use your own function:
function MyInterval(handler, interval) {
var args = Array.prototype.slice.call(arguments, 2);
var tick = function() {
handler.apply(undefined, args);
};
var id = setInterval(tick, interval);
this.cleared = false;
this.clear = function() {
this.cleared = true;
clearInterval(id);
};
}
This also has the advantage that it works even on browsers that don't support additional args on setInterval (fairly old ones).
Example:
function MyInterval(handler, interval) {
var args = Array.prototype.slice.call(arguments, 2);
var tick = function() {
handler.apply(undefined, args);
};
var id = setInterval(tick, interval);
this.cleared = false;
this.clear = function() {
this.cleared = true;
clearInterval(id);
};
}
var x = 2;
var y = 3;
var fn = function() {
x = x + y;
log(x);
};
var interval = new MyInterval(fn, 500, x, y);
setTimeout(function() {
interval.clear();
}, 3000);
function log(msg) {
var p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}
You might be tempted to use the new ES2015 spread operator:
var id = setInterval(...arguments);
...but note that if you transpile (and right now you'd have to), it ends up being an apply call, and so you have the issue of whether apply is supported.
I suggest that you pass an "options" parameter to your timeout.
var MyInterval = (function(window) {
return function(callbackFn, timeout, options) {
var id = setInterval.apply(window, arguments);
this.cleared = false;
this.clear = function() {
this.cleared = true;
clearInterval(id);
};
}
}(window));
var fn = function(opts) {
opts.x += opts.y;
console.log('x = ', opts.x);
};
var opts = {
x: 2,
y: 3
};
var ms = 5000;
var interval = new MyInterval(fn, ms, opts);
// Bootstrap a custom logger. :)
console.log = function() {
var logger = document.getElementById('logger');
var el = document.createElement('LI');
el.innerHTML = [].join.call(arguments, ' ');
logger.appendChild(el);
logger.scrollTop = logger.scrollHeight;
}
body{background:#7F7F7F;}h1{background:#D7D7D7;margin-bottom:0;padding:0.15em;border-bottom:thin solid #AAA;color:#444}#logger{height:120px;margin-top:0;margin-left:0;padding-left:0;overflow:scroll;max-width:100%!important;overflow-x:hidden!important;font-family:monospace;background:#CCC}#logger li{list-style:none;counter-increment:step-counter;padding:.1em;border-bottom:thin solid #E7E7E7;background:#FFF}#logger li:nth-child(odd){background:#F7F7F7}#logger li::before{content:counter(step-counter);display:inline-block;width:1.4em;margin-right:.5em;padding:.25em .75em;font-size:1em;text-align:right;background-color:#E7E7E7;color:#6A6A6A;font-weight:700}
<h1>Custom HTML Logger</h1><ol id="logger"></ol>
I created a utility function rather than a constructor to solve your issue.
function Wrapper(delay) {
var isCleared,
intervalId,
intervalDelay = delay || 5e3; // default delay of 5 sec
function clear() {
if (!isCleared) {
console.log('clearing interval');
isCleared = true;
clearInterval(intervalId);
}
}
function setUpInterval(callback){
var params = [].slice.call(arguments, 1);
if (!callback) {
throw new Error('Callback for interval expected');
}
params.unshift(intervalDelay);
params.unshift(callback);
intervalId = setInterval.apply(null, params);
}
return {
setUp : setUpInterval,
clear : clear
}
}
function intervalCallback() {
console.log([].slice.call(arguments).join(','));
}
var wrapper = Wrapper(1e3); // create wrapper with delay for interval
console.log('test case 1');
wrapper.setUp(intervalCallback, 'params', 'to', 'callback');
// call clear interval after 10sec
setTimeout(function() {
wrapper.clear();
}, 10e3);
Hope this helps.

Combining two Javascript functions to one window.onload not working

I have two functions that I want to run on window.onload event but only the last function seems to work so far. One function is for an image slider and the other one retrieves data from a google spreadsheet cell.
function fun1() { //image slider
var ul;
var li_items;
var imageNumber;
var imageWidth;
var prev, next;
var currentPostion = 0;
var currentImage = 0;
function init() {
ul = document.getElementById('image_slider');
li_items = ul.children;
imageNumber = li_items.length;
imageWidth = li_items[0].children[0].clientWidth;
ul.style.width = parseInt(imageWidth * imageNumber) + 'px';
prev = document.getElementById("prev");
next = document.getElementById("next");
prev.onclick = function() {
onClickPrev();
};
next.onclick = function() {
onClickNext();
};
}
function animate(opts) {
var start = new Date;
var id = setInterval(function() {
var timePassed = new Date - start;
var progress = timePassed / opts.duration;
if (progress > 1) {
progress = 1;
}
var delta = opts.delta(progress);
opts.step(delta);
if (progress == 1) {
clearInterval(id);
opts.callback();
}
}, opts.delay || 17);
}
function slideTo(imageToGo) {
var direction;
var numOfImageToGo = Math.abs(imageToGo - currentImage);
direction = currentImage > imageToGo ? 1 : -1;
currentPostion = -1 * currentImage * imageWidth;
var opts = {
duration: 1000,
delta: function(p) {
return p;
},
step: function(delta) {
ul.style.left = parseInt(currentPostion + direction * delta * imageWidth * numOfImageToGo) + 'px';
},
callback: function() {
currentImage = imageToGo;
}
};
animate(opts);
}
function onClickPrev() {
if (currentImage == 0) {
slideTo(imageNumber - 1);
} else {
slideTo(currentImage - 1);
}
}
function onClickNext() {
if (currentImage == imageNumber - 1) {
slideTo(0);
} else {
slideTo(currentImage + 1);
}
}
}
function fun2() {
// Google spreadsheet js
google.load('visualization', '1', {
callback: function() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1sA7M5kG6Xo8YScD1Df38PIA_G0bvhGRdqoExXg0KJTs/gviz/tq?tqx=out:html&tq?gid=0&headers=0&range=A1:C');
query.send(displayData);
}
});
function displayData(response) {
numRows = response.getDataTable().getValue(0, 0);
document.getElementById('data').innerHTML = numRows;
}
}
var addFunctionOnWindowLoad = function(callback) {
if (window.addEventListener) {
window.addEventListener('load', callback, false);
} else {
window.attachEvent('onload', callback);
}
}
addFunctionOnWindowLoad(fun1);
addFunctionOnWindowLoad(fun2);
This is the answer I've tried link but I can't seem to figure out where I'm going wrong.
This is what I ended up doing, and now all the functions work.
var ul;
var li_items;
var imageNumber;
var imageWidth;
var prev, next;
var currentPostion = 0;
var currentImage = 0;
function init() {
ul = document.getElementById('image_slider');
li_items = ul.children;
imageNumber = li_items.length;
imageWidth = li_items[0].children[0].clientWidth;
ul.style.width = parseInt(imageWidth * imageNumber) + 'px';
prev = document.getElementById("prev");
next = document.getElementById("next");
prev.onclick = function() {
onClickPrev();
};
next.onclick = function() {
onClickNext();
};
}
function animate(opts) {
var start = (new Date());
var id = setInterval(function() {
var timePassed = (new Date()) - start;
var progress = timePassed / opts.duration;
if (progress > 1) {
progress = 1;
}
var delta = opts.delta(progress);
opts.step(delta);
if (progress == 1) {
clearInterval(id);
opts.callback();
}
}, opts.delay || 17);
//return id;
}
function slideTo(imageToGo) {
var direction;
var numOfImageToGo = Math.abs(imageToGo - currentImage);
// slide toward left
direction = currentImage > imageToGo ? 1 : -1;
currentPostion = -1 * currentImage * imageWidth;
var opts = {
duration: 1000,
delta: function(p) {
return p;
},
step: function(delta) {
ul.style.left = parseInt(currentPostion + direction * delta * imageWidth * numOfImageToGo) + 'px';
},
callback: function() {
currentImage = imageToGo;
}
};
animate(opts);
}
function onClickPrev() {
if (currentImage === 0) {
slideTo(imageNumber - 1);
} else {
slideTo(currentImage - 1);
}
}
function onClickNext() {
if (currentImage == imageNumber - 1) {
slideTo(0);
} else {
slideTo(currentImage + 1);
}
}
window.onload = init;
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
function fun2() {
// Google spreadsheet js
google.load('visualization', '1', {
callback: function() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1sA7M5kG6Xo8YScD1Df38PIA_G0bvhGRdqoExXg0KJTs/gviz/tq?tqx=out:html&tq?gid=0&headers=0&range=A1:C');
query.send(displayData);
}
});
function displayData(response) {
numRows = response.getDataTable().getValue(0, 0);
document.getElementById('data').innerHTML = numRows;
}
}
addLoadEvent(fun2);
addLoadEvent(function() {
});
I found this function a while ago and believe it or not, I still need to use it every so often. addEventLoad() Just call addEventLoad while passing the function to load.
"The way this works is relatively simple: if window.onload has not already been assigned a function, the function passed to addLoadEvent is simply assigned to window.onload. If window.onload has already been set, a brand new function is created which first calls the original onload handler, then calls the new handler afterwards."
This snippet will load 3 functions on window.onload
Snippet
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
function alert1() {
alert("First Function Loaded");
}
function alert2() {
alert("Second Function Loaded");
}
function alert3(str) {
alert("Third Function Loaded; Msg: " + str);
}
addLoadEvent(alert1);
addLoadEvent(alert2);
addLoadEvent(function() {
alert3("This works");
});
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

Converting jquery to javascript progress bar

Please help me convert this JQuery to Javascript progress bar script
var generateButton = document.getElementById("generate");
if (generateButton.addEventListener) {
generateButton.addEventListener("click", random, false);
}
else if (generateButton.attachEvent) {
generateButton.attachEvent('onclick', random);
}
function random(e) {
setTimeout(function(){
$('.progress .bar').each(function() {
var me = $(this);
var perc = me.attr("data-percentage");
//TODO: left and right text handling
var current_perc = 0;
var progress = setInterval(function() {
if (current_perc>=perc) {
clearInterval(progress);
} else {
current_perc +=1;
me.css('width', (current_perc)+'%');
}
me.text((current_perc)+'%');
}, 50);
});
},300);
var num = Math.random();
var greetingString = num;
document.getElementById("rslt").innerText = greetingString;
}
Here is the Live version: http://jsfiddle.net/chjjK/9/
Pretty easy actually, use document.getElementsByClassName and a for loop to replace the each:
var bar = document.getElementsByClassName("bar");
for (var i = 0; i < bar.length; i++) {
var me = bar[i];
var perc = me.getAttribute("data-percentage");
var current_perc = 0;
var progress = setInterval(function() {
if (current_perc>=perc) {
clearInterval(progress);
} else {
current_perc +=1;
me.style.width = current_perc+'%';
}
me.innerHTML = ((current_perc)+'%');
}, 50);
}
}, 300);
Demo: http://jsfiddle.net/chjjK/13/

Simple function call inside module, getting NaN, huh?

Here is the module i am working on:
var FeatureRotator = (function($,global) {
var self = {},
currentFeature = 0,
images = [],
imagePrefix = "/public/images/features/",
timer = null,
totalImages = 0,
initialFeature,
interval,
blendSpeed,
element = null,
img1 = null,
img2 = null;
function setVisibleImage(iid) {
$("#img1").attr('src',images[iid].src).css('opacity',1);
$("#img2").css('opacity',0);
$(".active").removeClass("active");
$("#f"+iid).addClass("active");
}
function setCurrentImage(id) {
currentFeature = id;
setVisibleImage(id);
}
function doHoverIn(position) {
if (currentFeature === position) {
self.pause();
} else {
setCurrentImage(global.parseInt(position, 10));
self.pause();
}
}
function doHoverOut(position) {
self.unpause();
}
self.init = function(options,callback) {
var i = 0,
tempImg = null;
interval = options.interval || 5000;
blendSpeed = options.blendSpeed || 500;
element = options.element;
initialFeature = options.initialFeature || 0;
img1 = $("<img/>").attr('id','img1');
img2 = $("<img/>").attr('id','img2').css('opacity','0').css('margin-top',-options.height);
$(element).append(img1).append(img2);
totalImages = $(".feature").size();
for (i = 0;i < totalImages; i++) {
tempImg = new global.Image();
tempImg.src = imagePrefix +"feature_" + i + ".png";
images.push(tempImg);
$("#f"+i).css('background-image',
'url("'+imagePrefix+"feature_"+i+"_thumb.png"+'")')
.hover(doHoverIn($(this).attr('position'))
, doHoverOut($(this).attr('position'))
).attr('position',i);
}
setVisibleImage(initialFeature);
if (options.autoStart) {
self.start();
}
if (callback !== null) {
callback();
}
};
function updateImage() {
var active = $("#img1").css('opacity') === 1 ? "#img1" : "#img2";
var nextFeature = (currentFeature === totalImages-1 ? 0 : currentFeature+1);
if (active === "#img1") {
$("#img2").attr('src',images[nextFeature].src);
$("#img2").fadeTo(blendSpeed, 1);
$("#img1").fadeTo(blendSpeed, 0);
} else {
$("#img1").attr('src',images[nextFeature].src);
$("#img1").fadeTo(blendSpeed, 1);
$("#img2").fadeTo(blendSpeed, 0);
}
$("#f"+currentFeature).removeClass("active");
$("#f"+nextFeature).addClass("active");
currentFeature = nextFeature;
}
self.start = function() {
currentFeature = initialFeature;
setVisibleImage(currentFeature);
timer = global.setInterval(function(){
updateImage();
}, interval);
};
self.pause = function() {
global.clearTimeout(timer);
};
self.unpause = function() {
timer = global.setInterval(function(){
updateImage();
}, interval);
};
return self;
}(this.jQuery, this));
And here is how it is used on the page:
<script type="text/javascript">
// ...
$(function() {
FeatureRotator.init({
interval:5000,
element:'#intro',
autoStart:true,
height:177,
blendSpeed:1000,
initialFeature:0
});
});
</script>
The problem is, when setVisibleImage is called from the init method, the value of iid is NaN. I've stepped through the debugger and verified that 'initialFeature' is 0 when the setVisibleImage function is called, but alas, the value doesn't make it over there.
Can anyone help me determine what the problem is? I've run the code through JSLint, and it came back clean.
UPDATE
Ok here is my updated code, which works now except the fading doesnt work, the image just flips to the next one and doesn't fade smoothly anymore:
var FeatureRotator = (function($,global) {
var self = {},
currentFeature = 0,
images = [],
imagePrefix = "/public/images/features/",
timer = null,
totalImages = 0,
initialFeature = 0,
interval,
blendSpeed;
function setVisibleImage(iid) {
$("#img1").attr('src',images[iid].src).css('opacity',1);
$("#img2").css('opacity',0);
$(".active").removeClass("active");
$("#f"+iid).addClass("active");
}
function setCurrentImage(id) {
currentFeature = id;
setVisibleImage(id);
}
function doHoverIn(obj) {
var position = global.parseInt(obj.target.attributes["position"].value,10);
if (currentFeature === position) {
self.pause();
} else {
setCurrentImage(global.parseInt(position, 10));
self.pause();
}
}
function doHoverOut() {
self.unpause();
}
self.init = function(options,callback) {
var i = 0,
tempImg = null,
element = null,
img1 = null,
img2 = null;
interval = options.interval || 5000;
blendSpeed = options.blendSpeed || 500;
element = options.element;
initialFeature = options.initialFeature || 0;
img1 = $("<img/>").attr('id','img1');
img2 = $("<img/>").attr('id','img2').css('opacity','0').css('margin-top',-options.height);
$(element).append(img1).append(img2);
totalImages = $(".feature").size();
for (i = 0;i < totalImages; i++) {
tempImg = new global.Image();
tempImg.src = imagePrefix +"feature_" + i + ".png";
images.push(tempImg);
$("#f"+i).css('background-image','url("'+imagePrefix+"feature_"+i+"_thumb.png"+'")')
.hover(doHoverIn, doHoverOut)
.attr('position',i);
}
setVisibleImage(initialFeature);
if (options.autoStart) {
self.start();
}
if (typeof callback === "function") {
callback();
}
};
function updateImage() {
var active = $("#img1").css('opacity') === 1 ? "#img1" : "#img2";
var nextFeature = (currentFeature === totalImages-1 ? 0 : currentFeature+1);
if (active === "#img1") {
$("#img2").attr('src',images[nextFeature].src);
$("#img2").fadeTo(blendSpeed, 1);
$("#img1").fadeTo(blendSpeed, 0);
} else {
$("#img1").attr('src',images[nextFeature].src);
$("#img1").fadeTo(blendSpeed, 1);
$("#img2").fadeTo(blendSpeed, 0);
}
$("#f"+currentFeature).removeClass("active");
$("#f"+nextFeature).addClass("active");
currentFeature = nextFeature;
}
self.start = function() {
currentFeature = initialFeature;
setVisibleImage(currentFeature);
timer = global.setInterval(function(){
updateImage();
}, interval);
};
self.stop = function() {
global.clearTimeout(timer);
};
self.pause = function() {
global.clearTimeout(timer);
};
self.unpause = function() {
timer = global.setInterval(function(){
updateImage();
}, interval);
};
return self;
}(this.jQuery, this));
Since you're getting NaN, I'm guessing it is actually taking place from this line:
.hover(doHoverIn($(this).attr('position'))
...which calls this:
setCurrentImage(global.parseInt(position, 10)); // note the parseInt()
...which calls this:
setVisibleImage(id);
So the position being passed to parseInt is coming from $(this).attr('position'), which is likely an value that can't be parsed into a Number, so you get NaN.
Check out the value of that attribute in first line of the block for the for statement.
for (i = 0;i < totalImages; i++) {
console.log( $(this).attr('position') ); // verify the value of position
// ...

Categories

Resources