I wrote some JQuery and JS to power a single message element that:
reads a new message from an array for each loop
starts off-screen,
animates right, to center screen for 1/4 of the loop duration
waits at the center to be read for 1/2 of the loop duration
animates right again, off screen for another fourth of the loop duration
changes to the next loop with a new message
repeats
And what sounds like a simple task became (in relation to the feature) many lines of code:
function flow(i, duration){
var message = Game.activities[i]
var transTime = duration / 4;
var idleTime = duration / 2;
var windowDouble = $(window).width() * 2;
$(".message-flow").text(message);
$(".message-flow")
.animate({transform:"translateX(-" + windowDouble + "px)"},0)
.animate({transform:"translateX(0px)"},transTime)
.delay(idleTime)
.animate({transform:"translateX(" + windowDouble + "px)"},transTime);
}
function flowFunc(i, duration){
return function(){
flow(i, duration);
}
}
function activityFlowInit(duration){
var delay = 0;
for (var i = 0; i < Game.activities.length; i++){
setTimeout(flowFunc(i, duration),delay);
delay += duration;
}
totalDuration = duration * Game.activities.length;
setTimeout(function(){
activityFlowInit(duration);
},totalDuration);
}
Which produces a timing flaw where the message slowly begins to change during the transition period rather than when hidden;
I then thought of removing all of this code (which handles closures, in the midst of it all) and replacing the message's animation functionality with 11 simple lines of CSS:
.message{
animation: transit 4s;
animation-iteration-count:infinite;
}
#keyframes transit
{
0% {transform:translateX(-150%)}
25% {transform:translateX(50%)}
75% {transform:translateX(50%)}
100% {transform:translateX(150%)}
}
Afterwards changing the message at a set interval, in coordination with the time that the message is off screen.
However, I don't know how I can do this.
I'm thinking I need some sort of hybrid of setInterval and a loop; a loop that only loops after an interval of time has passed.
How is this (or the next best thing) achieved?
I started thinking about the way a loop and setInterval() works, and I realized that what a loop is really doing is setting an interval of 0, checking a condition and then incrementing a variable. I can make my own for loop-setInterval hybrid by setting the interval, (in my case) skipping the condition, and incrementing my own variable.
JS:
var i = 0;
var messages = ["message 1", "message2", "message 3"];
function writeAdd() { // Handling the closure
return function () {
$(".message").text(messages[i]);
//if (condition === true){ // condition excluded
i++;
if(i === messages.length) i = 0; //creating the loop's repetition
//}
};
}
function loopMessage(duration) {
$(".message").css("-webkit-animation-play-state","running");
setInterval(writeAdd(), duration); //setting the interval
}
loopMessage(4000);
CSS:
.message-flow{
-webkit-animation: transit 8s;
-webkit-animation-iteration-count:infinite;
-webkit-animation-play-state:paused;
}
#-webkit-keyframes transit {
0% {
-webkit-transform:translateX(-2000px);
}
25% {
-webkit-transform:translateX(0px);
}
75% {
-webkit-transform:translateX(0px);
}
100% {
-webkit-transform:translateX(2000px);
}
}
The JSFiddle
Related
I'm developing a game engine in HTML5. Characters are div elements using an animated sprite for background. As sprite animation have fluid parameters and must be set by code, they can't be predefined in a static CSS definition, thus I use element.animate to set sprite animations to a given row at a given speed knowing my scales and frame counts.
// Applies the given frame and animation to the sprite
// Frame is an angle, clockwise direction: 0 = up, 1 = right, 2 = down, 3 = left
set_animation(frame, duration) {
const scale_x = this.settings.sprite.scale_x * this.settings.sprite.frames_x;
const pos_y = this.settings.sprite.scale_y * -frame;
// Cancel the existing animation
if(this.data_actors_self.anim) {
this.data_actors_self.anim.cancel();
this.data_actors_self.anim = null;
}
// Play the animation for this row or show the first frame if static
if(duration > 0) {
this.data_actors_self.anim = this.element.animate([
{
backgroundPosition: px([0, pos_y])
}, {
backgroundPosition: px([scale_x, pos_y])
}
], {
duration: duration * 1000,
direction: "normal",
easing: "steps(" + this.settings.sprite.frames_x + ")",
iterations: Infinity
});
this.data_actors_self.anim.play();
} else {
this.element.style.backgroundPosition = px([0, pos_y]);
}
}
Obviously that's a snippet from an actor class function: this.element is the div, this.settings is an object with parameters to be used who's names should make sense in this context, the px() function is a simple converter to turn arrays into pixel strings for HTML (eg: [0, 0] to "0px 0px").
The issue I'm having: While I can always run this function to set a new animation, I want the ability to change the speed of the animation without resetting it. It doesn't need to be a smooth transition, for all I care the new speed can be applied at the next iteration... I only want to avoid a visual snap or any kind of reset upon applying the change. Once an animation is set, I have no idea how to access and update its duration parameter. Does anyone have any suggestions?
When using console.log on this.data.anim I'm rightfully told it's an animation object. I tried using JSON.stringify to get more information but nothing relevant is printed. this.data.anim.duration returns undefined so the setting must be stored under some other property. Even if I know that property, I'd like to be sure web browsers will agree with me changing it like this.data.anim.options.duration = new_duration.
You can wait for the end of an iteration before changing the animation duration if that is what is required.
This snippet only sets an event listener for animationiteration event when you click the button to increase the speed.
function upthespeed() {
const div = document.querySelector('div');
div.addEventListener('animationiteration', function() {
div.style.animationDuration = '1s';
});
document.querySelector('button').style.display = 'none';
}
div {
width: 10vmin;
height: 10vmin;
background-color: magenta;
animation: move 10s linear infinite;
}
#keyframes move {
0% {
transform: translateX(50vw);
}
50% {
transform: translateX(0);
}
100% {
transform: translateX(50vw);
}
}
<div></div>
<button onclick="upthespeed()">Click me to increase the speed at the end of the next iteration (you may have to wait!)</button>
The value for the animation duration isn't in the Animation object itself but in the CSS animation-duration property for the Element: so this.data_actors_self.style.animationDuration = new_duration will do the job. It will however restart the animation if it is being played, but if I understand correctly that isn't a problem for you.
Edit: To change the animation's duration without restarting it, all you have to do is set the value of anim.startTime to what it was before. For example:
const startTime = anim.startTime;
this.data_actors_self.style.animationDuration = new_duration
anim.startTime = startTime;
I am making a jackpot game with a selector very similar to this one
I have absolutely no idea where to start. My first thought was to use an array of randomly selected numbers sent from the server side to avoid cheating and animate those with jquery or css.
Then i thought about useing just jquery since i know it better and having the blink interval be a recursive fucnction that returns the values for easing speed i want. (the values would be pretty much exactly like in the video, no more than 3-4 seconds).
$('.blink').blink(); // default is 500ms blink interval.
$('.blink').blink(100); // causes a 100ms blink interval.
But now I am at a loss for where to get started since this has to be mobile friendly. What would you do?
UPDATE
$( document ).ready(function() {
var time = 0;
var diff = 50;
var minTime = 0;
var maxTime = 7000;
function easeInOutExpo(t, b, c, d) {
t /= d;
return c*t*t*t + b;
};
$("#clickme").click(function() {
for (var i = 0, len = diff; i <= len; i++) {
(function(s) {
setTimeout(function() {
$('#book').html("Page " + s + " turned");
}, time);
})(i); //<--------------i have no clue what this does------------
time = easeInOutExpo(i, minTime, maxTime, diff);
}
});
});//document ready
I've gotten the basic mechanic down, but when you click on it a second time instead of 50 it goes to 0. this is not good behavior as I am going to use these numbers to iterate through a randomly generated array.
Can anyone explain this behaviour? I've included a JS fiddle here. Thank you!
You can use simple css animation.
#keyframes blink {
0% { background-color:red; }
10% { background-color:purple; }
20% { background-color:gray; }
30% { background-color:green; }
40% { background-color:white; }
50% { background-color:cyan; }
65% { background-color:yellow; }
100% { background-color:black }
}
.Blink{
animation: blink 2s 1 ease-out;
background-color:black;
height:100px;
width:100px;
}
<div class="Blink">
I have the following code snippet:
function animate()
{
testdiv.style.transitionDuration="2500ms"
testdiv.style.transitionTimingFunction="linear"
testdiv.style.transform="rotate(45deg)"
window.requestAnimationFrame(animate)
}
window.requestAnimationFrame(animate)
This rotates the div 45 degrees and is working.
How can I turn this into an infinite animation loop so that the animation
restarts automatically (from 0 degrees)?
It doesn't make sense to use requestAnimationFrame for either your current code, or the code you want to change to.
For the current code, you're setting a style and then letting CSS take over. There's no need to do anything after time has passed.
To change it to reset and repeat the loop, you want to trigger the new code when the animation has finished, not when the browser is ready to render a new frame. To do that, listen for the transitionend event and then remove the transform value to set it back to the default.
var testdiv = document.querySelector("div");
testdiv.addEventListener("transitionend", animate);
setTimeout(animate, 100);
function animate() {
if (testdiv.style.transform) {
testdiv.style.transform = "";
} else {
testdiv.style.transform = "rotate(45deg)";
}
}
body {
padding: 100px;
}
div {
transition-Duration: 2500ms;
transition-Timing-Function: linear;
}
<div>....</div>
Hi try with below code.
var FPS = 24; //Frame per second.
var prevTime,curTime;
function animate()
{
curTime = new Date();
if(prevTime === undefined || (curTime - prevTime) >= 1000/FPS)
{
testdiv.style.transitionDuration="2500ms"
testdiv.style.transitionTimingFunction="linear"
testdiv.style.transform="rotate(45deg)"
prevTime = curTime;
}
window.requestAnimationFrame(animate);
}
window.requestAnimationFrame(animate)
I trying to make what appears to the user to be an image fader. A string of images fade into each other. All the solutions that I found were complex, and normally required an for every image. I've come up with what should be a simple solution. It's working 90% on Firefox/Chrome/IE11 on Windows. On Android Chrome it's having issues.
Basically my idea is, I have two divs, absolutely positioned, one on top of the other. Both start with a background, sized to cover. The top one fades out, revealing the bottom one, and at the end of the animation, the background-image of the top one (current hidden) is changed to image 3. After a pause, it fades back in, and the background-image of the bottom one is changed to image 4. This repeats indefinitely.
HTML:
<div class="slideshow" id="slideshow-top"></div>
<div class="slideshow" id="slideshow-bottom"></div>
CSS:
.slideshow {
display:block;
background-size:cover;
width: 100%;
height: 100%;
position:absolute;
top:0;
left:0;
}
#slideshow-top {
z-index:-5;
background-image:url(http://www.andymercer.net/wp-content/uploads/2013/12/slider-1.jpg);
}
#slideshow-bottom {
z-index:-10;
background-image:url(http://www.andymercer.net/wp-content/uploads/2013/12/slider-2.jpg);
}
Javascript:
var url_array = [
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-1.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-2.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-3.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-4.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-5.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-6.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-7.jpg',
'http://www.walldoze.com/images/full/2013/12/04/wallpapers-desktop-winter-nature-x-wallpaper-backgrounds-natureabstract-designs-interesting-hd-19045.jpg'
];
var count = 1;
setInterval(function() {
if (count%2) { // Fade In
jQuery('#slideshow-top').animate({opacity:0}, '200000', function() {
jQuery('#slideshow-top').css('background-image','url('+url_array[count]+')');
});
}
else { //Fade Out
jQuery('#slideshow-top').animate({opacity:1}, '200', function() {
jQuery('#slideshow-bottom').css('background-image','url('+url_array[count]+')');
});
}
count = (count == url_array.length-1 ? 0 : count + 1);
}, 2000);
http://jsfiddle.net/5eXy9/
As seen in the Fiddle above, this mostly works. However, it seems to ignore the length of the animation. Using .fadeOut has the same effect. I've tried going from 200 to 20000, and there doesn't seem to be a difference.
I'm not sure if this is tied into the other issue, which is that on Android (Galaxy S4, Chrome, Android 4.x), the animation doesn't occur at all. It simply changes images. Any ideas?
EDIT: Jan 10 - Timing problem is fixed, but the main issue (Android) is still unsolved. Any thoughts?
The interval keeps going, so when increasing the animation speed, you have increase the interval speed as well.
The way you've built this, you should always keep the speed of both animations equal to the interval, or if you need a delay, increase the interval compared to the animations so it at least has a higher number than the highest number used in the animations.
The reason changing the speed doesn't work at all for you, is because it should be integers, not strings, so you have to do
jQuery('#slideshow-top').animate({opacity:0}, 200000, function() {...
// ^^ no quotes
I would do something like this
var url_array = [
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-1.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-2.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-3.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-4.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-5.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-6.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-7.jpg',
'http://www.walldoze.com/images/full/2013/12/04/wallpapers-desktop-winter-nature-x-wallpaper-backgrounds-natureabstract-designs-interesting-hd-19045.jpg'];
var count = 1;
var speed = 2000,
delay = 1000;
$.each(url_array, function(source) { // preload
var img = new Image();
img.src = source;
});
setInterval(function () {
if (count % 2) { // Fade In
jQuery('#slideshow-top').animate({
opacity: 0
}, speed, function () {
jQuery('#slideshow-top').css('background-image', 'url(' + url_array[count] + ')');
});
} else { //Fade Out
jQuery('#slideshow-top').animate({
opacity: 1
}, speed, function () {
jQuery('#slideshow-bottom').css('background-image', 'url(' + url_array[count] + ')');
});
}
count = (count == url_array.length - 1 ? 0 : count + 1);
}, speed + delay);
FIDDLE
I am trying to animate a div moving 200px horizontally in JavaScript.
The code below makes it jump the pixels, but is there a way to make it look animated without using jQuery?
function () {
var div = document.getElementById('challengeOneImageJavascript');
div.style.left = "200px";
}
Here is a basic animation setup:
function animate(elem,style,unit,from,to,time) {
if( !elem) return;
var start = new Date().getTime(),
timer = setInterval(function() {
var step = Math.min(1,(new Date().getTime()-start)/time);
elem.style[style] = (from+step*(to-from))+unit;
if( step == 1) clearInterval(timer);
},25);
elem.style[style] = from+unit;
}
To use:
animate(
document.getElementById('challengeOneImageJavascript'),
"left","px",0,200,1000
);
This example will animate the given element to slide linearly from 0px to 200px over a time of 1 second (1000 ms).
You can easily do this through CSS3-Transition :
#challengeOneImageJavascript {
-webkit-transition: left .2s;
-moz-transition: left .2s;
-o-transition: left .2s;
transition: left .2s;
}
Though, it is not supported by IE9 and earlier browser versions.
I did a ton of research, and I finally learned how to do it really well.
I like to place my program in a window.onload function, that way it dosn't run the code until the page has finished loading.
To do the animation, make a function(I'll call it the draw function) and call it what ever you want except reserved words, then at the very end of the draw function call the requestAnimationFrame function and give it the name of the function to be called next frame.
Before the requestAnimationFrame function can be used it must be declared.
See the code below:
window.onload = function() {
function draw() { // declare animation function
context.fillStyle = "white";
context.fillRect(0, 0, 400, 400);
requestAnimationFrame(draw); // make another frame
}
var requestAnimationFrame = // declare the
window.requestAnimationFrame || // requestAnimationFrame
window.mozRequestAnimationFrame || // function
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
draw(); // call draw function
}
Note: Nothing after the line that calls the draw function will run, so you need to put everything you want to run before the line that calls the draw function.
You would have to use a javascript timeout function, and change the css value a little at a time. The easiest way would be to increment by a set amount each time until a threshold is reached, which would give you a linear animation, which would look clunky and amateurish compared to jQuery's default swing animation which follows a bezier curve approximately like an s-curve.
Untested code should do the linear animation
var lefty = 0;
var animate = function(){
lefty += 20;
var div = document.getElementById('challengeOneImageJavascript');
div.style.left = lefty +"px";
if(lefty < 200)
setTimeout(animate(),100);
}
animate()
n.b. there are lots of improvements to make to that block of code, but it should get you going...
With JavaScript, you will have to use setInterval function or this is how it can be done in jQuery:
$('#challengeOneImageJavascript').animate({left: '=-5'});
Adust value (5) as per your needs as well as direction via =- or =+
With Vanilla JavaScript:
var interval;
var animate = function(id, direction, value, end, speed){
var div = document.getElementById(id);
interval = setInterval(function() {
if (+(div.style) === end) {
clearInterval(interval);
return false;
}
div.style[direction] += value; // or -= as per your needs
}, speed);
}
And you can use it like:
animate('challengeOneImageJavascript', 'left', 5, 500, 200);
To stop animation any time, you would do:
clearInterval(interval);
Note: This just a very quick way to do it to give you an idea.
Simplest way via css.
https://jsfiddle.net/pablodarde/5hc6x3r4/
translate3d uses hardware acceleration running on GPU.
http://blog.teamtreehouse.com/increase-your-sites-performance-with-hardware-accelerated-css
HTML
<div class="movingBox"></div>
CSS
.movingBox {
width: 100px;
height: 40px;
background: #999;
transform: translate3d(0,0,0);
transition: all 0.5s;
}
.moving {
transform: translate3d(200px,0,0);
background: #f00;
}
JavaScript
const box = document.getElementsByClassName('movingBox')[0];
setTimeout(() => {
box.className += ' moving';
}, 1000);
CustomAnimation is a small libary for animating html elements which is written in pure js.You can use this libary.