I have a series of blocks that fall, and when they get to a certain point a grey block (placeholder for dust) appears; it goes away if the block bounces up past a certain point, then reappears when the block falls down again, getting smaller each time impact occurs.
Currently, however, since a class for the grey block is what is being affected, any falling block affects the overall size of the "dust" block despite falling and hitting at different times. I would like to keep track of each dust block separately, so each one changes depending on when the color block it is associated with impacts on the ground.
I've tried using ids - id='smoke"+i+"', $("#smoke"+i).height(40+smokeGlobal); - instead of a single class, but it appears doing that only allows the first block to animate. (I assumed a "for" loop is necessary there, but adding that in seemed to cancel the dust block altogether.)
As always, help would be appreciated. Thanks.
http://jsfiddle.net/pjhoL899/1/
JS:
var links = ["#portfolio", "#hamumu", "#beep", "#jk"];
var linkGlobal;
smokeGlobal = 0;
//home page functions
$(document).ready(function homePage() {
//check collisions
//initial animation
for (var i=0; i<links.length; i++) {
//animate links
$(links[i]).animate({
top: '0'
}, {
duration: 2000*(Math.random()*(2)+1),
easing: 'easeOutBounce',
step: function(y) {
if (y >= -2) {
smokeGlobal -= 2;
linkGlobal = $(this);
linkGlobal.html("<div class='smoke' id='smoke"+i+"'></div>");
$(".smoke").height(40+smokeGlobal);
$(".smoke").fadeTo("fast", 0);
}
}, complete: setTimeout(function() {
linkGlobal.html("");
}, 2000)
});
}
})
Edit, updated
Substituted now for y and $(tween.elem) for $(this) at step function. step function argument tween is one of objects within jquery .animate() ; having several properties , including currently animated element (elem) ; easing ; now ; options - which also has queue property (see .queue()).
For each element within the set links , the currently animated property could be retrieved utilizing tween object , along with the elements' animated position between the start and end of the animated property.
At original post , y could actually be utilized as now argument ; and $(this) for linkGlobal . The tween object should give access to the animated element at the specific portion of the animation required ; for adjustment of the element , animation , callback.
To keep track of each dust block separately , can access that element through .fadeTo() callback , or utilize done callback to adjust effects ; done fires before complete . done also has promise which could be utilized to adjust next animated element . There may be several potential options available to adjust features utilizing .animate().
Try (this pattern)
var links = ["#portfolio", "#hamumu", "#beep", "#jk"];
var linkGlobal;
smokeGlobal = 0;
//home page functions
$(document).ready(function homePage() {
//check collisions
//initial animation
for (var i=0; i<links.length; i++) {
//animate links
$(links[i]).animate({
top: '0'
}, {
duration: 2000*(Math.random()*(2)+1),
easing: 'easeOutBounce',
step: function(now, tween) {
console.log(now, tween);
// substituted `now` for `y`
if (now >= -2) {
smokeGlobal -= 2;
// substituted `$(tween.elem)` for `$(this)`
linkGlobal = $(tween.elem);
linkGlobal.html("<div class='smoke' id='smoke"+i+"'></div>");
// adjust "dust" colors ,
// from checking `tween.elem` `backgroundColor` , `now`
var color = linkGlobal.css("background-color");
$(".smoke").eq(0)
.css("background-color"
, color === "yellow" && now < -1.05 ? "purple" : "orange");
$(".smoke").eq(1)
.css("background-color"
, color === "purple" && now < -0.00025 ? "orange" : "pink");
$(".smoke").eq(2)
.css("background-color"
, color === "pink" && now >= -0.0075 ? "purple" : "yellow");
$(".smoke").eq(3)
.css("background-color"
, color === "orange" && now < -0.003 ? "pink" : "purple");
// alert(now);
$(".smoke").height(40+smokeGlobal);
$(".smoke").fadeTo("fast", 0);
}
}, complete: setTimeout(function() {
linkGlobal.html("");
}, 2000)
});
}
});
jsfiddle http://jsfiddle.net/guest271314/pjhoL899/10/
Related
I'm trying to do something very simple on a progress-bar script but my non-existent knowledges of javascript are making me struggle a little bit.
What I have looks like this :
if (progress == 100) {
var element = document.getElementById("avatar-progress");
element.classList.add("finish");
setTimeout(function () {
$('#avatar-progress').circleProgress(
'value',
0
);
}, 250);
}
if ($('#avatar-progress').circleProgress('value') == 0) {
var element = document.getElementById("avatar-progress");
element.removeAttribute("class");
}
$('#avatar-progress').circleProgress({
value: 0,
size: 156,
fill: { color: "#60bcff" },
emptyFill: "#ffffff",
thickness: 2,
});
Basically what happens with this progress-bar is this :
when the uploading hits 100% : a class is added to #avatar-progress for a cool pulse effect, then, after the requiered delay for the pulse animation, the value is set back to 0, making the progress-bar disapear, and is ready for the next upload.
However, for the script's sake, I have to wait the value has returned to 0 before deleting the class (if I don't the pulse animation won't load again).
And this is what I failed to do, I don't know how to write it, as you see in my code I tried some stuffs :
if ($('#avatar-progress').circleProgress('value') == 0) {
var element = document.getElementById("avatar-progress");
element.removeAttribute("class");
}
but my condition doesn't work. I'm looking for some help to write this line the right way. Thank you for your suggestions
You can actually do both things inside your setTimeout function:
if (progress === 100) {
var element = document.getElementById('avatar-progress');
element.classList.add('finish');
setTimeout(function () {
$('#avatar-progress').circleProgress('value', 0);
element.classList.remove('finish');
}, 250);
}
N.B. don't forget to use triple equals (===) in JavaScript, to ensure your comparison is correct.
I would like to add category icons to a Wordpress page, each icon animated with snap.svg.
I added the div and inside an svg in the loop that prints the page (index.php). All divs are appearing with the right size of the svg, but blank.
The svg has a class that is targeted by the js file.
The js file is loaded and works fine by itself, but the animation appears only in the first div of that class, printed on each other as many times it is counted by the loop (how many posts there are on the actual page from that category).
I added "each()" and the beginning of the js, but is not allocating the animations on their proper places. I also tried to add double "each()" for the svg location and adding the snap object to svg too, but that was not working either.
I tried to add unique id to each svg with the post-id, but i could not pass the id from inside the loop to the js file. I went through many possible solutions I found here and else, but none were adaptable, because my php and js is too poor.
If you know how should I solve this, please answer me. Thank you!
// This is the js code (a little trimmed, because the path is long with many randoms, but everything else is there):
jQuery(document).ready(function(){
jQuery(".d-icon").each(function() {
var dicon = Snap(".d-icon");
var dfirepath = dicon.path("M250 377 C"+ ......+ z").attr({ id: "dfirepath", class: "dfire", fill: "none", });
function animpath(){ dfirepath.animate({ 'd':"M250 377 C"+(Math.floor(Math.random() * 20 + 271))+ .....+ z" }, 200, mina.linear);};
function setIntervalX(callback, delay, repetitions, complete) { var x = 0; var intervalID = window.setInterval(function () { callback(); if (++x === repetitions) { window.clearInterval(intervalID); complete();} }, delay); }
var dman = dicon.path("m136 ..... 0z").attr({ id: "dman", class:"dman", fill: "#222", transform: "r70", });
var dslip = dicon.path("m307 ..... 0z").attr({ id: "dslip", class:"dslip", fill: "#196ff1", transform:"s0 0"});
var dani1 = function() { dslip.animate({ transform: "s1 1"}, 500, dani2); }
var dani2 = function() { dman.animate({ transform: 'r0 ' + dman.getBBox().cx + ' ' + dman.getBBox(0).cy, opacity:"1" }, 500, dani3 ); }
var dani3 = function() { dslip.animate({ transform: "s0 0"}, 300); dman.animate({ transform: "s0 0"}, 300, dani4); }
var dani4 = function() { dfirepath.animate({fill: "#d62a2a"}, 30, dani5); }
var dani5 = function() { setIntervalX(animpath, 200, 10, dani6); }
var dani6 = function() { dfirepath.animate({fill: "#fff"}, 30); dman.animate({ transform: "s1 1"}, 100); }
dani1(); }); });
I guess your error is here:
var dicon = Snap(".d-icon");
You are passing a query selector to the Snap constructor, this means Snap always tries to get the first DOM element with that class, hence why you're getting the animations at the wrong place.
You can either correct that in two ways:
Declare width and height inside the constructor, for example var dicon = Snap(800, 600);
Since you are using jQuery you can access to the current element inside .each() with the $(this) keyword. Since you are using jQuery instead of the dollar you could use jQuery(this).
Please keep in mind this is a jQuery object and probably Snap will require a DOM object. In jQuery you can access the dom object by appending a [0] after the this keyword. If var dicon = Snap( jQuery(this) ); does not work you can try with var dicon = Snap( jQuery(this)[0] );
Additionally, you have several .attr({id : '...', in your code. I assume you are trying to associate to the paths an ID which are not unique. These should be relatively safe since they sit inside a SVG element and I don't see you are using those ID for future selection.
But if you have to select those at a later time I would suggest to append to these a numerical value so you wont have colliding ID names.
I'm playing around with pure JavaScript, so I created a small fade in/out object, to adjust images opacity onmouseover and onmouseout. Fading works fine when the mouseover and mouseout actions are precise:
Start moving the cursor from the white background
Hover over an image
Hover back over the white background
The problem is, as soon as I start to move the mouse "naturally" from one image to another, the fading (or rather the script itself) freezes.
I'm not sure whether it's a animation-speed problem, or there's something I'm missing in the implementation.
If someone has the time to take a look, I would appreciate a peer check, so I can crack the issue and learn new stuff.
Here's a fiddle: http://jsfiddle.net/6bd3xepe/
Thanks!
As I see it, you have one INTERVAL for you FADER, you need one for each IMG.
My jsfiddle fixes this. I added an ALT-attribute to each IMG with "dome" content, so as to circumvent the jsfiddle working on non-cat-images .. ignore that part - commented out below.
There are some fundamental things wrong with the design - keeping track of objects & references is key. Usage of "this" & "that" aren't helping in the current implementation (see comments to OP). Also, on another note, the usage of "toFixed(2)" is not really required IMHO and you can shorten "o = o + 0.1" to "o += 0.1".
JS:
var fader = {
target: document.getElementsByTagName('img'),
interval: [],
speed: 25,
default_opacity: 1,
init: function() {
this.bindEvents();
},
// Get element's opacity and increase it up to 1
fadeIn: function(element) {
var element_opacity = this.getOpacity(element),
that = this,
idx = element.getAttribute('data-idx');
console.log("fI: "+idx+" "+element_opacity);
this.default_opacity = element_opacity.toFixed(2);
this.interval[idx] = setInterval(function() {
if (element_opacity.toFixed(2) < 1) {
element_opacity = element_opacity + 0.1;
element.style.opacity = element_opacity.toFixed(2);
} else {
clearInterval(that.interval[idx]);
}
}, that.speed);
},
// Get current opacity and decrease it back to the default one
fadeOut: function(element) {
var element_opacity = this.getOpacity(element),
that = this,
idx = element.getAttribute('data-idx');
console.log("fO: "+idx+" "+element_opacity);
this.interval[idx] = setInterval(function() {
if (element_opacity.toFixed(2) > that.default_opacity) {
element_opacity = element_opacity - 0.1;
element.style.opacity = element_opacity.toFixed(2);
} else {
clearInterval(that.interval[idx]);
element.removeAttribute('style');
}
}, that.speed);
},
// Get opacity of an element using computed styles
getOpacity: function(element) {
var styles = window.getComputedStyle(element),
opacity = parseFloat(styles.getPropertyValue('opacity'));
return opacity;
},
bindEvents: function() {
var that = this, count = 0;
for (var i in this.target) {
// the whole "dome" is just a fsfiddle hack - otherwise it sees 7 images instead of 4!
//if( this.target[i].alt == "dome" ){
console.log("COUNT: "+count);
this.target[i].setAttribute('data-idx',count);
this.target[i].onmouseover = function() {
that.fadeIn(this);
}
this.target[i].onmouseout = function() {
that.fadeOut(this);
}
count++;
//}
}
}
};
fader.init();
this is my code :
var pane = $('#Container'),
box = $('#PLayer'),
w = pane.width() - box.width(),
d = {},
x = 3;
function newv(v, a, b) {
var n = parseInt(v, 10) - (d[a] ? x : 0) + (d[b] ? x : 0);
return n < 0 ? 0 : n > w ? w : n;
}
$(window).keydown(function (e) { d[e.which] = true; });
$(window).keyup(function (e) { d[e.which] = false; });
setInterval(function () {
box.css({
left: function (i, v) { return newv(v, 37, 39); },
top: function (i, v) { return newv(v, 38, 40); }
});
}, 20);
<div id="Container" class="Container">
<div id="PLayer" class="player" ></div>
</div>
by this code i managed to make the div animate by using the arrow key but how can i make that jumping effect ? like the one used here
Here's a link to a fork of your fiddle:
http://jsfiddle.net/dJut2/
I made two changes:
Jquery wanted top to have an initial value while using the 2-argument callback inside .css(...), so I set it to 50% in CSS: .player{ ... top: 50%; }
I added "gravity" using another ternary check inside the input response/collision function. It checks against whether 38/the up-key is passed as an input case and adds 2 to the top: ... + (a==38 ? 2 : 0)
By the way, verbose variable names or comments could really make your code easier to read. Also, ternary operators aren't as efficient or readable as some if statements. Lastly, you should break your input response and collision functionality into specific cases so you can edit them each specifically later without having to refactor.
Lastly, if you want to simulate a 'jump', you'll need to have some kind of timed input case. This can be accomplished automatically with an acceleration variable (set it to a number, subtract it from the top every frame, and decrement it every frame flooring at 0 when on the ground; the gravity I added can be removed in this case) or some kind of specific animation (subtract 4 every frame for 20 frames).
If you want to do something similar to that platformer game you linked (which is awesome), why not just check out the source code for it? http://taffatech.com/Platformer.js
if(Player.isUpKey == true)
{
if(!Player.jumping){
Player.jumping = true;
Player.velY = -Player.speed*2;
}
}
If you look there you see he's not actually using CSS animations, but recalculating the player's position every frame. If the player hit's the up key, their y velocity is increased, and then every frame this is called to move the player
//gravity would be a numeric variable, this makes the player constantly move
//back downwards when they leave the ground
Player.velY += gravity;
//adjusting the player's position according to new
//calculated x and y velocity
Player.x += Player.velX;
Player.y += Player.velY;
This is similar to how most game engines work, recalculating the scenario and forces each frame so they can constantly react to what's going on. Instead of animations, a physics engine is doing the math and moving things accordingly on screen.
I'm using a simple chunk of code (based of 'ScrollTo Posts with jQuery' which allows you to click a next/previous link and it'll jump through to the top of each post.
I have my HTML structure so it goes post > image > post > image etc.
I'm wondering if it's possible that if you click the next/previous button, it scrolls to the next post as normal, but it hangs/hovers over the images/div inbetween? So it eventually completes it's scroll, but slows down over the divs inbetween.
Here's my jQuery code:
$(function () {
function a(f) {
var b, e, c = [],
d = $(window).scrollTop(),
g = $('.section-slide');
g.each(function () {
c.push(parseInt($(this).offset()['top'], 10))
});
for (e = 0; e < c.length; e++) {
if (f == 'next' && c[e] > d) {
b = g.get(e);
break
}
if (f == 'prev' && e > 0 && c[e] >= d) {
b = g.get(e - 1);
break
}
}
if (b) {
$.scrollTo(b, {
duration: 1400
})
}
return false
}
$('#next,#prev').click(function () {
return a($(this).attr('id'))
});
$('.scrolltoanchor').click(function () {
$.scrollTo($($(this).attr('href')), {
duration: 1400
});
return false
})
});
Assuming your structure will remain static: post -> image -> post -> image etc. you can accomplish this by finding the previous / next image to the post you will be scrolling to, and scrolling to it first, then use the onAfter callback/setting from the $.scrollTo plugin to fire a secondary scroll after a predefined setTimeout like this:
$(function () {
function scroll(direction) {
var scroll, scrollImage, i,
positions = [],
here = $(window).scrollTop(),
collection = $('.post');
collection.each(function () {
positions.push(parseInt($(this).offset()['top'], 10));
});
for (i = 0; i < positions.length; i++) {
if (direction == 'next' && positions[i] > here) {
scroll = collection.get(i);
// Find Image Before Post
scrollImage = $(scroll).prev('.image').get(0);
break;
}
if (direction == 'prev' && i > 0 && positions[i] >= here) {
scroll = collection.get(i - 1);
// Find Image After Post
scrollImage = $(scroll).next('.image').get(0);
break;
}
}
if (scroll) {
// Check if Scroll Image Exists
if (scrollImage){
// Scroll with Image Delay
$.scrollTo(scrollImage, {
duration: 750,
onAfter: function(){
setTimeout(function(){
$.scrollTo(scroll, {
duration: 750
});
}, 1000); // Change the Delay to Increase / Decrease the Hover
}
});
} else {
$.scrollTo(scroll, {
duration: 750
});
}
}
return false;
}
$("#next,#prev").click(function () {
return scroll($(this).attr('id'));
});
$(".scrolltoanchor").click(function () {
$.scrollTo($($(this).attr("href")), {
duration: 750
});
return false;
});
});
You can find an updated fiddle here: http://jsfiddle.net/hfg2v/2/
I hope this helps.
This is happening because you're using a parallax scrolling library (Stellar.js), which makes different elements scroll at different speeds.
A possible fix would be to scroll at a higher speed when no element is in the current viewport until the edge of the next element is just off the screen, then immediately scroll at the original scrolling speed until there are no elements in the viewport again, and keep repeating this until you reach the desired scroll offset.
Edit:
Sorry, something came up while I was writing my answer and I didn't have time to finish the code.
However, after working on it for some time I'm starting to think that my proposed solution wouldn't work. I was thinking something along those lines:
$(window).scrollTo(640, {onAfter: function () {
var scrollRatio = 3;
var distance = 855 - 640;
$(window).scrollTo(855, {
easing: 'linear',
duration: distance * scrollRatio / speed,
onAfter: function () {
var scrollRatio = 1;
var distance = 1200 - 855;
$(window).scrollTo(1200, {
easing: 'linear',
duration: distance * scrollRatio / speed,
onAfter: function () {
var scrollRatio = 3;
var distance = 1280 - 1200;
$(window).scrollTo(1280, {
easing: 'linear',
duration: distance * scrollRatio / speed
});
}
});
}
});
}});
If you paste the previous code in the website provided in the question (http://dev.du.st/field-station/), you'll be taken to the first element, and it will attempt to scroll you to the next one using the method I described. I hardcoded the offset values because I was still experimenting with it. However, I don't think this approach would work since it still feels off. This is because changing instantly speed in the middle of the animation will always be noticeable.
Right now, I think the best way you can mitigate the slow-scrolling feel that parallax scrolling is causing is by using a different easing function. After all, making the background pictures slower, is exactly what you're using parallax scrolling for.
The following code, when ran in your website, would make all animations use 'easeOutCirc' for their easing function by default, after some experimenting, I found it to be the one that makes the scrolling feel least odd:
// Add the jQuery-easing plugin, needed for the more sophisticated easing functions.
$.getScript('//cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js');
// Set easeOutCirc as the default easing.
jQuery.easing.def = 'easeOutCirc';
You can find more easing functions at this website
Once you're done experimenting, if you do decide on using an easing (you can use different ones for scrolling up and down), then you should probably keep the default easing as is, and just change the easing in the scroll animation by adding {easing: EASING_NAME} to your options hash in the scrollTo function. So your code will look something like this:
$.scrollTo($($(this).attr("href")), {
duration: 750,
easing: 'easeOutCirc'
});