What did I do wrong? My skill bars are dancing. After loading I want to fixed them.
Check my pen here : http://codepen.io/anon/pen/KdEeWW
$(window).scroll(function() {
if ($(this).scrollTop() > 300) {
$('progress').each(function() {
var max = $(this).val();
$(this).val(0).animate({
value: max
}, {
duration: 2000,
easing: 'easeOutCirc'
});
});
};
});
Your skillbars were dancing because you have written the event on scroll. So if you scroll twice before completion of animation, then it will begin again and also you are not checking whether your animation has been performed.
Just .stop the animation before animating as below:
$(this).stop().val(0).animate({
value: max
}, {
duration: 2000,
easing: 'easeOutCirc'
});
Fiddle DEMO
Update
There is a bug in the way you are doing it right now. Your original value gets overridden every time you scroll thus giving space for less progress display every time. So what you need to do is, store original value in some data-* attribute of each element and set value every time from original value and thus you can also make you value=0 each time. Below changes will accommodate you with the above effect.
HTML
<progress value="80" data-originalvalue="80" max="100"></progress>
//^^^^To store original value
<span>JavaScript/jQuery</span>
<progress value="70" data-originalvalue="70" max="100"></progress>
<span>HTML5/CSS3</span>
<progress value="60" data-originalvalue="60" max="100"></progress>
<span>NodeJS</span>
<progress value="70" data-originalvalue="70" max="100"></progress>
<span>Java/PHP</span>
<progress value="60" data-originalvalue="60" max="100"></progress>
<span>MySQL</span>
<progress value="80" data-originalvalue="80" max="100"></progress>
<span>Photoshop</span>
You JS now would be
$(window).scroll(function() {
if ($(this).scrollTop() > 300) {
$('progress').each(function() {
var max = $(this).data('originalvalue'); //get from data-originalvalue attribute
$(this).val('0').stop().animate({
value: max
}, {
duration: 2000,
easing: 'easeOutCirc'
});
});
};
});
Updated DEMO
Now if you want it to animate only once when it hits users view, you just need to set a global variable value and add one more condition, as below:
var isAnimated=false; //global variable
$(window).scroll(function() {
if ($(this).scrollTop() > 300 && !isAnimated) {//Also check if animated
$('progress').each(function() {
var max = $(this).data('originalvalue');
$(this).val('0');
$(this).stop().animate({
value: max
}, {
duration: 2000,
easing: 'easeOutCirc'
});
});
isAnimated=true;//once done set it to true so that animation will not repeat.
};
});
One time animation demo
It is because you set your value 0 everytime. you can try this. It is easy to implement and you don't need to maintain all this.
http://mynameismatthieu.com/WOW/
Related
I try to make a rotationg block, which rotation speed is controlled by <input type="range". The problem is that I can't find solution that doesn't restart animation when speed updates.
I tried three variants:
Directly set CSS animation speed by JS. — restarts animation;
jQuery's animate — doesn't work with transforms;
Library anime.js — it has method for speed changing but it also
restarts animation (or just makes block jump, it's unclear)
What method allows to create smoothly changing by JS animation?
let block = anime({
targets: '#transforms .block',
rotateY: '360',
easing: 'linear',
loop: true,
duration: 1000,
});
var el = document.querySelectorAll('#range')[0];
el.addEventListener('change', function() {
// console.log(value);
// console.log(pos);
var value = this.value;
anime.speed = value/20;
// console.log(block);
})
.block {
width: 500px;
height: 300px;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.js"></script>
<div id="transforms">
<div class="block"></div>
</div>
<input id="range" type="range" min="0" max="20" step="1" value="10">
anime.js example code On Codepen
With velocity-animate library you can do a trick this way:
Velocity.animate(this.yourElement, {
rotateZ: `${angle}deg`,
duration: yourSpeed
})
I guess triggering the speed change at the end of the animation cycle is what you need. However with this package i was unable to attach a transitionend event listener to any of the two divs. It won't trigger. So digging into this library i suppose you may achieve a similar task by attaching a run property to the anime options object which takes a function as value and invokes it multiple times by passing a progress argument. Once this progress argument is 100 we can make our speed change operation if the speed has changed (newSpeed !== void 0).
Don' let void 0 confuse you. It's just a perfect undefined value which i prefer to use when comparing undefined values.
let block = anime({
targets : '#transforms .block',
rotateY : '360',
easing : 'linear',
loop : true,
duration: 1000,
run : anim => anim.progress === 100 && newSpeed !== void 0 && (anime.speed = newSpeed, newSpeed = void 0)
});
var range = document.getElementById('range'),
newSpeed = void 0; // perfect undefined
anime.speed = range.value/20;
range.addEventListener('change', function(e) {
newSpeed = e.target.value/20;
});
.block {
width: 500px;
height: 300px;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.js"></script>
<div id="transforms">
<div class="block"></div>
</div>
<input id="range" type="range" min="0" max="20" step="1" value="10">
I'm trying to use input range moving one by one. For exemple here is my slider :
<input id="replay-input" type="range" min="0" max="100" step="1" value="0">
Really basic. But the problem is that you can freely move from 5 to 89 by one click. What I would like to achieve is to increment or decrements only by one so my value will look like this is if I move the cursor :
0 -> 1 -> 2 -> 3 -> 4
Then if I go back :
4 -> 3 -> 2 -> 1 -> 0
With big max like 5000 we have missing steps because there is too many values on a small area :
4800 -> 4799 -> 4790 -> 4785
Is there a way to avoid this ? One idea may be to use JS and store value and only allow change of one but maybe there is something more simple in HTML ?
https://jsfiddle.net/vcoyxg4v/5/
Thanks !
I would not suggest limiting the default functionality of the slider control, as people expect it to work in a certain way: think also of dragging the slider, using the arrow/page/home/end keys when the control has focus, ...
But for the sake of the exercise, here is code that will make the slider value only increase/decrease with 1. So if you drag, the value will slowly catch up with the mouse position. This solution uses a data property to keep track of the previous value:
$('#replay-input').data({
was: $('#replay-input').val()
}).on('input', function () {
var data = $(this).data();
$(this).data({
was: this.value = +data.was + (this.value > data.was || -1)
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="replay-input" type="range" min="0" max="100" step="1" value="0">
Using animation
As an extension to this idea, you could use the animate method to take care of the progression towards the target value:
$('#replay-input').data({
current: $('#replay-input').val()
}).on('input', function () {
var data = $(this).data(),
value = this.value;
$(this).data(data = {
current: this.value = +data.current, // restore previous value
}).stop().animate({ value }, { // ... and animate towards the target
duration: 500, // Experiment with other durations...
easing: 'swing', // Experiment with other easing values...
step: function(val) {
$(this).data({current: this.value}) // accept change
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="replay-input" type="range" min="0" max="100" step="1" value="0">
As indicated in the comments, you can experiment a bit with the animation options duration and ease to tailor it to your needs.
There is a slight visual glitch just after a click because the slider also receives an input event on mouseup.
I have this animated donut that changes value on li hover. However, currently it resets to 0 and then animates to the new value. Ideally it should animated from value to value.
Here's a JSFiddle: http://jsfiddle.net/jme11/xx2Ky/
My JS:
var dial = $('.dial');
dial.knob({
readOnly: true
});
$('.pets > li').on('mouseenter', function () {
var button = $(this);
var myVal = button.data('value');
button.css('backgroundColor', 'yellowgreen').siblings().css('backgroundColor', '#ccc');
dial.stop().animate({
value: myVal
}, {
duration: 200,
easing: 'swing',
step: function () {
dial.val(Math.ceil(this.value)).trigger('change');
},
complete: function () {
dial.val(myVal + '%');
}
});
});
I have located the problem; it's this:
dial.val(myVal + '%');
When you animate something with a val attribute, it automatically uses that val value as its starting point. However, your code is setting val to a string. jQuery then gets confused and defaults to 0 the next time you want to animate. If you change the line to
dial.val(myVal);
you'll see it works as desired—with the obvious drawback that you lose your percent sign. You can add it back with knob's format feature, seen here, but I can't get it to work in your jsFiddle.
I'm trying to modify a jQuery knob plugin to use as an animated chart.
This is what I have so far:
HTML:
<ul id="chart">
<li rel="100">Cats</li>
<input class="knob animated donut" value="0" rel="70" />
Javascript:
$('.knob').each(function () {
var $this = $(this);
var myVal = $this.attr("rel");
$(this).knob({
readOnly: true,
displayInput: false,
bgColor: "cccccc",
fgColor: "e60022"
});
$({
value: 0
}).animate({
value: myVal
}, {
duration: 1000,
easing: 'swing',
step: function () {
$this.val(Math.ceil(this.value)).trigger('change');
}
})
});
$('#chart > li').mouseover(function(){
$('#donut').text($(this).attr('rel'));
});
I'd like to be able to hover over the <li> element and use the rel value to apply it to the chart. I think I might need to include some JS to redraw the chart on hover though as well, but not sure how to do that either (I don't have much JS knowledge).
Any help is appreciated.
DEMO
You need to set the animate properties in the event handler. So, initialize your "knob" element as you did, then in the event handler retrieve the values and run the animation.
In the demo I used a data attribute (it just makes more sense to me), not the rel attribute, but the following should work with your markup:
var donut = $('.knob');
donut.knob({readOnly: true,
displayInput: false,
});
$('#chart > li').on('mouseenter', function(){
var myVal = $(this).attr('rel');
donut.stop().animate({value: myVal}, {
duration: 200,
easing: 'swing',
step: function () {
donut.val(Math.ceil(this.value)).trigger('change');
}
});
});
HTML: change the input to use the data attributes for color, as there is a bug in FF
<input class="knob" data-fgColor="#e60022" data-bgColor="#ccc" value="" />
In my code below, I want to change the initial value with a slider. The slider works and everything, but it's not changing the values of the timeout, shown under the $('ul.<?php echo $this->session->userdata('username'); ?>').innerfade({ line.
The value of slider in the line $('#ex1').on('slide', function(slider) is equal to the value of the input-form attribute data-slider-value which is 100.
Now, when I start to adjust the input slider, it will change the attribute from its initial value of 100 to whatever the user slides to.
But the problem is, the slider won't change the values inside the jquery code...
So to make it more clear:
In the JS code, the variable 'value' is declared, but not yet initialized to a value.
The variable 'value' is then assigned to 'slider.value'
And so the logical conclusion is that the 'timeout' variable should change dynamically, according to the values inputted by the slider.
<!-- Start slider -->
<p>
<input id="ex1" data-slider-id='ex1Slider' type="text" data-slider-min="1" data-slider-max="1000" data-slider-step="1" data-slider-value="100"/>
</p>
<script type="text/javascript">
$(document).ready(
function(){
var value;
$('#ex1').slider();
$('#ex1').on('slide', function(slider)
{
value = slider.value;
});
$('ul.<?php echo $this->session->userdata('username'); ?>').innerfade({
speed: 0,
timeout: value,
type: 'sequence',
containerheight: '480px'
});
});
</script>
It's normal, your animation is already made. Your have to remake your animation or better, change the option.
edit :
There is the idea (not sure if is the correct syntax) :
//make it
var usernameInnerFace = $('ul.<?php echo $this->session->userdata('username'); ?>').innerfade({
speed: 0,
timeout: value,
type: 'sequence',
containerheight: '480px'
});
//change it
usernameInnerFace.options['timeout'] = new_value;
You cant because the innerfade function runs before the on('slide').
On sliding you should call a function that sets the innerfade like this.
$(document).ready(
function(){
$('#ex1').slider();
$('#ex1').on('slide', function(slider)
{
setFade(slider.value);
});
});
function setFade(value){
$('ul.<?php echo $this->session->userdata('username'); ?>').innerfade({
speed: 0,
timeout: value,
type: 'sequence',
containerheight: '480px'
});
}
The slide function will get 2 args: event and ui. The value of the slider is in the ui object, so I would try this:
$('#ex1').on('slide', function(event, ui) {
value = ui.value;
});
as documented here:
http://api.jqueryui.com/slider/#event-slide