In the previous two sections, we went together to make an example of creating an increasing numerical effect that often appears on Landing Page pages. The final result is quite complete, we learn a new brand – requestAnimationFrame()
in Javascript, as well as using the method of calculating numerical values based on time, …
Motion function of animation
First of all, I would like to bring back the example CodePen – our final result in the previous section:
If you look closely, the increasing effect of the above figures looks a bit … boring. In the end, what are we missing?
In my opinion, it is because the value of the numbers is currently increasing steadily with the value of time. In other words, our effects are running at a linear speed – not changing over time.
No object in nature moves at the same velocity with the 45-degree angular graph shown above. No wonder something was wrong.
If you have ever used CSS3 animation with transitions, then you will know that there are many different types of motion functions to choose from: linear, ease (slow – fast – slow), ease-in (slow start), ease -out (slow ending), …
At easings.net, there are many motion functions that I can apply to the effects in my example. I will try to get the easeOutExpo function to use. Remember that ease-out functions have a quick start, but at the end the movement slows down.
1 2 3 4 5 6 | <span class="token comment">// Lấy tại https://easings.net/#easeOutExpo</span> <span class="token keyword">function</span> <span class="token function">easeOutExpo</span> <span class="token punctuation">(</span> x <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token operator">-</span> Math <span class="token punctuation">.</span> <span class="token function">pow</span> <span class="token punctuation">(</span> <span class="token number">2</span> <span class="token punctuation">,</span> <span class="token operator">-</span> <span class="token number">10</span> <span class="token operator">*</span> x <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
This function takes an argument that the value of x
is the time scale (in the range of 0 to 1), and will return the ratio of the distance between 0 and 1.
Now I will add the above function to our animation calculation function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <span class="token keyword">function</span> <span class="token function">easeOutExpo</span> <span class="token punctuation">(</span> x <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token operator">-</span> Math <span class="token punctuation">.</span> <span class="token function">pow</span> <span class="token punctuation">(</span> <span class="token number">2</span> <span class="token punctuation">,</span> <span class="token operator">-</span> <span class="token number">10</span> <span class="token operator">*</span> x <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">animateNumber</span> <span class="token punctuation">(</span> finalNumber <span class="token punctuation">,</span> duration <span class="token operator">=</span> <span class="token number">5000</span> <span class="token punctuation">,</span> startNumber <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">,</span> callback <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> startTime <span class="token operator">=</span> performance <span class="token punctuation">.</span> <span class="token function">now</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">updateNumber</span> <span class="token punctuation">(</span> currentTime <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> elapsedTime <span class="token operator">=</span> currentTime <span class="token operator">-</span> startTime <span class="token keyword">if</span> <span class="token punctuation">(</span> elapsedTime <span class="token operator">></span> duration <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">callback</span> <span class="token punctuation">(</span> finalNumber <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> timeRate <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token number">1.0</span> <span class="token operator">*</span> elapsedTime <span class="token punctuation">)</span> <span class="token operator">/</span> duration <span class="token keyword">const</span> numberRate <span class="token operator">=</span> <span class="token function">easeOutExpo</span> <span class="token punctuation">(</span> timeRate <span class="token punctuation">)</span> <span class="token keyword">const</span> currentNumber <span class="token operator">=</span> Math <span class="token punctuation">.</span> <span class="token function">round</span> <span class="token punctuation">(</span> numberRate <span class="token operator">*</span> finalNumber <span class="token punctuation">)</span> <span class="token function">callback</span> <span class="token punctuation">(</span> currentNumber <span class="token punctuation">)</span> <span class="token function">requestAnimationFrame</span> <span class="token punctuation">(</span> updateNumber <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">requestAnimationFrame</span> <span class="token punctuation">(</span> updateNumber <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
The change from my previous post is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token coord">@@ -1,3 +1,7 @@</span> <span class="token inserted">+function easeOutExpo(x) {</span> <span class="token inserted">+ return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);</span> <span class="token inserted">+}</span> <span class="token inserted">+</span> function animateNumber(finalNumber, duration = 5000, startNumber = 0, callback) { const startTime = performance.now() function updateNumber(currentTime) { <span class="token coord">@@ -5,8 +9,9 @@</span> function animateNumber(finalNumber, duration = 5000, startNumber = 0, callback) if (elapsedTime > duration) { callback(finalNumber) } else { <span class="token deleted">- const rate = elapsedTime / duration</span> <span class="token deleted">- const currentNumber = Math.round(rate * finalNumber)</span> <span class="token inserted">+ const timeRate = (1.0 * elapsedTime) / duration</span> <span class="token inserted">+ const numberRate = easeOutExpo(timeRate)</span> <span class="token inserted">+ const currentNumber = Math.round(numberRate * finalNumber)</span> callback(currentNumber) requestAnimationFrame(updateNumber) } |
The result is here (press the 0.5x button for a more panoramic view). Now you can see that the slower the numbers move towards the end, the more natural it looks.
More advanced, you can learn and apply bezier curve functions to effects, used by most of the motion functions in CSS3. There is a great article (in Vietnamese) about the bezier curve in CSS3 animation here that you should read.