I am trying to let a html element jump by clicking on a button while another animation is running on that element. The animations are triggered in a game loop if conditions are met (flashing if health is critical), or if a button is clicked (jumping if fed).
Problem: every time the loop repeats, the animation function is called again and is put into the queue; flashing wouldn't stop when health is okay again. Clearing the queue in a callback function of the animation only works if it's the default queue ("fx"), but I need several custom queues.
Working with global boolean variables to allow or refuse the animation function to get called are no solution for me because I want the jump() and flash() animations to be used by several html elements.
I read about queuing and starting a 2nd queue on an element in learn.jquery.com and also read the jQuery API documentations about animation and queing but could not find a solution yet.
Check out flashAnimation1(), it's the expected result: queue cleared in callback so the element will stop flashing if triggering stops. But this works on the default (fx) queue only.
letJump1 (no queue) and letJump2 (custom queue) let the element rise or shrink without control.
flashAnimation2() is a flickering mess.
Can you help me please?
let requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || windows.msRequestAnimationFrame;
let cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
let reqAnimF;
let progress = 0;
let lastRender = 0;
let animationOn = false;
const button = document.getElementById("button");
const state = document.getElementById("state");
const jump = document.getElementById("jump");
const block = $("#fadeInAndOut");
const changeStatus = () => animationOn = !animationOn;
const flashAnimation1 = (element) => { $(function() {
element.animate( {opacity: 0}, "fast", "linear" )
.animate( {opacity: 1}, "fast", "linear", ()=> element.clearQueue() );
})
}
const flashAnimation2 = (element) => { $(function() {
element.queue("flash", (next)=> {
element.animate( {opacity: 0}, {
duration: "fast",
easing: "linear",
queue: "flash"
}).animate( {opacity: 1}, {
duration: "fast",
easing: "linear",
queue: "flash",
complete: element.clearQueue()
});
next();
}).dequeue("flash");
});
};
// Jumping: no queue
const letJump1 = (element) => { $(function() {
element.animate( {width: "+=50", height: "+=20"}, {
duration: "fast",
queue: false,
always: () => {
element.animate( {width: "-=50", height: "-=20"}, {
duration: "fast",
queue: false
});
}
}
);
})};
// Jumping queued to another queue
function letJump2(element) {
$(function() {
element.queue("jump", function(next) {
element.animate({width: "+=50", height: "+=20"}, {
duration: "fast",
queue: "jump"
})
.animate( {width: "-=50", height: "-=20"}, {
duration: "fast",
queue: "jump"
});
next();
}).dequeue("jump");
})
};
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
/* function update(progress) {} */
function draw() {
state.innerHTML = animationOn;
if (animationOn) {
flashAnimation2(block);
}
}
function loop(timestamp) {
progress = timestamp - lastRender;
/* update(progress); */
draw();
lastRender = timestamp;
reqAnimF = requestAnimationFrame(loop);
}
button.addEventListener("click", changeStatus);
//jump.addEventListener("click", letJump1(block)); // button is dead for some reason
reqAnimF = requestAnimationFrame(loop);
.center {
position: relative;
margin: auto;
width: 300px;
height: 300px;
text-align: center;
border: 1px solid red;
}
button {
margin: 0 0 20px;
}
#fadeInAndOut {
margin: auto;
width: 100px;
height: 100px;
background-color: black;
}
#jump {
position: absolute;
left: 50%;
bottom: 0;
transform: translateX(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="center">
<h1 id="state"></h1>
<button type="button" id="button">Flash on/off</button>
<div id="fadeInAndOut"></div>
<button type="button" id="jump" onclick="letJump1(block)">Jump</button>
</div>
Related
I've just created a simple animation function that moves a box from left to right. The problem is when the animation runs the box becomes a rectangle when it animates so the proportion of the box shape is gone which is not what I want, how can you retain the shape of the box through the animation. When you slow the animation down to 2 seconds the box retains its shape but when you speed up the animation then it becomes skewed. How do you prevent this from happening?
function animate(...args) {
let starttime = new Date().getTime();
let requestID;
if(args.length == 5) {
args = { el: args[0], props: args[1], duration: args[2], step: args[3], callback: args[4] };
} else {
args = { el: args[0], props: args[1], duration: args[2], callback: args[3] };
}
function moveit(args) {
var timestamp = new Date().getTime();
var runtime = timestamp - starttime;
var progress = runtime / args.duration;
progress = Math.min(progress, 1);
for(const prop in args.props) {
let dist = parseInt(args.props[prop].substring(0, args.props[prop].length - 2), 10);
args.el.style[prop] = (dist * progress).toFixed(2) + 'px';
}
if(args.step != undefined) {
args.step(progress);
}
if (runtime < args.duration){ // if duration not met yet
requestID = requestAnimationFrame(moveit.bind(new Date().getTime(), args));
} else {
args.callback();
cancelAnimationFrame(requestID);
}
}
requestAnimationFrame(moveit.bind(new Date().getTime(), args));
}
window.addEventListener('load', function(event) {
//alert('Hello World')
document.getElementById('reset')
.addEventListener('click', function(event) {
document.getElementById('box').setAttribute('style', '')
});
document.getElementById('play')
.addEventListener('click', function(event) {
animate(document.getElementById('box'), { left: '400px' }, 500, function(step) {
}, function() {
});
});
});
.box {
background: red;
width: 50px;
height: 50px;
position: relative;
top: 0;
left: 0;
}
.controls {
position: relative;
top: 20px;
}
<div id="box" class="box"></div>
<div class="controls">
<button id="reset">reset</button>
<button id="play">play</button>
</div>
I want a counter animation which is triggered only when webpage reaches that certain part. For example, the js file would be this. I want the count to start only when the page reaches that certain section.
const counters = document.querySelectorAll('.counter');
const speed = 200; // The lower the slower
counters.forEach(counter => {
const updateCount = () => {
const target = +counter.getAttribute('data-target');
const count = +counter.innerText;
// Lower inc to slow and higher to slow
const inc = target / speed;
// console.log(inc);
// console.log(count);
// Check if target is reached
if (count < target) {
// Add inc to count and output in counter
counter.innerText = count + inc;
// Call function every ms
setTimeout(updateCount, 1);
} else {
counter.innerText = target;
}
};
updateCount();
});
Yo can easily do it using Jquery
$(document).ready(function() {
$(window).scroll(function() {
if ($(document).scrollTop() > 50) {
$("div").css("background-color", "#111111");
} else {
$("div").css("background-color", "transparent");
}
});
});
div {
height: 120vh;
transition-duration: 0.5s;
}
<div>
Scroll to Change Background
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
You can use Intersection Observer to do that
const $observeSection = document.querySelector('#second');
const options = {
root: null,
rootMargin: '0px',
threshold: 0.5
};
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.intersectionRatio > options.threshold) {
$observeSection.classList.add('yellow');
} else {
$observeSection.classList.remove('yellow');
}
});
}, options);
observer.observe($observeSection);
main {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
main section {
width: 100vw;
height: 100vh;
}
#first {
background: red;
}
#second {
background: blue;
}
#third {
background: green;
}
.yellow {
background: yellow!important;
}
<main>
<section id="first"></section>
<section id="second"></section>
<section id="third"></section>
</main>
In this example, I observe the second section, and when the scroll come to the middle of the section (threshold: 0.5), I add a class to change the color of this section.
Be careful if you need to handle legacies browsers as you can see here :
https://caniuse.com/#feat=intersectionobserver
You don't need jquery to achieve this.
Here is a VanillaJS solution:
window.onscroll = (e) => {
e.stopPropagation();
window.pageYOffset > 50 && console.log("do smh");
}
Have a java script table that connects to a web socket and update table.
I want to use jquery falsher to flash if the value is greater than and less than the current value.
Update Table function
var child = createStockNode(stock, type, template);
// try to replace
var stockNode = document.querySelector(type + "[data-symbol=" + stock.n + "]");
if (stockNode) {
table.replaceChild(child, stockNode);
} else {
// add new stock
table.appendChild(child);
}
//stock.c ===> close Price
var bg = stock.c < 0
? '255,148,148' // red
: '154,240,117'; // green
$row = child;
$row.flash(bg, 1000);
//child.flash(bg , 1000)
}
Jquery flusher function
jQuery.fn.flash = function (color, duration) {
var current = this.css('backgroundColor');
this.animate({ backgroundColor: 'rgb(' + color + ')' }, duration / 2)
.animate({ backgroundColor: current }, duration / 2);
};
Error Uncaught ReferenceError: $row is not defined
Jquery is defined in my html page as well.
EDIT
The jQuery documentation about the animate() function specifies :
For example, width, height, or left can be animated but background-color cannot be, unless the jQuery.Color plugin is used
I'd recommand to use CSS3 for thins kind of animation.
Still, here are to ways of flashing.
(function($) {
$.fn.blink = function(options) {
var defaults = {
delay: 500
};
var options = $.extend(defaults, options);
return this.each(function() {
var obj = $(this);
var blink = false;
setInterval(function() {
if (blink) {
$(obj).css('background', options.from);
} else {
$(obj).css('background', options.to);
}
blink = !blink;
}, options.delay);
});
}
}(jQuery))
$('#purejQuery').blink({
delay: 500,
from: "red",
to: "blue"
});
/* The animation code */
#keyframes blinking {
0%{
background-color: red;
}
50%{
background-color: red;
}
51%{
background-color: blue;
}
100%{
background-color: blue;
}
}
#pureCSS {
width: 100px;
height: 100px;
animation: blinking 1s infinite;
}
#purejQuery {
width: 100px;
height: 100px;
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="pureCSS">Done by CSS</div>
<div id="purejQuery">Done by jQuery</div>
Official older link for Owl 1 progress bar doesn't even work anymore but I have found working example but also for Owl 1.
I have tried to use the code but I am not able to set it to work with Owl 2
http://codepen.io/anon/pen/GrgEaG
$(document).ready(function() {
var time = 7; // time in seconds
var $progressBar,
$bar,
$elem,
isPause,
tick,
percentTime;
//Init the carousel
$("#owl-demo").owlCarousel({
items: 1,
initialized : progressBar,
translate : moved,
drag : pauseOnDragging
});
//Init progressBar where elem is $("#owl-demo")
function progressBar(elem){
$elem = elem;
//build progress bar elements
buildProgressBar();
//start counting
start();
}
//create div#progressBar and div#bar then prepend to $("#owl-demo")
function buildProgressBar(){
$progressBar = $("<div>",{
id:"progressBar"
});
$bar = $("<div>",{
id:"bar"
});
$progressBar.append($bar).prependTo($elem);
}
function start() {
//reset timer
percentTime = 0;
isPause = false;
//run interval every 0.01 second
tick = setInterval(interval, 10);
};
function interval() {
if(isPause === false){
percentTime += 1 / time;
$bar.css({
width: percentTime+"%"
});
//if percentTime is equal or greater than 100
if(percentTime >= 100){
//slide to next item
$elem.trigger('owl.next')
}
}
}
//pause while dragging
function pauseOnDragging(){
isPause = true;
}
//moved callback
function moved(){
//clear interval
clearTimeout(tick);
//start again
start();
}
//uncomment this to make pause on mouseover
// $elem.on('mouseover',function(){
// isPause = true;
// })
// $elem.on('mouseout',function(){
// isPause = false;
// })
});
#bar{
width: 0%;
max-width: 100%;
height: 4px;
background: #7fc242;
}
#progressBar{
width: 100%;
background: #EDEDED;
}
the callback functions are not being fired because you're calling them on events that don't exist in owlCarousel 2. The events are prefixed with 'on'.
So if you call them like this:
$("#owl-demo").owlCarousel({
items: 1,
onInitialized : progressBar,
onTranslate : moved,
onDrag : pauseOnDragging
});
The functions will be called. Check the owlCarousel event docs here.
Check out this CodePen for an example progressbar in OwlCarousel using CSS transitions.
After running into the need for a progress bar I stumbled across this question, as well as the example of a progress bar with owl-carousel v1.
Using v2.3.3 I came up with the following js/css-animation based solution:
javascript:
const $slider = $('.my-slider')
const SLIDER_TIMEOUT = 10000
$slider.owlCarousel({
items: 1,
nav: false,
dots: false,
autoplay: true,
autoplayTimeout: SLIDER_TIMEOUT,
autoplayHoverPause: true,
loop: true,
onInitialized: ({target}) => {
const animationStyle = `-webkit-animation-duration:${SLIDER_TIMEOUT}ms;animation-duration:${SLIDER_TIMEOUT}ms`
const progressBar = $(
`<div class="slider-progress-bar"><span class="progress" style="${animationStyle}"></span></div>`
)
$(target).append(progressBar)
},
onChanged: ({type, target}) => {
if (type === 'changed') {
const $progressBar = $(target).find('.slider-progress-bar')
const clonedProgressBar = $progressBar.clone(true)
$progressBar.remove()
$(target).append(clonedProgressBar)
}
}
})
scss
.slider-progress-bar {
/* your progress bar styles here */
.progress {
height: 4px;
background: red;
animation: sliderProgressBar ease;
}
}
.my-slider:hover {
.slider-progress-bar .progress {
animation-play-state: paused;
}
}
#keyframes sliderProgressBar {
0% {
width: 0%;
}
100% {
width: 100%;
}
}
var track = Ti.UI.createView({
width: 100, height: 30,
backgroundColor: '#e8e8e8',
top: '30%'
});
var progress = Ti.UI.createView({
left: 0,
width: 1, height: 30,
backgroundColor: '#00c36a'
});
track.add(progress);
Ti.UI.currentWindow.add(track);
Ti.UI.currentWindow.addEventListener('open', function () {
progress.animate({
width: 100,
duration: 10000,
repeat: 6
});
I have made a custom progress bar using two views and .animate function. How do I do implement some functionality everytime a repetition of progress.animate() is completed
Here is an example of JQuery animation Complete callback.
var cbFunction = function(){
//Animation Complete Callback function
alert('animation completed!');
}
//Test buntton click event
$(".testbutton").on('click',function(){
//Launch animation
$(".test").animate({width:100},1000,cbFunction);
});
.test{
background-color:#ff0000;
width:200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button class="testbutton">TEST</button>
<div class="test">-</div>
Try this:
var repeat = 6;
var rep = 0;
var autoProgress = function() {
createAnimation(progress, function() {
alert('complete nÂȘ-> ' + rep);
rep++;
if (rep < repeat) {
autoProgress();
}
});
};
/**
* create animation to view
* #param Ti.UI.View view
* #param {Function} callback
*/
var createAnimation = function(view, callback) {
callback = _.isFunction(callback) ? callback : function() {
};
//create animate
var animate = Titanium.UI.createAnimation({
width : 100,
duration : 10000,
});
/**
* Fired when the animation complete.
*/
animate.addEventListener('complete', function() {
view.width = 0;
callback();
});
view.animate(animate);
};
Ti.UI.currentWindow.addEventListener('open', autoProgress);