cordova css transition become slower after few clicks - javascript

I have a list in my html page. There is a button that allow user to add item into the list. Everytime user adds a new item, it will have animation effect let new item move from left to center
$("#addNewItem").on("click",function(){
$('.List').append('<li class="listLeft listTransition"></li>');
setTimeout(function () {
$('#newLi').removeClass('listLeft');
$('#newLi'.addClass('listCenter');
}, 10);
});
//css class
.listLeft{
-webkit-transform: translate3d(-100%, 0, 1px);
transform: translate3d(-100%, 0, 0);
}
.listCenter{
-webkit-transform: translate3d(0, 0, 1px);
transform: translate3d(0, 0, 0);
}
.listTransition{
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
}
It work well for first few attempts, after I clicked more than 3 times, the transition will become slower. It will take 2 -3 seconds to wait for item animates into center. After I tried more than 7 times, it will become even slower. This is nothing related to list size, because if I restart and reopen the app, by having larger list items, the first few attempts will always have good performance. After 4th clicks, the transition become slower. Previously I was using jquery .animate('left', 1000) to do transition. I thought this is the reason that cause slow transition, so i switch to hardware accelerated by using webkit transition, but eventually the results are same, so I guess there is nothing related to it.
During testing, I put an alert('testing') before the $('.List').append(), I noticed this accidentally solved my problem, maybe the alert() will clear some cache or do something, but I don't know. Unfortunately this is not allowed to prompt alert box, so it cannot be solution for me, I tried to use bootstrap modal dialog to do the same thing, but it did not give me the smooth transition as well after 4th clicks
I wish to know what is the magic inside alert() that can solve my problem, then I can duplicate similar logic of code without calling alert(). If would be nice if I can know root cause as well

Related

I have an issue with swiper and arrow buttons (magic)

Arrows of swiper not showed before swipe or change any property in css(not inline)
link of demo: http://sinneren.ru/side/giftormagic/views/index0.html
How to: To see my bug You must use browser in mobile orientation (Chrome, Safary, may be any else). Scroll to big white block with roses. Do you see arrows? Nope, and if you swipe once on it, or You change any property in css, or You change focus on block - they will be shown. It's magic. And it's shown before, but placed under white block. I change any styles, positions, used hacks with init-callback and timers to change inline styles - it's not working.
Since this only happens in Chrome (right?) it could be anti aliasing issue. Try this property:
-webkit-backface-visibility: hidden; on button style. If that doesn't help try:
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0)

Angular Ng-Animate - Smoother Transitions

Using ng-animate to provide some transitions when a user clicks into a tab.
Simply using
.ng-enter{
transition:0.50s;
opacity: 0;
}
.ng-enter-active{
opacity: 1;
}
which works a treat. However, the first time you click in it's somewhat sticky.
The view which is being transitioned into displays for a brief second before being transitioned into, so you see it twice almost. This only occurs on the first time round, on subsequent visits the transition works perfectly.
Is there a way then to make the animation smoother the first time round? The tabs are being displayed using a div with ng-include.
You have to target the animation on the tab elements, like this :
.tab.ng-enter {
transition:0.5s linear all;
opacity:1;
}
.tab.ng-enter.ng-enter-active {
opacity:0;
}
ngAnimate (like ngLeave, ngEnter, etc...) classes will be added to each element appearing/disappearing in the view, so in your case, it is needed to restrain your animation to only one element.
You can see the documentation too.

Ionic App jerky while smooth in Mobile Browser

I've written an Ionic app, where nine images are positioned inside a DIV. Here's the relevant snippet from my CSS file:
.mydiv {
position: relative;
overflow: hidden;
}
.mydiv > img {
position: absolute;
box-shadow: 6px 6px 8px #aaaaaa;
}
I'm using $ionicGesture.on('drag', function(e) {}) to move these images around, following the move of my finger. That's the relevant part from my controller.js:
jQuery('.mydiv > img').each(function(i, myImg) {
jQuery(myImg).css('left', initLeft + e.gesture.touches[0].pageX - initX);
jQuery(myImg).css('top', initTop + e.gesture.touches[0].pageY - initY);
}
So, basically, every time the drag event occurs, I move the images by changing their 'left' and 'top' attribute.
The problem is though, that this solutions works wonderfully in a browser, but is horribly lagging as an Ionic app on my iPhone 5. When I put the contents of the Ionic 'www' folder on a web server and access the web app with my iPhone's web browser, the movement is extremely smooth. So, obviously, it's not a performance issue, but Ionic is doing something that makes the app stuttering. Using the Chrome profiler on my Mac, I learned nearly all of the time is used by internal Ionic functions and not by my client code. This seems to be another hint, that this is some kind of Ionic problem.
Why is my app, that runs perfectly smooth in my mobile browser on the same device gets jerky as hell when packed as an Ionic app?
Additional information:
Those images I drag along are scaled with jQuery(myImg).width(). I now replaced them with pre-scaled image files and got rid of the box-shadow style. Now the lagging is reduced but still worse than in the mobile browser. Is it possible, that the mobile Safari on my iPhone uses the GPU for Javascript induced style changes, while for a Cordova app the GPU is not used?
Looks like you have animation issue. Here is an article from Ionic team that explains on how to deal with this.
What’s happening is that as you try to animate the left property of
the items, the web view will have to go back and try to recalculate
that item’s position. This happens for a lot of CSS properties.
Thankfully, we have other ways to animate these items.
Let’s change that left property to transform and set the value to use
translate3d. Translate3d is a special CSS value that will actually
move the animation to the device’s GPU. This is called hardware
accelerated animation.
#-webkit-keyframes slideIn {
0% {
left: -100%;
}
100% {
left: 0;
}
}
#-webkit-keyframes slideInSmooth {
0% {
-webkit-transform: translate3d(-100%,0,0);
}
100% {
-webkit-transform: translate3d(0,0,0);
}
}
.slide-in{
-webkit-animation: slideInSmooth ease-in 1;
animation: slideInSmooth ease-in 1;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
-webkit-animation-duration: 750ms;
animation-duration: 750ms;
}
I haven't seen your animation or your code but my guess is that the device GPU isn't carrying the weight it should.
Obviously without seeing your app, I'm doing some guessing here -- but from what you've described this may be the issue:
There are a couple ways to get the GPU to kick in, but the most basic is not to animate using "top" and "left". Using standard CSS positioning like top/left to animate DOM elements works, but it's the slowest way to go and as you've discovered: performance tends to suck in many environments. (Particularly when you're using complex images or blurs/shadows).
A far better way to go is to use translateX / translateY which engages the GPU. That should give you silky smooth performance. Using translateX and translateY will also allow for subpixel rendering and give a far smoother appearance than using top/left which blips along pixel-by-pixel.
There's an excellent discussion of this by a Chrome team member here:
https://www.youtube.com/watch?v=NZelrwd_iRs
Lastly, if for some reason you must use top/left -- a quick and somewhat hacky method to get the GPU to kick in is to set the parent DIV to translate3d(0, 0, 0);
This forces the parent layer into the hands of the GPU (via 3D transforms) during the browser-paint, and the subsequent standard CSS top/left changes that you're using should now render using the GPU. Needless to say, this second method isn't the best way to go in terms of best-practices, so go with CSS transforms first if that's an option.
Using transform: translate3d() does the trick. Animations are now extremely smooth. Because I had some trouble to convert my code from the CSS left-top-style to using translate3d(), here is what I did as a reference for other users:
jQuery('.mydiv > img').each(function(i, myImg) {
var x = initLeft + e.gesture.touches[0].pageX - initX;
var y = initTop + e.gesture.touches[0].pageY - initY;
jQuery(myImg).css({
'-webkit-transform' : 'translate3d('+x+'px, '+y+'px, 0px)',
'transform' : 'translate3d('+x+'px, '+y+'px, 0px)'
});
}
I even can switch on box-shadow again and the animation stays silky smooth.

How can I trigger ng-move after a splice?

I am using ng-animate and I have a list of entries iterated through using ng-repeat. When you make a selection on a particular entry, it disappears. I have defined .ng-move, .ng-move-active, .ng-leave, .ng-leave-active appropriately so that the .leave animation occurs when I perform a .splice() operation on my data, and the .move operation occurs when I reorder entries.
However, what I want is for when one of the entries is removed, the .ng-leave occurs on that entry while .ng-move slides them all up. I've found that .splice() doesn't trigger an .ng-move though, so I'm curious if there is a way to force that animation to happen after a .splice()?
Here is the html:
<div data-ng-repeat="entry in data" class="container card-drop card-shift">
<card data="entry"></card>
</div>
Here are the css classes:
.card-drop.ng-leave {
transition: 0.5s ease-in-out;
opacity: 1;
}
.card-drop.ng-leave.ng-leave-active {
transform: scale(0.5);
opacity: 0;
}
.card-shift.ng-move {
transition: 0.5s ease-in-out;
}
.card-shift.ng-move.ng-move-active {
transform: translateY(-284px);
}
And in the javascript the event I am concerned about is simply $scope.data.splice(index, 1);
EDIT: http://plnkr.co/edit/nz38XxPbV4Ycqdn3QYVP?p=preview
Above is the plunk for the issue I am referring to. Notice that when you click on an entry and it is spliced, the .ng-leave animation occurs but none of the ng-move animations do.
The solution was that there was no easy way to do this. Ultimately I ended up manipulating DOM elements' CSS from within the directive to provide the sliding animation, then instantaneously shifted them to their original spot at the same time as the splice, resulting in the animation I was after, albeit in a hacky way.

webkit-transform overwrites z-index ordering in Chrome 13

Update
Sorry for failing to add the minor detail that we also layer a lot of div elements on top of each other with z-index.
After working more with this problem, it seems that the webkit-transform actually messes with the z-index ordering, and that the actual problem is not related to the animations themselves.
End update
I am currently in a project where we develop an application which is quite heavy on CSS3 animations. We're animating a lot of div elements around with -webkit-transform and -webkit-transition.
All is well, until today where all of the to-be-animated elements of the page disappeared. It seems that Google Chrome has updated from 12.xx to 13.0.782.107m and now, all of a sudden, CSS3 properties with -webkit prefixes has stopped working, and elements which have this property applied to them just doesn't show anymore. Removing the -webkit-transform property through the Chrome debugger makes the elements visible again.
Has anyone else experienced the same issues, or know how to solve this problem?
I might add that I've tried to remove just the -webkit prefixes (leaving just transform), which then shows the missing elements, but then that won't animate the elements at all, as the CSS3 property transform is not supported.
I have also tried using el.style.webkitTransform and el.style.WebkitTransform, with no success.
Will pass some example code to explain. The desired result of this is to move sq1 away and reveal sq2.
HTML:
<div id="sq1" style="z-index:10;">
<div id="sq2" style="z-index:5;">
JS
/* fetch the element */
var el = document.getElementById("sq1");
/* apply CSS */
el.style["-webkit-transition"] = "-webkit-transform 500ms linear";
el.style["-webkit-transform"] = "translate3d(30px, 30px, 0px)";
Solved it myself through trial and error. Thought I'd report back if someone else stumbles upon this problem. It shall still be noted that this problem did not occur before Chrome updated itself to Chrome 13 (13.0.782.107m).
The trick here seems to be to add a translate3d operation to the underlying <div> (sq2) element upon declaration (or atleast before animating sq1).
Otherwise, the translate3d operation on the overlying <div> (sq1) will cause rendering to ignore the z-index and place sq1 below sq2. I'm guessing that this is because sq1 is defined before sq2 in the DOM, therefore sq2 will be rendered above it.
So, the solution seems to be to put translate3d in the definition of the <div>:s (add it to both just to be clear):
HTML:
<div id="sq1" style="z-index:10; -webkit-transform: translate3d(0px, 0px, 0px);">
<div id="sq2" style="z-index:5; -webkit-transform: translate3d(0px, 0px, 0px);">
This should only affect any elements which are positioned as absolute or relative. In order to remedy the issue, you can apply the following css statement to every element which is positioned this way and is causing issues:
-webkit-transform: translate3d(0,0,0);
This will apply the transform to the element without actually doing a transformation, but affecting it's render order so it is above the element causing the issue.
I think you need to try using -webkit-transform or webkitTransform instead of webkit-transform.
Use el.style.WebkitTransform (uppercase W).
el.style["-webkit-transition"] = "-webkit-transform 500ms linear";
el.style["webkit-transform"] = "translate3d(30px, 30px, 0px)";
Your missing the - on the second line, this could be the problem.

Categories