Why do my elements flicker before an animation using css - javascript

I was creating a 2048 clone from scratch as a project. I have got the game pretty much working only problem is that my animations look janky. I have used css grid to construct my game board and after every move (user input) all the tiles are meant to slide across the board in a direction. That part works fine, it's when they start the slide animation that for whatever reason some of the elements flicker.
I'm not the best with css animations but I have tried to look at every resource I could and I couldn't find any solutions suited to my code. I tried switching the animation timing, delaying the animation etc to no avail. I did use a package animate-css-grid (because animating css grid is hard) which only handles the tiles sliding across the grid and I do not suspect that it is causing the issue.
I have put the code on js fiddle if anyone is interested to try and see the problem https://jsfiddle.net/codedjourney/uv1o48L6/3/ hello
Also if anyone has a better way of animating css grid let me know the package while helpful is a bit odd to work with. Thanks for the help

I managed to get rid of the flickering by commenting out the hidden class in the addTile method
addTile(tile) {
// create the tile
const tileElm = document.createElement("div")
tileElm.classList.add(
"cell",
"tile",
// "hidden",
`cell-${tile.x}-${tile.y}`
)
const valueElm = document.createElement("div")
valueElm.classList.add("tile-container", `value-${tile.value}`)
valueElm.textContent = tile.value
tileElm.appendChild(valueElm)
this.display.appendChild(tileElm)
this.cells[tile.x][tile.y] = new Tile(
tileElm,
tile.x,
tile.y,
tile.value
)
// request frame to allow transition to play
window.requestAnimationFrame(() => {
tileElm.classList.remove("hidden")
})
}

As I saw your code All I see is that it's getting larger while colliding and it's happening because you have added css the one which scales your box while colliding.
Transform: Scale
Try using this css style and you might get your problem solved.

Related

How to increase speed of mousemove/clientX/Y and applying a transform?

I have built a WordPress theme. I came across a website that created a div to follow the user's cursor. The div was enlarged smoothly when the user hovers over a button or a link.
I want to add this nice functionality as an optional feature.
I added a div to the web page, #ambition_cursor and added some basic styling. The div now shows like a blue circle. The circle has position fixed to the top left corner of the site. The position can be changed by adding a CSS translate property.
I managed to make it work with the following code:
var ambition_cursor = document.getElementById("ambition_cursor");
function ambition_mouse(e) {
var ambition_cursor_x = e.clientX; // Get the horizontal coordinate
var ambition_cursor_y = e.clientY; // Get the vertical coordinate
var ambition_cursor_pos = `translate(${ambition_cursor_x}px, ${ambition_cursor_y}px)`;
ambition_cursor.style.transform = ambition_cursor_pos;
}
window.addEventListener('mousemove', ambition_mouse);
The big downside here is the lag (?). There's quite a big delay, especially when moving the mouse around very fast. You can try it out on this site. I also put the situation in a JSFiddle; although the delay doesn't really happen there.
I didn't apply yet much styling (the default cursor is visible, so you can get a better idea of the real position). I first want this to work better, before I spent much time on that.
How can I increase the speed of this, so that the div position follows the mouse more accurately? I'm a beginner, so I don't really know which JavaScript optimisations I should make.
Current code is JavaScript, but jQuery is also an option.
Many thanks in advance!
Update: example how it looks on my computer.
All elements on the page have a transition applied. Remove/override this style and the delay goes away (tested).
As an alternative to the great answer of Joseph Atkinson:
var ambition_cursor = document.getElementById("ambition_cursor");
function ambition_mouse(e) {
ambition_cursor.style.left = e.clientX + 'px'; // Get the horizontal coordinate
ambition_cursor.style.top = e.clientY + 'px' ; // Get the vertical coordinate
}
window.addEventListener('mousemove', ambition_mouse);
See: https://levelup.gitconnected.com/use-javascript-to-make-an-element-follow-the-cursor-3872307778b4
I visited the site example, cracked open the dev console, and found throttled(20, ambition_mouse) It is not a performance issue, and the solution is to not throttle the events. It was too smooth to be a performance issue, which gave me the first clue it had to be an accidental/deliberate effect.

Flexslider breaks jQuery accordion [duplicate]

I have a test page to better explain my problem. I have several items on a list (they're images on the test page); when I click on one of them, a corresponding slideshow, using flexslider, sldes down.
The problem is that, on page load, the slideshow shows all slides at once, at a much smaller size than intended. But then, if I switch the focus from the window (i.e. switch between browser tabs or move to another program and come back), the slideshow is now working and the slides are the proper size. This happens in mobile devices too.
When I check with firebug, there's an element.style rule applying to ul.slides:
transform: translate3d(-89px, 0px, 0px);
Which hides one of the slides. Additionally, there's another rule for the list items inside ul.slides that gives them their initial width, which is not even the same for all sliders so I don't understand where it is coming from.
Can someone take a look and suggest a fix? I've tried overriding the element.style rule but so far unsuccessfully.
I think I've figured it out, in principal at least...
.flexslider{display:none;} seems throw off the re-size function of Flexslider.
You could just remove it, but that makes for some ugly loading.
To avoid said ugly loading I put together a quick, work-around- jsFiddle
$(document).ready(function(){
$(".flexslider").css('display','block').slideUp();
});
There's a still a quick glitch while loading, but hopefully it will at least steer you in the right direction.
Another method I played with a bit was to try and force the re-size function like so-
$(".client").click(function () {
$('.flexslider').resize(); // Problematic but promising
var project = this.id;
var project_id = '#' + project + '-project';
var elem = $(".flexslider:visible").length ? $(".flexslider:visible"): $(".flexslider:first");
elem.slideUp('slow', function () {
$(project_id).slideDown('slow');
});
});
This sort of solved the mini-picture issue, but was spotty at best.

Animating SVG elements with GSAP

I am tasked with creating an interactive SVG infographic with few slides for a browser game, it has 5 steps total. When you click prev / next buttons or a specific step, the whole svg should animate itself to the correct step.
In terms of code, this is what I have:
function Slide() {
// Cache all top-level svg elements for later use
this.el = $('svg#betfair-slider');
this.hands = this.el.find('#hands_8_');
this.cardsDesk = this.el.find('g#center-cards');
this.textContainer = $('.step-text');
// Use a shared timeline across all slides, so there are no overlapping tweens
this.tween = new TimelineLite();
}
function Slide2 () {
// Inherit from the main slide
Slide.call(this);
// each slide has its own supporting explanatory text
this.html = [
'<h3>Preflop</h3>',
'<p>Amet sit lorem ipsum dolar</p>'
].join('');
// the main openslide method
this.openSlide = function() {
// find the cards that need to be animated for this specific slide
var cards = this.hands.find('.card');
// fade out each card
this.tween.staggerTo(cards, 0.2, { opacity: 0 }, 0.2);
// Render supporting text
this.textContainer.html(this.html);
};
}
Here are the cards I am trying to get:
I am able to fetch them using the this.hands.find('.card'); jquery method (I can see them in the console), but I just can't animate them. I have tried animating different attributes (opacity, x, y, left, etc), but nothing happens - nothing moves on the screen.
I am able to do this.hands.find('.card').hide() and change the css using jQuery, but why TimelineLite doesn't work here? I also tried this approach:
var cards = this.hands.find('.card');
for (var i = cards.length - 1; i >= 0; i -= 1) {
var card = cards[i];
this.tween.to(card, 0.2, { opacity: 0 });
}
But still no success... The interesting thing is that when I attach an onComplete callback on the tweens, THEY ARE fired, but absolutely nothing moves on the screen. You can check out everything here.
Thanks for the help in advance, any suggestions are more then welcome.
I think you might be misunderstanding how timelines work (or perhaps I'm misunderstanding your intent). Like all tweens, timelines start playing immediately by default. So if you're using one timeline and shoving all your tweens in there based on user interaction (meaning time elapses between when you create it and when you populate it...and populate it more...), its playhead will already have advanced. I bet that's causing your tweens to jump to their end state almost immediately. That's not a bug - it's how things are supposed to work, although there's some logic in GSAP to adjust behavior in certain circumstances to make it more intuitive.
I see several options:
Just use TweenMax instead of a TimelineLite. Like TweenMax.staggerTo(...) and TweenMax.to(...).
Or just create a TimelineLite for each user interaction (instead of one for ALL of your tweens globally). That way you'll populate it right away and it'll play as you expected.
You could use one global timeline if you really want to, but you might just need to manage its playhead if you're going to be inserting tweens on each user interaction rather than all at once.
If you're still having trouble, don't hesitate to post in the GSAP-dedicated forums at http://greensock.com/forums/ and it's be super helpful if you included a codepen or jsfiddle reduced test case so that we can tinker and very quickly see what's going on and how the changes affect the result.
Happy tweening!

jQuery hover scale from bottom

This is certainly going to be an easy one but I can't get my head around what I am doing wrong...
I am trying to do a hover effect on a UL that affects a link within one of the UL LI's.
My current code looks like this:
$("ul.punchlines").hover(function () {
$(this).find("li a.light-grey-gradient").animate({'width' : '60%','top':'-65px'});
});
$("ul.punchlines").mouseleave(function () {
$(this).find("li a.light-grey-gradient").animate({'width' : '30%','top':'0px'});
});
This technically works as it gives the effect that the base of the element to be scaled remains in place and scales up from the bottom however it does it in two stages, I am trying to get this effect to happen all in one motion so it is a seamless scale and move.
I can do this easily with basic CSS3 transitions but as it is not supported in IE9 I am trying to use jQuery to allow for maximum browser support.
Can anyone offer a little support firstly about how I get the animation to happen in one motion (not staggered) and secondly if this is the right approach? I am new to jquery and only just getting my hands dirty with it :-)
Please see JQuery hover api:
http://api.jquery.com/hover/
also make sure that your "li" have absolute position.
$("ul.punchlines").hover(function () {
$(this).find("li a.light-grey-gradient").animate({'width' : '60%','top':'-65px'});
}, function () {
$(this).find("li a.light-grey-gradient").animate({'width' : '30%','top':'0px'});
});

jQueryui animation with inital undefined height

See the following fiddle:
[edit: updated fiddle => http://jsfiddle.net/NYZf8/5/ ]
http://jsfiddle.net/NYZf8/1/ (view in different screen sizes, so that ideally the image fits inside the %-width layouted div)
The image should start the animation from the position where it correctly appears after the animation is done.
I don't understand why the first call to setMargin() sets a negative margin even though the logged height for container div and img are the very same ones, that after the jqueryui show() call set the image where I would want it (from the start on). My guess is that somehow the image height is 0/undefined after all, even though it logs fine :?
js:
console.log('img: ' + $('img').height());
console.log('div: ' + $('div').height());
$('img').show('blind', 1500, setMargin);
function setMargin() {
var marginTop =
( $('img').closest('div').height() - $('img').height() ) / 2;
console.log('marginTop: ' + marginTop);
$('img').css('marginTop', marginTop + 'px');
}
setMargin();
Interesting problem...after playing around with your code for a while (latest update), I saw that the blind animation was not actually firing in my browser (I'm testing on Chrome, and maybe it was firing but I wasn't seeing it as the image was never hidden in the first place), so I tried moving it inside the binded load function:
$('img').bind('load', function() {
...
$(this).show('blind', 500);
});
Now that it was animating, it seemed to 'snap' or 'jump' after the animation was complete, and also seemed to appear with an incorrect margin. This smacks of jQuery not being able to correctly calculate the dimensions of something that hadn't been displayed on the screen yet. On top of that, blind seems to need more explicit dimensions to operate correctly. So therein lies the problem: how to calculate elements' rendered dimensions before they've actually appeared on the screen?
One way to do this is to fade in the element whose dimensions you're trying to calculate very slightly - not enough to see yet - do some calculations, then hide it again and prep it for the appearance animation. You can achieve this with jQuery using the fadeTo function:
$('img').bind('load', function() {
$(this).fadeTo(0, 0.01, function() {
// do calculations...
}
}
You would need to work out dimensions, apply them with the css() function, blind the image in and then reset the image styles back to their original states, all thanks to a blind animation that needs these dimensions explicitly. I would also recommend using classes in the css to help you manage things a little better. Here's a detailed working example: jsfiddle working example
Not the most elegant way of doing things, but it's a start. There are a lot more easier ways to achieve seemingly better results, and I guess I just want to know why you're looking to do image blinds and explicit alignment this way? It's just a lot more challenging achieving it with the code you used...anyways, hope this helps! :)

Categories