Translate CSS transition-timing-function to swiping - css

I am fading in a div (using CSS transitions) with a custom timing function (http://cubic-bezier.com/#1,0,1,1). The timing function is basically a more extreme version of 'ease-in'.
div {
opacity: 0;
transition: opacity 1s;
.in {
opacity: 1;
transition-timing-function: cubic-bezier(1, 0, 1, 1);
}
In addition to that, I want to be able to fade in the div by swiping across the screen. I am using the following Jquery to set the opacity according to how far the user has swiped:
documentWidth = $(document).width();
$(document).on('touchmove', function(e) {
// How much of the animation is completed (in %)
completion = e.changedTouches[0].pageX / documentWidth;
$('div').css('opacity', completion);
})
Nooooow, this is linear! Is there a clever Math-person out there who can figure out how to re-state that last line to represent my timing function?
So, for example, if completion is at 25%, the opacity should be around 2%. At 50%, it should be around 11% and at 75% it should be around 31%.

Start by finding a curve that approximates your cubic-bezier curve. With the given points and some online tools it's possible to draw a curve with this equation:
y = 464085.7 + (0.0174619 - 464085.7)/(1 + (x/22.88957)^4.174069)
in your case the x represents your completion variable and y the resulting opacity.
Then your code becomes
let completion = e.changedTouches[0].pageX / documentWidth;
let exponential = Math.pow((completion / 22.88957), 4.174069);
let opacity = 464085.7 + (0.0174619 - 464085.7)/(1 + exponential);
$('div').css('opacity', opacity);
(of course you may find a better equation that best fits your needs)

Related

Resetting RotateY degrees without transformation

I use css 3D-transform rotateY to flip a div with css transition. I want the image to flip for a certain number of times : when the transition ends, I trigger it again until a certain counter value is reached.
What I would like to do : when the rotateY reaches 360 deg, I want reset it to 0 to restart the same rotation.
What happens: if I reset to 0, the div rotates backward first. I tried to disable the transform property before "rewinding', without any luck.
Is there an easy way to restore the 0 deg value without any transformation / rotation?
I did a codepen to illustrate: http://codepen.io/3MO/pen/QKogxE
It is not very graphical, but if you click on start, then reset, it will be obvious.
Here is my reset function:
$('#reset').click(function () {
deg = 0;
countRotations = 0;
$('#card').attr('transition', 'transform 0');
flipStarted = false;
flip($('#card'), 0);
});
You need to set the transition property to 0s, then change the rotation to 0 (this way it'll rotate instantly), then change the transition back to the "default" value.
Thanks to #Harry here's a working demo:
http://codepen.io/hari_shanx/pen/PGLKzN

CSS animation performance

I have a small hobby project in which I try to build a matrix rain: .
See demo here. Or this JSFiddle
My question is: how can I make this more efficient, as I can see it gets slow when I add a lot of columns.
I have implemented it as rendering a lot of absolute positioned divs that are animated.
Here is my CSS:
div
{
position:absolute;
width:1em;
display:inline-block;
color: black;
animation-name: example;
animation-duration: 2s;
text-shadow: none;
}
#keyframes example
{
0% {color: white; text-shadow: -1px 1px 8px white;}
15% {color: #5f5 ; text-shadow: -1px 1px 8px #5f5 ;}
100% {color: black; text-shadow: none;}
}
In javascript I set some custom styling for each div, where I vary some settings, like font-size, animation speed etc.
Main part of the JS:
var textStrip = ['诶', '比', '西', '迪', '伊', '吉', '艾', '杰', '开', '哦', '屁', '提', '维'];
var matrixcol = function()
{
var top = Math.floor(Math.random() * $(window).height() * 0.5);
var size = 10 + Math.floor(Math.random()*10);
var col = Math.floor(Math.random() * $(window).width() - size);
var ms = 500 + Math.floor(Math.random()*1500);
var timer;
var aap = function()
{
var randomNumber = Math.floor(Math.random()*textStrip.length);
var newelem = $("<div style='font-size:"+ size+ "px;top:"+top+"px; left:"+col+"px;animation-duration:"+ 2*ms + "ms'>" + textStrip[randomNumber] + "</div>" );
$('body').append(newelem);
top+=size;
setTimeout( function() {newelem.remove();}, (1.6*ms)-(ms/40));
if (top>$(window).height()-size)
{
size = 10 + Math.floor(Math.random()*10);
top=0; Math.floor(Math.random() * $(window).height() * 0.5);
col = Math.floor(Math.random() * $(window).width() -size);
ms = 500 + Math.floor(Math.random()*1500);
clearInterval(timer);
timer = setInterval(aap, ms/40);
}
}
timer = setInterval(aap, ms/40);
}
$( document ).ready(function() {
var i;
for (i = 0; i < 25; i++) {
matrixcol();
}
I have tried to use the chrome profiling, that shows my a warning:
Long frame times are an indication of jank and poor rendering
performance.
The link that is provided gives some insight; however, as far a I can see I don't have much layouting going on.
tl;dr
It is slow. What would be a good performance optimizations?
After several try, I think your best solution is looking to canvas, if the exact animation is desired.
The ending result I get is here. Not as exact as yours but get a 50+ fps.
For every modification I have added comment, please check it out.
Cache
The easiest thing you can do is cache $(window).height(). It is usually a stable number, no need to re-query it. And resize handler can be added to adapt viewport change. Cache window size changes my fps from 9~10 to 12~15. Not big, but a low-hanging fruit.
Expensive Style
The next thing you need to do is remove text-shadow, it is a very expensive style, given the node number in your case. (Why? It requires CPU paints shadow and GPU cannot help here. read more here, and html5rocks).
If you are interested in Chromium implementation, text-shadow is done in TextPainter.cpp, painted by GraphicContext, which is done primarily by CPU. And animating text-shadow is a performance nightmare. Change this boost fps to 20+.
DOM Access
The last thing is DOM access, every frame update requires a dom insertion and, correspondingly, a dom removal by yet another timer. This is painful. I try to reduce DOM removal, so I added a container for each column. And adding container does add DOM complexity, I have to wait for the animation end to update the container. After all, it saves many dom manipulations, timers and closures. Furthermore I updated setTimeout to requestAnimationFrame so that browser can orchestra DOM access better.
Combining the above three, I got a 50+ fps, not as smooth as 60fps. Maybe I can further optimize it by reducing DOM insertion, where all characters in a column is inserted once, and for each character the animation-delay is at interval.
Looking on Canvas
Still, your animation is quite harsh job for DOM based implementation. Every column is updated, and text size varies frequently. If you really want the original matrix effect, try canvas out.

Breaking up transformations

I have 48 elements and they all have the same animation which is a transformation in the Y axis but they each have a different rotation
transform:rotate(0deg) translateY(-105px);
...
#keyframes mov {
0%,65%,100% {transform:rotate(0deg) translateY(-105px);}
15%, 50% {transform:rotate(0deg) translateY(105px);}
}
and it would be horribly inefficient if I were to have that for each element - is there a way I can have transform:rotate(0deg) in one place and translateY(?px); in another place?
Current solution: element in an element, first is rotate and the second is translateY

Can I make a transition go through a keyframe?

I have a css 'level up' bar defined like so:
.levelup-bar {
background: //;
color: //;
-webkit-transition:width .6s ease;
transition:width .6s ease;
}
And it works out quite beautifully indeed, my bar automatically animates when I change the width!
What I am doing is calculating the current rate against a max. Of course, once you reach the max, you level up and it goes back to zero. So once it is 100/100, I'm conditionally making it 0/100 to simulate a level up.
And that is the problem, my bar never reaches 100/100 and it is never truly full.
There is a million and one way to solve this in javascript, but I want to solve it using css3. Is there a way to keyframe my width so that it always goes one way, and resets only to zero once its maxed out?
Plunkr: http://plnkr.co/edit/N42aoxfJzpIjhWMofmIP?p=preview
On your onclick event on the button you have the following:
cur += 10;
if(cur>=max)
cur = 0;
If you change the if statement from >= to > the bar will fill up if it reaches 100 exactly:
cur += 10;
if(cur>max)
cur = 0;
I'm not entirely sure if this is the solution you are after.
If it goes over the 100 you could stop it at 100, then set a timer to add the remainder of the score after x ms (but then you are using Javascript again) ?
This seems to work :
// reset cur when you click and you are already at 100%
if(cur >= max)
cur = 0;
cur += 10;
if(cur > max)
cur = 0;

Rotate more than 360 deg using css 3 matrix

I am using CSS transitions like this:
div
{
-webkit-transform: rotate(0deg);
-webkit-transition: -webkit-transform 2s;
}
div:hover
{
-webkit-transform: rotate(720deg);
}
This effectively makes the div rotate 2 times for 2 seconds. Now I want to use the matrix so that I can rotate and scale the image; however the matrix does not use degrees but cos(a) and sin(a) and as we all know cos(0) = cos(360) = cos(720) etc. So using the matrix I am unable to rotate the image more than 359deg.
So I decided to be clever and with JavaScript I took the matrix from a rotated element (720deg) and it looks like this:
-webkit-transform: matrix(1, -0.0000000000000004898587196589413, 0.0000000000000004898587196589413, 1, 0, 0);
However using this matrix I am not able to rotate the element - I will later calculate the size and apply that too.
So the question is - how do I rotate an element more than 359deg using css 3 matrix transform?
Matrices in CSS 3 define
a mathematical mapping from one coordinate system into another
(W3C reference),
which implies that 720deg is exactly equivalent to 360deg as you pointed out. So you will not be able to do this directly with a matrix.
However, this syntax should work for your need :
div:hover {
transform: scale(1.5,1.5) rotate(720deg);
transition: transform 3s;
}

Resources