Javascript animation flickering when run multiple times - javascript

So this is my first attempt at playing with JS animations. I just modified a simple tutorial to create a border that fades out when you click an element. It works perfectly the first time but every subsequent click it flickers and acts strangely. I can't work out what the issue is.
function move(elem) {
var left = 1
function frame() {
left = left - 0.1 // update parameters
elem.style.border = '6px solid rgba(48, 28, 237, '+left+')';
if (left == 0) // check finish condition
clearInterval(id)
}
var id = setInterval(frame, 100) // draw every 10ms
}
HTML:
<div onclick="move(this)" class="example_path"></div>
Codepen - http://codepen.io/anon/pen/jqrwoo

javascript count float number is inaccuracy,
for example:
console.log(0.1+0.2);
not 0.3,is 0.30000000000000004,
so...
"left = left - 0.1" forever not equal to "0"
should be
"if(left == 0)"
modification
"if(left <= 0)"
I`m sorry my English is not good,express dimness.

Your interval is not clearing. Try this (if) condition:
if (left <= 0) { // check finish condition
clearInterval(id)
// alert("cleared")
}

Related

how to get click duration on pointerdown PhaserJs 3 [duplicate]

I'm creating pinball game using Phaser Framework.
When the ball holder is pressed (please check attached screenshot so you have an idea what I mean ball holder), depending on the press speed, it should move the ball around the spiral channel. So now trying to detect the down pressed duration of the holder.
Here is my code:
var ballButton;
ballButton = game.add.sprite(196, 100, 'ballHolder');
ballButton.inputEnabled = true;
ballButton.events.onInputDown.add(inputDownAction, this);
function inputDownAction(ballButton, pointer) {
/* returns 0 */
console.log( pointer.duration);
}
So pointer.duration is not working and returns 0.
But game.input.activePointer.duration inside update() function is working and returns duration.
if (game.input.activePointer.duration > 200 && game.input.activePointer.duration < 500){
console.log('first range '+game.input.activePointer.duration);
}else if(game.input.activePointer.duration > 500 && game.input.activePointer.duration < 700){
console.log('second range '+game.input.activePointer.duration);
}else if(game.input.activePointer.duration > 700){
console.log('third range '+game.input.activePointer.duration);
}
How can I make it work for specific item/sprite? Any ideas please?
in phaser 3 something like
function update(){
var duration = 0
if( this.input.activePointer.isDown ){
duration++;
}
}
You can get the time from the scene and calculate it with the downTime from the activePointer. So, you can try this approach:
function update(time, delta){
console.log(time - window.game.input.activePointer.downTime);
}
I came to the conclusion that this is the best approach when you want to get the duration on press down key because there is not duration attribute in activePointer anymore(Phaser3). So, this code works on Phaser 3 as well.
I hope it helps!

how to get activePointer pressed duration of sprite in Phaser

I'm creating pinball game using Phaser Framework.
When the ball holder is pressed (please check attached screenshot so you have an idea what I mean ball holder), depending on the press speed, it should move the ball around the spiral channel. So now trying to detect the down pressed duration of the holder.
Here is my code:
var ballButton;
ballButton = game.add.sprite(196, 100, 'ballHolder');
ballButton.inputEnabled = true;
ballButton.events.onInputDown.add(inputDownAction, this);
function inputDownAction(ballButton, pointer) {
/* returns 0 */
console.log( pointer.duration);
}
So pointer.duration is not working and returns 0.
But game.input.activePointer.duration inside update() function is working and returns duration.
if (game.input.activePointer.duration > 200 && game.input.activePointer.duration < 500){
console.log('first range '+game.input.activePointer.duration);
}else if(game.input.activePointer.duration > 500 && game.input.activePointer.duration < 700){
console.log('second range '+game.input.activePointer.duration);
}else if(game.input.activePointer.duration > 700){
console.log('third range '+game.input.activePointer.duration);
}
How can I make it work for specific item/sprite? Any ideas please?
in phaser 3 something like
function update(){
var duration = 0
if( this.input.activePointer.isDown ){
duration++;
}
}
You can get the time from the scene and calculate it with the downTime from the activePointer. So, you can try this approach:
function update(time, delta){
console.log(time - window.game.input.activePointer.downTime);
}
I came to the conclusion that this is the best approach when you want to get the duration on press down key because there is not duration attribute in activePointer anymore(Phaser3). So, this code works on Phaser 3 as well.
I hope it helps!

need help shortening/looping javascript function using loops and alternative to mod

I have an animation that shows one of 8 possible frames depending on the scrolling position on the page. Every time you scroll 20px the next frame is shown until you get to frame 8, then it goes back to frame one after 160px. At the moment if the page is 2000px long I need 100 if statements which seems ridiculous. There must be a way to make it into a few lines using a nice function using loops. A friend said it would be a job for 'mod'but apparently javascript cant do mod or remainders.
I have done an excerpt of the script below but you can see the whole idea here
http://jsfiddle.net/jimmytheman/NnFmn/2/
function scroll() {
if (window.pageYOffset < 20){
setTimeout("document.images['ball'].src=imageArray[0].src",0);
}
else if (window.pageYOffset < 40){
setTimeout("document.images['ball'].src=imageArray[1].src",0);
}
else if (window.pageYOffset < 60){
setTimeout("document.images['ball'].src=imageArray[2].src",0);
}
else if (window.pageYOffset < 80){
setTimeout("document.images['ball'].src=imageArray[3].src",0);
}
You can use modulo in javascript it's % character, http://jsfiddle.net/NnFmn/4/
but you can shorten the code using something like this:
function scroll() {
setTimeout(function() {
document.images['ball'].src = imageArray[window.pageYOffset % 7].src;
}, 0);
return false;
}
http://jsfiddle.net/NnFmn/5/

Image Rotation using pure Javascript

PLEASE DO NOT RECOMMEND JQUERY - I AM DOING THIS EXERCISE FOR LEARNING PURPOSES.
I have implemented a JavaScript, which rotates images (_elementSlideChange) on a timer, using a set interval of 10 seconds. Also I have added a slide functionality to this, which is 7 milliseconds (_slideImage).
The image rotates automatically every 10 seconds on page load, and I have also provided next and previous buttons, which allow the user to change the images manually.
_elementSlideChange: function () {
var myString;
var myText;
for (var i = 0; i < this._imgArray.length; i++) {
var imageArr = "url(" + this._imgArray[i].src + ")";
var imageBg = this._imageHolder.style.background + "";
if (imageArr == imageBg) {
if (i == (this._imgArray.length - 1)) {
myString = "url(" + this._imgArray[0].src + ")";
myText = this._infoArray[0];
} else {
myString = "url(" + this._imgArray[(i + 1)].src + ")";
myText = this._infoArray[i + 1];
}
}
}
this._imageNextSlide.style.background = myString;
this._imageNextSlide.style.background);
this._infoElement.innerHTML = myText;
this._myTimer = setInterval(MyProject.Utils.createDelegate(this._slideImage, this), 7);
},
_slideImage: function () {
if (parseInt(this._imageHolder.style.width) >= 0 && parseInt(this._imageNextSlide.style.width) <= 450) {
this._imageHolder.style.backgroundPosition = "right";
this._imageHolder.style.width = (parseInt(this._imageHolder.style.width) - 1) + 'px';
console.log(this._imageNextSlide.style.background);
this._imageNextSlide.style.width = (parseInt(this._imageNextSlide.style.width) + 1) + 'px';
} else {
console.log("reached 0px");
if (parseInt(this._imageHolder.style.width) == 0) {
this._imageHolder.style.background = this._imageNextSlide.style.background;
this._imageHolder.style.width = 450 + 'px';
this._imageHolder === this._imageNextSlide;
this._imageHolder.className = "orginalImage";
this._imageNextSlide.style.width = 0 + "px";
this._imageNextSlide = this._dummyImageNextSlide;
this._imagesElement.appendChild(this._imageHolder);
this._imagesElement.appendChild(this._imageNextSlide);
clearInterval(this._myTimer);
}
clearInterval(this._myTimer);
clearInterval(this._elementSlideChange);
}
}
So when the user clicks on the Next arrow button, the event listener for "click" is triggered. This creates a div for the current image on display, and creates a new div, which will contain the next image. The image slide and rotation works correctly (whether it's onLoad or onClick). The issue I have is if I click the Next button, while the new div image is sliding into position, it causes it to run into an infinite loop, so the same div with the image to be displayed keeps sliding in, and the more you click the Next button, the faster the image starts to rotate.
I have tried putting a clear interval for the image rotation and slider, but I do understand my code is wrong, which causes the infinite loop of the sliding image. And I know I am close to finishing the functionality.
Can anyone please advise where I could be going wrong? Or should I try to implement the sliding DIV in another way?
Once again please don't recommend jQuery.
And thank you for your help in advance.
Kush
To solve the issue, I did re-write the entire code, where I had a next and previous button event listener.
myProject.Utils.addHandler(this._nextImageElement, "click", myProject.Utils.createDelegate(this._changeImage, this));
Both the buttons will call the same function :
_changeImage: function (e)
In this function I check to see if the function is Transition (changing images),
I declare a boolean var forward = e.target == this._nextImageElement;
Then check to see the current index if forward ? Add 1 else minus 1
this._currentImageIndex += forward ? 1 : -1;
If its at the end of the Array and forward is true, assign the this._currentImageIndex to reset to 0 or Array.length – 1 if it’s in reverse
Then call another function which gives the ‘div’ a sliding effect. In this case call it this._transitionImage(forward);
In this function, set the this._inTranstion to true. (Because the div’s are sliding in this case).
The following code solved the issue i was having.
this._slideImageElement.style.backgroundImage = "url(\"" + this._imgArray[this._currentImageIndex].src + "\")";
this._slideImageElement.style.backgroundPosition = forward ? "left" : "right";
this._slideImageElement.style.left = forward ? "auto" : "0px";
this._slideImageElement.style.right = forward ? "0px" : "auto";
The above code is very important as the object is to place the “sliding in div” Left or Right of the current Visible “div” to the user, and this is mainly dependent on if the forward variable is true or false.
var i = 0;
Then start the transition by
setInterval( function() {
this._currentImageElement.style.backgroundPosition = (forward ? -1 : 1) * (i + 1) + "px";
this._slideImageElement.style.width = (i + 1) + "px";
Notice the forward will determine if the bgPosition will go to the left if its forward as we multiple by -1 or +1,
So for example
If the user clicks NEXT BUTTON,
Forward = true
So the first thing we do is set the
this._slideImageElement.style.backgroundPosition = "left"
Then
this._slideImageElement.style.left = "auto"
this._slideImageElement.style.right = "0px"
This means when the sliding image moves in its background position is LEFT but the div is placed on the RIGHT to 0px;
then this._currentImageElement.style.backgroundPosition = -1 * (i + 1)
Which moves the position of the currentImageElement to the left by 1px,
Increase the width of the slideImage which in this case is right of the current div,
and as the current div moves to the left the sliding image starts to appear from the right. (By default set the width of slideImageElement to 0px so the div exists but isn’t visible to the user). This gives it the slide effect of moving forward new image coming from the right.
this._slideImageElement.style.width = (i + 1) + "px";
then declare it to stop when it it’s the image width. In this case it will be 500px.
if ((i = i + 2) == 500) {
In this if statement reset the currentImageElement background and the background position “right” or “left” don’t really matter as long it has been reset.
Clear the interval
Set the transition to false again
Then call a setTimeout for the function changeImage, which will continue until the slide is completed.
The following shows the reset code as this is very important to prevent repeating the same image (This solved my entire issue)
// set the current image to the "new" current image and reset it's background position
this._currentImageElement.style.backgroundImage = "url(\"" + this._imgArray[this._currentImageIndex].src + "\")";
this._currentImageElement.style.backgroundPosition = "right";
// reset the slide image width
this._slideImageElement.style.width = "0px";
// clear the transition interval and mark as not in transition
clearInterval(this._transitionInterval);
this._inTransition = false;
// setup the next image timer
this._nextImageTimeout = setTimeout(myProject.Utils.createDelegate(this._changeImage, this), 2500);
}
I have provided a thorough detail because then it easier to understand the logic of the problem, and even if your not having the same issue, this may help you fingure out any problem.
I couldn't provide a JSfiddle, as i have created my CSS using Javascript, there are different ways of doing this, but i wanted to understand the logic behind the forward and reverse, and having a timer which continuously goes forward.
It seems like you want to cancel the animation on the slide (perhaps have it fade out while the next slide animates in, cancel its animation abruptly or let it finish and ignore the button click)
What I usually do, personally, is check for the animated state (yes, I use jquery, but you should be able to test the CSS or positioning values you are using to animate in the same way) you could even add an "active" class or data type during animation to make testing easier. Global flags work, too. If there is animation, ignore the button. (For my work... Depends on your intention)
Like I said, the problem may be with button behaviour not with the animation routine. It would be useful to see how you are calling this from the button click, and what your intended results are going to be.
How about CSS3 transitions?
transition: all 1s ease 0.5s;
Simple example on JS Fiddle.
This takes care of the animation, so you just need to set the intended destination using JavaScript, i.e.
this.style.left = '100px';
Or
this.style.top = '30px';
And CSS3 transitions will smoothly slide the element.
Cross Browser Note!
The transition property may need a vendor prefix for some browsers, I am using the latest production Firefox and you don't need -moz for that. Same goes for Opera, no '-o' required. Internet Exporer 10 needs no prefix. You may need to use -webkit for Safari / Chrome, but test without first.

smooth auto scroll by using javascript

I am trying to implement some code on my web page to auto-scroll after loading the page. I used a Javascript function to perform auto-scrolling, and I called my function when the page loads, but the page is still not scrolling smoothly! Is there any way to auto scroll my page smoothly?
Here is my Javascript function:
function pageScroll() {
window.scrollBy(0,50); // horizontal and vertical scroll increments
scrolldelay = setTimeout('pageScroll()',100); // scrolls every 100 milliseconds
}
It's not smooth because you've got the scroll incrementing by 50 every 100 milliseconds.
change this and the amount you are scrolling by to a smaller number to have the function run with the illusion of being much more 'smooth'.
turn down the speed amount to make this faster or slower.
function pageScroll() {
window.scrollBy(0,1);
scrolldelay = setTimeout(pageScroll,10);
}
will appear to be much smoother, try it ;)
Try to use jQuery, and this code:
$(document).ready(function(){
$('body,html').animate({scrollTop: 156}, 800);
});
156 - position scroll to (px), from top of page.
800 - scroll duration (ms)
You might want to look at the source code for the jQuery ScrollTo plug-in, which scrolls smoothly. Or maybe even just use the plug-in instead of rolling you own function.
Smoothly running animations depends on the clients machine. No matter how fairly you code, you will never be satisfied the way your animation runs on a 128 MB Ram system.
Here is how you can scroll using jQuery:
$(document).scrollTop("50");
You might also want to try out AutoScroll Plugin.
you can use jfunc function to do this.
use jFunc_ScrollPageDown and jFunc_ScrollPageUp function.
http://jfunc.com/jFunc-Functions.aspx.
Since you've tagged the question as 'jquery', why don't you try something like .animate()? This particular jquery function is designed to smoothly animate all sorts of properties, including numeric CSS properties as well as scroll position.
the numbers are hardcoded, but the idea is to move item by item (and header is 52px) and when is down, go back
let elem = document.querySelector(".spfxBirthdaysSpSearch_c7d8290b ");
let lastScrollValue = 0
let double_lastScrollValue = 0
let scrollOptions = { top: 79, left: 0, behavior: 'smooth' }
let l = console.log.bind(console)
let intScroll = window.setInterval(function() {
double_lastScrollValue = lastScrollValue //last
lastScrollValue = elem.scrollTop // after a scroll, this is current
if (double_lastScrollValue > 0 && double_lastScrollValue == lastScrollValue){
elem.scrollBy({ top: elem.scrollHeight * -1, left: 0, behavior: 'smooth' });
} else {
if (elem.scrollTop == 0){
elem.scrollBy({ top: 52, left: 0, behavior: 'smooth' });
} else {
elem.scrollBy(scrollOptions);
}
}
}, 1000);
Here's another take on this, using requestAnimationFrame. It gives you control of the scroll time, and supports easing functions. It's pretty robust, but fair warning: there's no way for the user to interrupt the scroll.
// Easing function takes an number in range [0...1]
// and returns an eased number in that same range.
// See https://easings.net/ for more.
function easeInOutSine(x) { return -(Math.cos(Math.PI * x) - 1) / 2; }
// Simply scrolls the element from the top to the bottom.
// `elem` is the element to scroll
// `time` is the time in milliseconds to take.
// `easing` is an optional easing function.
function scrollToBottom(elem, time, easing)
{
var startTime = null;
var startScroll = elem.scrollTop;
// You can change the following to scroll to a different position.
var targetScroll = elem.scrollHeight - elem.clientHeight;
var scrollDist = targetScroll - startScroll;
easing = easing || (x => x);
function scrollFunc(t)
{
if (startTime === null) startTime = t;
var frac = (t - startTime) / time;
if (frac > 1) frac = 1;
elem.scrollTop = startScroll + Math.ceil(scrollDist * easing(frac));
if (frac < 0.99999)
requestAnimationFrame(scrollFunc);
}
requestAnimationFrame(scrollFunc);
}
// Do the scroll
scrollToBottom(document.getElementById("data"), 10000, easeInOutSine);

Categories

Resources