diff --git a/3-animation/1-bezier-curve/article.md b/3-animation/1-bezier-curve/article.md index 39767305..6166f25c 100644 --- a/3-animation/1-bezier-curve/article.md +++ b/3-animation/1-bezier-curve/article.md @@ -33,7 +33,7 @@ For two points we have a linear curve (that's a straight line), for three points Because of that last property, in computer graphics it's possible to optimize intersection tests. If convex hulls do not intersect, then curves do not either. So checking for the convex hulls intersection first can give a very fast "no intersection" result. Checking the intersection or convex hulls is much easier, because they are rectangles, triangles and so on (see the picture above), much simpler figures than the curve. -The main value of Bezier curves for drawing -- by moving the points the curve is changing *in intuitively obvious way*. +**The main value of Bezier curves for drawing -- by moving the points the curve is changing *in intuitively obvious way*.** Try to move control points using a mouse in the example below: @@ -56,7 +56,7 @@ First let's see the 3-points example. Here's the demo, and the explanation follow. -Points can be moved by the mouse. Press the "play" button to run it. +Control points (1,2 and 3) can be moved by the mouse. Press the "play" button to run it. [iframe src="demo.svg?p=0,0,0.5,1,1,0&animate=1" height=370] @@ -117,12 +117,11 @@ A curve that looks like `y=1/t`: [iframe src="demo.svg?p=0,0,0,0.75,0.25,1,1,1&animate=1" height=370] - -With zig-zag control points: +Zig-zag control points also work fine: [iframe src="demo.svg?p=0,0,1,0.5,0,0.5,1,1&animate=1" height=370] -Loop form: +Making a loop is possible: [iframe src="demo.svg?p=0,0,1,0.5,0,1,0.5,0&animate=1" height=370] @@ -130,16 +129,19 @@ A non-smooth Bezier curve (yeah, that's possible too): [iframe src="demo.svg?p=0,0,1,1,0,1,1,0&animate=1" height=370] -As the algorithm is recursive, we can build Bezier curves of any order: using 5, 6 or more control points. But in practice many points are less useful. Usually we take 2-3 points, and for complex lines glue several curves together. That's simpler to develop and calculate. +```online +If there's anything unclear in the algorithm description, then live examples above show how +the curve is built. +``` + +As the algorithm is recursive, we can build Bezier curves of any order, that is: using 5, 6 or more control points. But in practice many points are less useful. Usually we take 2-3 points, and for complex lines glue several curves together. That's simpler to develop and calculate. ```smart header="How to draw a curve *through* given points?" -We use control points for a Bezier curve. As we can see, they are not on the curve. Or, to be precise, the first and the last ones do belong to curve, but others don't. +We use control points for a Bezier curve. As we can see, they are not on the curve, except the first and the last ones. Sometimes we have another task: to draw a curve *through several points*, so that all of them are on a single smooth curve. That task is called [interpolation](https://en.wikipedia.org/wiki/Interpolation), and here we don't cover it. -There are mathematical formulas for such curves, for instance [Lagrange polynomial](https://en.wikipedia.org/wiki/Lagrange_polynomial). - -In computer graphics [spline interpolation](https://en.wikipedia.org/wiki/Spline_interpolation) is often used to build smooth curves that connect many points. +There are mathematical formulas for such curves, for instance [Lagrange polynomial](https://en.wikipedia.org/wiki/Lagrange_polynomial). In computer graphics [spline interpolation](https://en.wikipedia.org/wiki/Spline_interpolation) is often used to build smooth curves that connect many points. ``` @@ -147,17 +149,17 @@ In computer graphics [spline interpolation](https://en.wikipedia.org/wiki/Spline A Bezier curve can be described using a mathematical formula. -As we saw -- there's actually no need to know it. But for completeness -- here it is. +As we saw -- there's actually no need to know it, most people just draw the curve by moving points with a mouse. But if you're into maths -- here it is. Given the coordinates of control points Pi: the first control point has coordinates P1 = (x1, y1), the second: P2 = (x2, y2), and so on, the curve coordinates are described by the equation that depends on the parameter `t` from the segment `[0,1]`. - The formula for a 2-points curve: P = (1-t)P1 + tP2 -- For three points: +- For 3 control points: P = (1−t)2P1 + 2(1−t)tP2 + t2P3 -- For four points: +- For 4 control points: P = (1−t)3P1 + 3(1−t)2tP2 +3(1−t)t2P3 + t3P4 diff --git a/3-animation/2-css-animations/article.md b/3-animation/2-css-animations/article.md index 332eb8f8..1189ab95 100644 --- a/3-animation/2-css-animations/article.md +++ b/3-animation/2-css-animations/article.md @@ -40,7 +40,7 @@ Click the button below to animate the background: ``` -There are 5 properties to describe CSS transitions: +There are 4 properties to describe CSS transitions: - `transition-property` - `transition-duration` @@ -260,9 +260,15 @@ But how to make the Bezier curve for a specific task? There are many tools. For Timing function `steps(number of steps[, start/end])` allows to split animation into steps. -Let's see that in an example with digits. We'll make the digits change not in a smooth, but in a discrete way. +Let's see that in an example with digits. -For that we split the animation into 9 steps: +Here's a list of digits, without any animations, just as a source: + +[codetabs src="step-list"] + +We'll make the digits appear in a discrete way by making the part of the list outside of the red "window" invisible and shifting the list to the left with each step. + +There will be 9 steps, a step-move for each digit: ```css #stripe.animate { @@ -271,11 +277,11 @@ For that we split the animation into 9 steps: } ``` -In action `step(9, start)`: +In action: [codetabs src="step"] -The first argument of `steps` is the number of steps. The transform will be split into 9 parts (10% each). The time interval is divided as well: 9 seconds split into 1 second intervals. +The first argument of `steps(9, start)` is the number of steps. The transform will be split into 9 parts (10% each). The time interval is automatically divided into 9 parts as well, so `transition: 9s` gives us 9 seconds for the whole animation – 1 second per digit. The second argument is one of two words: `start` or `end`. @@ -301,7 +307,7 @@ So the process would go like this: - ... - `9s` -- `-90%` -In action `step(9, end)`: +Here's `step(9, end)` in action (note the pause between the first digit change): [codetabs src="step-end"] diff --git a/3-animation/2-css-animations/step-list.view/index.html b/3-animation/2-css-animations/step-list.view/index.html new file mode 100644 index 00000000..d7931f5e --- /dev/null +++ b/3-animation/2-css-animations/step-list.view/index.html @@ -0,0 +1,14 @@ + + + + + + + + + + +
0123456789
+ + + diff --git a/3-animation/2-css-animations/step-list.view/style.css b/3-animation/2-css-animations/step-list.view/style.css new file mode 100644 index 00000000..a934e834 --- /dev/null +++ b/3-animation/2-css-animations/step-list.view/style.css @@ -0,0 +1,9 @@ +#digit { + border: 1px solid red; + width: 1.2em; +} + +#stripe { + display: inline-block; + font: 32px monospace; +} diff --git a/3-animation/3-js-animation/article.md b/3-animation/3-js-animation/article.md index b6208e9f..f0f258c3 100644 --- a/3-animation/3-js-animation/article.md +++ b/3-animation/3-js-animation/article.md @@ -4,20 +4,19 @@ JavaScript animations can handle things that CSS can't. For instance, moving along a complex path, with a timing function different from Bezier curves, or an animation on a canvas. -## setInterval +## Using setInterval -From the HTML/CSS point of view, an animation is a gradual change of the style property. For instance, changing `style.left` from `0px` to `100px` moves the element. +An animation can be implemented as a sequence of frames -- usually small changes to HTML/CSS properties. -And if we increase it in `setInterval`, by making 50 small changes per second, then it looks smooth. That's the same principle as in the cinema: 24 or more frames per second is enough to make it look smooth. +For instance, changing `style.left` from `0px` to `100px` moves the element. And if we increase it in `setInterval`, changing by `2px` with a tiny delay, like 50 times per second, then it looks smooth. That's the same principle as in the cinema: 24 or more frames per second is enough to make it look smooth. The pseudo-code can look like this: ```js -let delay = 1000 / 50; // in 1 second 50 frames let timer = setInterval(function() { if (animation complete) clearInterval(timer); - else increase style.left -}, delay) + else increase style.left by 2px +}, 20); // change by 2px every 20ms, about 50 frames per second ``` More complete example of the animation: @@ -50,15 +49,13 @@ Click for the demo: [codetabs height=200 src="move"] -## requestAnimationFrame +## Using requestAnimationFrame Let's imagine we have several animations running simultaneously. -If we run them separately, each one with its own `setInterval(..., 20)`, then the browser would have to repaint much more often than every `20ms`. +If we run them separately, then even though each one has `setInterval(..., 20)`, then the browser would have to repaint much more often than every `20ms`. -Each `setInterval` triggers once per `20ms`, but they are independent, so we have several independent runs within `20ms`. - -These several independent redraws should be grouped together, to make it easier for the browser. +That's because they have different starting time, so "every 20ms" differs between different animations. The intervals are not alignned. So we'll have several independent runs within `20ms`. In other words, this: @@ -70,19 +67,19 @@ setInterval(function() { }, 20) ``` -...Is lighter than this: +...Is lighter than three independent calls: ```js -setInterval(animate1, 20); -setInterval(animate2, 20); +setInterval(animate1, 20); // independent animations +setInterval(animate2, 20); // in different places of the script setInterval(animate3, 20); ``` -There's one more thing to keep in mind. Sometimes when CPU is overloaded, or there are other reasons to redraw less often. For instance, if the browser tab is hidden, then there's totally no point in drawing. +These several independent redraws should be grouped together, to make the redraw easier for the browser (and hence smoother for people). -There's a standard [Animation timing](http://www.w3.org/TR/animation-timing/) that provides the function `requestAnimationFrame`. +There's one more thing to keep in mind. Sometimes when CPU is overloaded, or there are other reasons to redraw less often (like when the browser tab is hidden), so we really shouldn't run it every `20ms`. -It addresses all these issues and even more. +But how do we know about that in JavaScript? There's a specification [Animation timing](http://www.w3.org/TR/animation-timing/) that provides the function `requestAnimationFrame`. It addresses all these issues and even more. The syntax: ```js @@ -416,7 +413,7 @@ Here's the animated "bouncing" text typing: ## Summary -JavaScript animation should be implemented via `requestAnimationFrame`. That built-in method allows to setup a callback function to run when the browser will be preparing a repaint. Usually that's very soon, but the exact time depends on the browser. +For animations that CSS can't handle well, or those that need tight control, JavaScript can help. JavaScript animations should be implemented via `requestAnimationFrame`. That built-in method allows to setup a callback function to run when the browser will be preparing a repaint. Usually that's very soon, but the exact time depends on the browser. When a page is in the background, there are no repaints at all, so the callback won't run: the animation will be suspended and won't consume resources. That's great.