How do I loop these two opacity functions in an interval? - javascript

My program: https://jsfiddle.net/60ucsfrb/
I am trying to copy the format of my change size function which manages to loop itself and continuously change the size of div with the help of intervals from an animate function. However, when I try to do the same format for my change opacity for the div, it does not work. Instead it only works once, making the opacity 0.9 from 1 and being done. I'm going to try a for loop instead, but I don't think I'm supposed to since the animate function is supposed to already loop it for me, but I'm not sure.
This is the change size function that WORKS and changes the div from 150 to 50.
function shrinkSize(elem){
var currentWidth = parseInt(getTheStyle(elem.id,'width'))-2;
elem.style.width=currentWidth+"px";
if(parseInt(elem.style.width)==50){
clearInterval(sizeTimer);
sizeTimer = setInterval(function(){growSize(elem);},10);
}
}
function growSize(elem){
var currentWidth = parseInt(getTheStyle(elem.id,'width'))+2;
elem.style.width=currentWidth+"px";
if(parseInt(elem.style.width)==150){
clearInterval(sizeTimer);
sizeTimer = setInterval(function(){shrinkSize(elem);},10);
}
}
This is the animate function that creates intervals for loops.
var moveTimer;
var sizeTimer;
var opacityTimer;
var mover = document.getElementById("movingElem");
function Animate(elem){
//only clears most recent interval, cant clear anything before that
clearInterval(moveTimer);
clearInterval(sizeTimer);
clearInterval(opacityTimer);
moveTimer = setInterval(function(){MoveRight(elem,'wrapper');}, 10);//a function that'll call another function after certain amount of time, speed of animation, once every ten milisecond
sizeTimer = setInterval(function(){shrinkSize(elem);}, 10);
opacityTimer = setInterval(function(){decreaseOpacity(elem);}, 10);
}
And this is my NOT WORKING change opacity function that I'm trying to follow the same format as change size function.
function increaseOpacity(elem){
var currentOpacity = parseInt(getTheStyle(elem.id,'opacity'))+0.1;
elem.style.opacity= parseInt(currentOpacity);
console.log(currentOpacity);
if(parseInt(elem.style.opacity)==1){
clearInterval(opacityTimer);
opacityTimer = setInterval(function(){decreaseOpacity(elem);},10);
}
}
function decreaseOpacity(elem){
var currentOpacity = parseInt(getTheStyle(elem.id,'opacity'))-0.1;
elem.style.opacity=currentOpacity;
if(parseInt(elem.style.opacity)==0){
clearInterval(opacityTimer);
opacityTimer = setInterval(function(){increaseOpacity(elem);},10);
}
}
I know it has to do with this opacity line not matching up with this pixel in change size, but I don't know how to get it working.
elem.style.opacity= parseInt(currentOpacity);
elem.style.width=currentWidth+"px";

I think the problem is that you use parseInt which parses the number to a rounded integer (in your case after the first shrink, it parses the opacity from '0.9' to 0). In the opacity case you are dealing with decimals, so you have to use parseFloat instead.
function increaseOpacity(elem){
var currentOpacity = parseFloat(getTheStyle(elem.id,'opacity'))+0.1;
elem.style.opacity= parseFloat(currentOpacity);
console.log(currentOpacity);
if(parseFloat(elem.style.opacity)==1){
clearInterval(opacityTimer);
opacityTimer = setInterval(function(){decreaseOpacity(elem);},10);
}
}
function decreaseOpacity(elem){
var currentOpacity = parseFloat(getTheStyle(elem.id,'opacity'))-0.1;
elem.style.opacity=currentOpacity;

Related

jQuery 2.1.0 | Display elements incrementally

I need to display rows of buttons incrementally from top to bottom in a scrollable parent div. These rows of buttons are created using a replace method applied onto a text string converted to html. Since I can have 500+ more rows of buttons to create and display, the text-to-html conversion can take a few seconds or longer, which freezes the UI during conversion. The code below uses a setInterval which unlocks the UI and provides a cool way of "animating" the gradual display of button rows. Problem is, currently, the whole set of rows is repeated at each setInterval, that's not what I want, I can't figure out what to do next. I need each individual row to be displayed incrementally without repeating, from top to bottom, in the order provided by the string, until the length of array is met. The scrolable parent div is a fixed height of 300px. Maybe a Lazy loading method would be better? Any help solving this issue is appreciated.
DEMO fiddle
var placeholder = $('#placeholder');
placeholder.html(placeholdertohtml(placeholder));
function placeholdertohtml(placeholder){
placeholder.html(placeholder.text().replace(/((\d{2},\d{2}))/g, function(match, number){
var blocks = placeholder.text().split(',').length;
console.log(blocks);
var el = number.substr(0,5).split(',');
var prefix = el[0];
var suffix = el[1];
var t = setInterval(function(){
if (blocks) {
var content = '<p><button>'+prefix+'</button><button>'+suffix+'</button></p>';
$('#placeholder').append(content);
blocks--;
} else {
clearInterval(t);
}
}, 100);
}));
}
So, I reworked your code using for loops instead of the replace function to fix the problem.
Here is a working codepen
I basically made a loop that built up an array of html to add:
var numberOfPairs = placeholder.text().match(/((\d{2},\d{2}))/g).length;
var countdown = numberOfPairs;
var string = placeholder.text();
var elements = [];
for(var i = 0; i < numberOfPairs; i++) {
var pair = string.substring(5 * i + 1, (5 * i) + 6).split(',');
var prefix = pair[0];
var suffix = pair[1];
elements.push('<p><button>'+prefix+'</button><button>'+suffix+'</button></p>');
}
And then looped over the elements with your interval function to get the same "loading" effect:
var elementIndex = countdown;
var t = setInterval(function(){
if (countdown >= 0) {
$('#placeholder').append(elements[(countdown - elementIndex) * -1]);
countdown--;
} else {
clearInterval(t);
}
}, 100);

How to proper use setTimeout with IE?

For a mockup-webpage used for research on interaction on websites, I created a mockup message-stream using JavaScript. This message stream should show images at pre-set intervals. In Chrome, this code posts the images below one another, at the pre-set intervals. In IE, only the first image is shown. I have already removed the passing of parameters in the window.setTimeout method, but am lost as to what else I need to do to satisfy IE. What else should I do to make all images appear in the pre-set intervals?
My script-section has several global variables:
var updateinterval = 400; // a multiplier (integer) used to
var scrollinterval = 5; // an interval (integer) to wait before scrolling
var point; // integer used to prevent using parameters in window.setTimeout
var interval = [0, 10, 40]; // array of integers creating diversity in intervals
var images = ["r1", "a1", "r2"];// array of strings referring to images to show
The following functions are present:
function trypost(){
point = point + 1;
if(point < interval.length){
//write the required image
document.writeln("<img src='images/"+images[point]+".png'/><br/>");
//time scroll to bottom
var stb = window.setTimeout(scrollToBottom, scrollinterval);
//time next post
var nextupdate = interval[point]*updateinterval;
var tp = window.setTimeout(trypost, nextupdate);
}
}
function scrollToBottom(){
window.scrollBy(0,document.body.scrollHeight);
}
function startpost(){
point = -1;
trypost();
}
window.onload = startpost;
You can use setInterval instead of repeatedly calling setTimeout, setInterval repeats until you call clearInterval.
Also as noted in the comments, document.writeln is from a different decade ;)
You can modify the DOM directly now.
var i=0;
var interval = [0, 10, 400, 10, 1000];
var images = [
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRTiW-7zqLiG1DNq4Tmt6x4j1iBc0FZRBpyYZtIXgDzUy_NHwTv",
"http://img2.wikia.nocookie.net/__cb20120327004334/mrmen/images/a/a0/MrMean.gif",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRTiW-7zqLiG1DNq4Tmt6x4j1iBc0FZRBpyYZtIXgDzUy_NHwTv",
"http://img2.wikia.nocookie.net/__cb20120327004334/mrmen/images/a/a0/MrMean.gif",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRTiW-7zqLiG1DNq4Tmt6x4j1iBc0FZRBpyYZtIXgDzUy_NHwTv"
];
for(var i=0; i<interval.length;i++)
var timer = setTimeout(function(img){
var newImg = document.createElement("IMG");
newImg.src = img;
document.getElementById('holder').appendChild(newImg);
}, interval[i], images[i]);
with this HTML
<div id='holder'>
</div>
Running demo
http://jsfiddle.net/W7QXH/4/

Javascript easing not animating

Trying to implement simple easing in javascript (without jQuery) but unfortunately there doesn't seem to be any animation when the button is clicked (see below).
My goal is to get the hidden list item (the last item) visible by tweening the first item's margin left property. I know it isn't a CSS issue because manually modifying the style moves the list, but I'm not sure what the issue is. My guess is with how I'm calling the ease function but changing the params still wasn't working for me.
The easing part is below, entire code is here: Fiddle
JS:
var start = document.getElementById('start'),
list = document.getElementById('my-list'),
imgs = list.getElementsByTagName('img'),
last_img = imgs[imgs.length -1 ];
ease = function(t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
},
shift_imgs = function(el) {
var orig_value = parseFloat( el.style.marginLeft ),
end_value = -37,
change = Math.abs( end_value - orig_value ),
duration = 1, // 1 second
time = 0;
for ( var i = 0; i < change; i++ ) {
setTimeout(function() {
el.style.marginLeft = ( parseFloat( el.style.marginLeft ) + 1 ) + 'px';
}, time);
time = ease(time, orig_value, change, duration);
}
};
start.onclick = function() {
shift_imgs(last_img);
}
Your orig_value is NaN as parseFloat(el.style.marginLeft) returns nothing, even if you set an initial value in the css. i.e: margin-left: 15px; still will return nothing.
You can use window.getComputedStyle(...).getPropertyValue, similar to this:
window.getComputedStyle(el, null).getPropertyValue("margin-left");
This will give you the actual current value along with the px, i.e: 0px.
(It always return the value in px even if set in CSS as em or pt)
So you need to remove the px and the get the float value.
You can wrap this into a little helper similar to this:
getElementMarginLeftAsFloat = function (el) {
var pxValue = window.getComputedStyle(el, null).getPropertyValue("margin-left");
var valueOnly = pxValue.substring(0, pxValue.length - 2);
return parseFloat(valueOnly);
}
Another issue is that the moving of the actual element occurs within setTimeout executed inside a loop. The loop which calls setTimeout, causes each setTimeout to be queued nearly simultaneously, hence they all execute close to the same time, causing the element to just jump.
You can use a recursive sub-method inside your method which uses setTimeout to call itself until it is done. That way each setTimeout is triggered only after the specified interval, causing them to be executed close enough apart to the specified interval, similar to this:
shift_imgs = function (el) {
var orig_value = getElementMarginLeftAsFloat(el),
end_value = -37,
change = Math.abs(end_value - orig_value),
duration = 1, // 1 second
time = 0;
function doShift() {
currentValue = getElementMarginLeftAsFloat(el);
if(currentValue+1 > change){
return;
};
el.style.marginLeft = (currentValue + 1) + 'px';
time = ease(time, orig_value, change, duration);
setTimeout(doShift, time);
}
doShift();
};
By having the setTimeout function call itself, it releases the resources, ensuring the drawing of the element can occur between each "iteration".
I updated your code to use this approach and it seems to work now.
DEMO - animating movement using computed style
You can most likely do this many other ways and also prettify this code for sure but but this should get you started either way.

Transform property jquery

$(document).ready(function(){
$('#space').css({
'-webkit-transform': 'scale(2,3)',
});
$('#space').css({
'-webkit-transform': 'skew(30deg,20deg)',
});
});
CSS
#space{transition:duration:20s;}
Using the above Jquery, I want the scale property to run for the first 20 seconds and then the skew property for the next 20 seconds but here it only does skew.I was thinking to provide a delay of 20 seconds for the next statement but is there any other simple way to do it? Thanks
You cannot use .delay() for CSS properties. Instead, you can try using the setInterval() function to progressively add transform to your element based on a predefined set of transform you want. I have made a fiddle here - http://jsfiddle.net/teddyrised/5AqCm/
This answer is made under the assumption that you want to, eventually, both scale and skew the element in it's final state.
Let me explain my code a little:
$(document).ready(function () {
var $spce = $("#space"),
trsfm = [], // Declare empty array for transforms
delay = 1000, // Set delay in ms
count = 0; // Set iteration count
// Declare a stepwise array where you want the transform to occur
trsfm = ['scale(2,3)', 'skew(30deg,20deg)'];
var timer = window.setInterval(function () {
if(count < trsfm.length) {
// Increase count by 1
count += 1;
// Stepwise addition of transforms
var trsfmStep = trsfm.slice(0, count).join(' ');
$spce.css({
'-moz-transform': trsfmStep,
'-o-transform': trsfmStep,
'-webkit-transform': trsfmStep,
'transform': trsfmStep
});
// Log in the console, just for fun
console.log(trsfmStep);
} else {
// If you have iterated through all the transforms, clear interval
window.clearInterval(timer);
console.log('Timer cleared.');
}
}, delay);
});
I have defined the delay, 1000ms (of course you can change that), and also used an array to store all the transforms you want to apply. The transforms are applied in a step-wise fashion from left to right, starting from scale and then to skew.
A timer is set, and the count is started. Every time an interval is reached, the script checks if you have iterated through the transform array. If not, it will apply stepwise addition of the transform, by joining the items in the array from the start, but stopping at whatever step you are at (using the .slice()) method :)

I would like to move an element to the left using loop

I bet I've got elementary question, but I couldn't solve it for two nights.
I've got 1 "ul" element and I just want it to move any amount of pixels every e.g. 2 sec to the left. I want him to move like this step by step and then come back to the original position and start moving again.
I've been stucked, my script only moves it to the final position and finish.
window.onload = function moveUl(){
var eUl = document.getElementById('change');
var eLi = eUl.getElementsByTagName('li');
x = -300;
function move(){
for(i=0;i< eLi.length;i++){
eUl.style.marginLeft = i*x+'px';
}
}
setInterval(move,1000);
}
This is the simpliest I can think of. I know this script executes whole loop after 1 sec, but I try to do something like this : Move this element to the left, wait, move more to left and so on.
Do you mean something like this?
window.onload = function moveUl()
{
var eUl = document.getElementById('change');
var eLi = eUl.getElementsByTagName('li');
var delta = 0;
function move()
{
for(i=0;i< eLi.length;i++)
eUl.style.marginLeft = (-300*i+delta)+'px';
delta -= 100; // Prepares for the next step
if ( delta == -1000 )
delta = 0; // Resets after 10 steps
}
setInterval(move,1000);
}
If you want it to slide, you have to timeout per iteration. Try writing a function that does a single shift, then calling this function every 10 ms. You can also look into a Javascript library like jQuery that provides a nice API for doing the moving.
Is the problem you can't go back from where you started?
Why not just add a new for loop in move
for(i=eLi.length; i>0 ;i--){
eUl.style.marginLeft = i*x+'px';
}
Do you also want it to loop for ever ie start -> left -> start -> left and again?

Categories