Learn JS animation from emoticons
preface
The first two periods introduced how to learn Canvas from emoticons, pixi.js from League of Legends, and how to use Canvas drawing library from canvas introduction. Today, I will supplement the animation part that was not mentioned before. This time, I will use a hand-painted emoticons to explain the animation implementation of JS. If your opponent is interested in writing canvas emoticons, you can learn canvas from emoticons. The following is the animation of this issue’s hand-painted wind emoji pack. By the end of this reading, you will have learned the common methods of JS animation and how to implement SVG stroke. Learn expression pack, small test ox knife, learn expression pack again, open ren Du 2 pulse.
When I finished writing, I looked back, it was a bit abstract, not to brag, maybe half as good as Van Gogh and Teacher ONE.
Step into the animation world
In Web development, common animation means are divided into two forms, one is tween animation controlled by CSS, the other is frame by frame animation controlled by JS. Tween animation: Given the animation positions for the first and last frames, the browser takes care of the rest.
// eg: @keyframes mymove { 0% {top:0px; } 100% {top:200px; }}Copy the code
Frame by frame animation: we need to manually give the position of each frame animation
// eg:
let timer = setInterval(() => {
if (top >= 200) {
clearInterval(timer)
} else {
top += 1
}
} 60)
Copy the code
JS and CSS animation have their own strengths, mainly depending on the use scene. CSS uses GPU computing, and CSS animation can still run smoothly when JS is blocked due to complex operations. JS animation control is flexible, easy to write complex code logic, can control non-DOM elements, such as balls in the canvas, which CSS can not do. Next explain JS animation commonly used means.
requestAnimationFrame
RequestAnimationFrame, which is made up of three words request (request), Animation (Animation), Frame (Frame), plus the window, the window. The requestAnimationFrame, Isn’t that what you mean by asking your browser for an animated refresh? RequestAnimationFrame = requestAnimationFrame = requestAnimationFrame = requestAnimationFrame = requestAnimationFrame = requestAnimationFrame SetTimeout (() => {}, 60) after a complex operation js executes for 1s, because js is executed in a single thread. SetTimeout will not fire after 60 milliseconds. SetTimeout will not fire after at least 1 +0.06 seconds, so the actual execution time is always later than the set time, while the requestAnimationFrame callback is browser-determined and is the same as the screen refresh time.
let x = 0; Function animation() {x += 1; / images/modify the location of the if (x < 100) {/ /, before the end of the animation without recursive rendering window. RequestAnimationFrame (animation); }} // Render animation()Copy the code
tween
Tween is a JS tween animation, similar to CSS animation. You only need to specify the start and end positions. Each frame in the middle is calculated by the Tween animation engine.
// const box = document.createElement('div') box-style.setProperty ('background-color', '#008800') box.style.setProperty('width', '100px') box.style.setProperty('height', '100px') document.body.appendChild(box) // Setup the animation loop. function animate(time) { requestAnimationFrame(animate) TWEEN.update(time) } requestAnimationFrame(animate) const coords = {x: 0, y: 0} // Start at (0, 0) const tween = new TWEEN.Tween(coords) // Create a new tween that modifies 'coords'. .to({x: 300, y: 200}, 1000) // Move to (300, 200) in 1 second. .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. .onUpdate(() => { // Called after tween.js updates 'coords'. // Move 'box' to the position described by 'coords' with a CSS translation. box.style.setProperty('transform', `translate(${coords.x}px, ${coords.y}px)`) }) .start() // Start the tween immediately.Copy the code
The emoji Case
Two days ago, I saw an introduction of rough. Js library written by digger on the nuggets. It was quite interesting to contact with it for the first time, so I tried to use it in this case.
Basic use of rough.js
import rough from 'roughjs'; const rc = rough.svg(svg); let node = rc.rectangle(10, 10, 200, 200); // x, y, width, height svg.appendChild(node); rc.circle(50, 50, 80, { fill: 'red' }); // fill with red hachure rc.rectangle(120, 15, 80, 80, { fill: 'red' }); Rc. circle(50, 150, 80, {fill: "RGB (10,150,10)", fillWeight: 3 // thicker lines for hachure}); rc.rectangle(220, 15, 80, 80, { fill: 'red', hachureAngle: 60, // angle of hachure, hachureGap: 8 }); Rectangle (120, 105, 80, 80, {fill: 'rgba(255,0,200,0.2)', fillStyle: 'solid' // solid fill});Copy the code
Getting started is pretty easy. If you want to know more, you can read this articleHand to hand teach you to achieve hand-painted style graphics, we will not introduce rough. Js extension here. Next, follow the routine of the first episode to draw an emoji package.
Painting expression package
import rough from 'roughjs' const svg = document.getElementById('svg') const rc = rough.svg(svg); let mouth, timer let tear = {height :60} let dash = {offset: 0} function getTear(x, y, width = 20, height = 60, radian = 15) { return `M${x} ${y} L${x + width} ${y} L${x + width} ${y + height} Q${x + width / 2} ${y + height + radian} ${x} ${y+height} L${x} ${y}` } function getMouth() { let m = rc.curve([[200, 360], [280, 380], [340, 360]]) m.styles ['strokeDasharray'] = 200 m.styles ['strokeDashoffset'] = offset function render() {// render() {// render() svg.appendChild(rc.circle(300, 300, 300, { fill: AppendChild (rc. Rectangle (50, 50, 50, 50) {fill: rectangle(50, 50, 50, 50); AppendChild (rc. Rectangle (300, 220, 50, 50, 50) {fill: AppendChild (rc.circle(180, 240, 15, {fill: AppendChild (rc.circle(326, 240, 15, {fill: Path (getTear(176, 255, 20, tear. Height), {stroke: 'blue', strokeWidth: '1', fill: Path (getTear(316, 255, 20, tear. Height), {stroke: 'blue', strokeWidth: '1', fill: AppendChild (tear2) SVG. AppendChild (tear2) SVG.Copy the code
Emoji pack animation implementation
- Hand-drawn wind animation
Rough. Js will randomly generate the offset trajectory graph, and constantly regenerate it.
// Clear SVG every time, then return setInterval(() => {svg.innerhtml = 'render()}, 400)Copy the code
- Tears animation
Using tween.js’s tween effect, draw tear’s height from 0 to 60
const tearTween = new Tween(tear).to({height: 60}, 2000).easing(Easing.Quadratic.In).onComplete(() => {
remove(tearTween)
}).start()
function animate() {
timer = requestAnimationFrame(animate)
getAll().forEach((t) => {
t.update()
})
}
Copy the code
- Animation depicting the mouth
The dotted line feature of SVG is used here. First, let’s take a look at the strokeDasharray of SVG. When strokeDasharray = 10, each 10 pixels draws a section of realization, and each 10 pixels draws a blank section, forming a dotted line effect for each 10 pixels.
If the path of the entire mouth is 200, the effect should be 200 solid lines followed by 200 dotted lines. Since it is only 200 long, the effect should be a complete mouth without dotted lines. In fact, SVG provides a method to get the length of a path. PathLength () returns the total length of a path.So strokeDashoffset, as the name suggests, is the offset of the dotted line. Look at the strokeDashoffset effect
As can be seen from the debugging tool of Google Browser, when the SVG path of strokeDashoffset changes from 0 to 200 mouths gradually disappears, we reverse the effect, and the drawing of offset changes from the maximum value to 0, thus realizing the drawing of SVG Path. This is how common SVG stroke animations work. Tween is used to change the strokeDashoffset from 200 to 0 frame by frame to achieve the effect of drawing mouth lines.
const mouthTween = new Tween(dash).to({offset: 0}, 2000).easing(Easing.Quadratic.In).onUpdate(() => {
mouth.style['strokeDashoffset'] = dash.offset
}).onComplete(() => {
remove(mouthTween)
}).start()
Copy the code
The last
This issue combined with tween, SVG, rough. Js to do a hand-drawn wind animation, explained the implementation principle of JS animation (source code address). It is not recommended to render SVG animation in the production environment. In order to increase the introduction of SVG stroke animation, SVG rendering is used for graphics drawing, and the commonly used method of screen cleaning and redrawing of Canvas is used for animation. Every graph of SVG is a DOM element, and dom insertion and deletion are constantly consuming performance. Under normal circumstances, CSS is recommended for SVG stroke effects.