issue150:inkscape
Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
issue150:inkscape [2019/11/04 14:53] – d52fr | issue150:inkscape [2019/11/07 14:03] (Version actuelle) – andre_domenech | ||
---|---|---|---|
Ligne 3: | Ligne 3: | ||
We have looked at animation in this series before: in part 75 we looked at some simple CSS animations, then in parts 76 and 77 we moved on to SMIL animation. At the time I commented that SMIL was something of a dead-end technology, largely due to Microsoft never implementing it in any browser. But times have changed, and Microsoft have effectively given up on developing their own browser engine: shortly Microsoft Edge will begin using the same engine as Chrome, so should gain SMIL support as a side-effect. Whether or not this is enough to turn the tide for SMIL remains to be seen. Personally I think it’s a great technology for animating SVG particularly, | We have looked at animation in this series before: in part 75 we looked at some simple CSS animations, then in parts 76 and 77 we moved on to SMIL animation. At the time I commented that SMIL was something of a dead-end technology, largely due to Microsoft never implementing it in any browser. But times have changed, and Microsoft have effectively given up on developing their own browser engine: shortly Microsoft Edge will begin using the same engine as Chrome, so should gain SMIL support as a side-effect. Whether or not this is enough to turn the tide for SMIL remains to be seen. Personally I think it’s a great technology for animating SVG particularly, | ||
- | Durant ces derniers mois, nous avons regardeé | + | Durant ces derniers mois, nous avons regardé |
- | Nous avons déjà une animation dans notre série : dans la partir | + | Nous avons déjà une animation dans notre série : dans la partie |
**So we’re slightly stuck in limbo. SMIL offers huge power, but its time may be short. CSS animation is less powerful, but widely supported. However with JavaScript we can sort-of get the best of both worlds: as much power and flexibility as we need, in a way that has excellent cross-browser support. | **So we’re slightly stuck in limbo. SMIL offers huge power, but its time may be short. CSS animation is less powerful, but widely supported. However with JavaScript we can sort-of get the best of both worlds: as much power and flexibility as we need, in a way that has excellent cross-browser support. | ||
Ligne 11: | Ligne 11: | ||
Of course things aren’t all rosy. When using SMIL or CSS animations you essentially take a pretty hands-off approach to things. Your input is a simple instruction: | Of course things aren’t all rosy. When using SMIL or CSS animations you essentially take a pretty hands-off approach to things. Your input is a simple instruction: | ||
- | Ainsi, nous sommes un peu dans le flou. SMIL offre une puissance énorme, mais son temps est compté. Les animations avec CSS sont moins puissantes, mais largement supportées. Cependant, avec Javascript, nous pouvons | + | Ainsi, nous sommes un peu dans le flou. SMIL offre une puissance énorme, mais son temps est sans doute compté. Les animations avec CSS sont moins puissantes, mais largement supportées. Cependant, avec JavaScript, nous pouvons |
- | Bien sûr, les choses ne sont aps aussi roses. Quand nous utilisons des animations avec SMIL ou CSS, nous privilégions une approche plutôt | + | Bien sûr, les choses ne sont pas toutes |
**So JS animation gives you flexibility, | **So JS animation gives you flexibility, | ||
Ligne 19: | Ligne 19: | ||
Enough of the pros and cons, on with the code! Once again we’ll do all this in the browser’s developer tools, so you’ll need a super simple SVG file to start with the code shown below.** | Enough of the pros and cons, on with the code! Once again we’ll do all this in the browser’s developer tools, so you’ll need a super simple SVG file to start with the code shown below.** | ||
- | L' | + | L' |
- | Arrêtons ces comparaisons, | + | Arrêtons ces comparaisons, |
**If you were to load that file into Inkscape, it should look like the image below. The page boundary is a square of 100×100 units, as defined in the viewBox attribute. The square itself is positioned with its top left corner at 10 units down, and 10 units across from the origin (the top-left of the page in SVG). Remember these units are not pixels – the image will actually be scaled to fit the available space in the browser window. By using a 100×100 viewBox it can be convenient to think of the values as percentages, | **If you were to load that file into Inkscape, it should look like the image below. The page boundary is a square of 100×100 units, as defined in the viewBox attribute. The square itself is positioned with its top left corner at 10 units down, and 10 units across from the origin (the top-left of the page in SVG). Remember these units are not pixels – the image will actually be scaled to fit the available space in the browser window. By using a 100×100 viewBox it can be convenient to think of the values as percentages, | ||
- | Si vous chargiez ce fichier dans Inkscape, il ressemblerait à l' | + | Si vous chargiez ce fichier dans Inkscape, il ressemblerait à l' |
**We’re going to animate the “x” attribute from its starting value of 10 up to a value of 90. Because the square is 30 units wide, this will leave it hanging off the right-hand side of the screen when the animation finishes. I’ve done this to demonstrate a key difference between animating the content of an SVG file, and animating a <div> or other box in an HTML page: in the latter case the page width will grow and a horizontal scroll bar will appear (unless you specifically prevent that behaviour). With an SVG file, anything outside the viewBox simply isn’t rendered, making it easier to have animations that start or end ‘off-screen’. Think of it a little like a theatre stage, with your props and characters moving to and from the wings.** | **We’re going to animate the “x” attribute from its starting value of 10 up to a value of 90. Because the square is 30 units wide, this will leave it hanging off the right-hand side of the screen when the animation finishes. I’ve done this to demonstrate a key difference between animating the content of an SVG file, and animating a <div> or other box in an HTML page: in the latter case the page width will grow and a horizontal scroll bar will appear (unless you specifically prevent that behaviour). With an SVG file, anything outside the viewBox simply isn’t rendered, making it easier to have animations that start or end ‘off-screen’. Think of it a little like a theatre stage, with your props and characters moving to and from the wings.** | ||
- | Nous allons animer l' | + | Nous allons animer l' |
**Load that file into your browser then in the developer console (F12) we’ll get a handle to it assigned to a variable for use later on. | **Load that file into your browser then in the developer console (F12) we’ll get a handle to it assigned to a variable for use later on. | ||
Ligne 45: | Ligne 45: | ||
var s1 = document.querySelector("# | var s1 = document.querySelector("# | ||
- | Rappel : voici comment la coordonnée x peut être modifiée, en utilisant JS. Lancez-la pour confirmer que la boîte se déplace un peu. | + | Rappel : voici comment la coordonnée x peut être modifiée en utilisant JS. Lancez-la pour confirmer que la boîte se déplace un peu. |
s1.setAttribute(" | s1.setAttribute(" | ||
- | En gros, notre animation consistera à lancer une ligne comme celle-là de façon répétitive. | + | En gros, notre animation consistera à lancer une ligne comme celle-là de façon répétitive. |
Ligne 60: | Ligne 60: | ||
setTimeout(moveSquare, | setTimeout(moveSquare, | ||
setTimeout(moveSquare, | setTimeout(moveSquare, | ||
+ | |||
+ | Avez-vous remarqué ce qu'on a fait ? Au lieu de juste paramétrer l' | ||
+ | |||
+ | setTimeout(moveSquare, | ||
+ | setTimeout(moveSquare, | ||
+ | setTimeout(moveSquare, | ||
+ | setTimeout(moveSquare, | ||
+ | setTimeout(moveSquare, | ||
+ | setTimeout(moveSquare, | ||
+ | |||
**Well I don’t think Pixar has got anything to worry about, but it’s definitely animated. Creating a long list of setTimeout() calls isn’t great though. Fortunately JavaScript has a related function, setInterval(), | **Well I don’t think Pixar has got anything to worry about, but it’s definitely animated. Creating a long list of setTimeout() calls isn’t great though. Fortunately JavaScript has a related function, setInterval(), | ||
Ligne 65: | Ligne 75: | ||
var i = setInterval(moveSquare, | var i = setInterval(moveSquare, | ||
- | + | < | |
- | // Some time later… | + | |
clearInterval(i); | clearInterval(i); | ||
+ | |||
+ | Bon. Je ne pense pas que ça inquiète beaucoup Pixar, mais il est bel et bien animé. La création d'une longue liste d' | ||
+ | |||
+ | var i = setInterval(moveSquare, | ||
+ | |||
+ | < | ||
+ | clearInterval(i); | ||
**Now that we don’t have to type a setTimeout() function for every frame of our animation, we can make things move a little more smoothly by reducing the delta, and reducing the time between function calls accordingly: | **Now that we don’t have to type a setTimeout() function for every frame of our animation, we can make things move a little more smoothly by reducing the delta, and reducing the time between function calls accordingly: | ||
Ligne 74: | Ligne 90: | ||
var i = setInterval(moveSquare, | var i = setInterval(moveSquare, | ||
- | // Some time later… | + | < |
clearInterval(i); | clearInterval(i); | ||
Still a bit fast for you? Increase the delay in the setInterval() call. Not fast enough? You can reduce the delay further, but browsers clamp setTimeout() and setInterval() to a lower limit, so it probably won’t have much effect. Instead you can increase the delta value so the square moves two or three units at a time. Or 4.25 if you want – neither JS nor SVG require everything to be integers.** | Still a bit fast for you? Increase the delay in the setInterval() call. Not fast enough? You can reduce the delay further, but browsers clamp setTimeout() and setInterval() to a lower limit, so it probably won’t have much effect. Instead you can increase the delta value so the square moves two or three units at a time. Or 4.25 if you want – neither JS nor SVG require everything to be integers.** | ||
+ | |||
+ | Maintenant que nous n' | ||
+ | |||
+ | var delta = 1; | ||
+ | var i = setInterval(moveSquare, | ||
+ | |||
+ | < | ||
+ | clearInterval(i); | ||
+ | |||
+ | Est-ce encore un peu rapide pour vous ? Augmentez le délai dans l' | ||
**For a long time setTimeout() and setInterval() were the only practical way to run some JavaScript at the sort of regular intervals needed for animation. Over the past few years, however, browsers have gained more support for technologies needed to run games – 2D bitmap canvases, 3D graphics and a little thing called requestAnimationFrame(). In case the name didn’t give it away, this function is intended to make animation a little easier. Specifically it does so by calling a function just before the browser is about to display the next frame on screen (typically about 60 times per second). It’s like a setTimeout() where the delay is automatically set to to an optimal value by the browser.** | **For a long time setTimeout() and setInterval() were the only practical way to run some JavaScript at the sort of regular intervals needed for animation. Over the past few years, however, browsers have gained more support for technologies needed to run games – 2D bitmap canvases, 3D graphics and a little thing called requestAnimationFrame(). In case the name didn’t give it away, this function is intended to make animation a little easier. Specifically it does so by calling a function just before the browser is about to display the next frame on screen (typically about 60 times per second). It’s like a setTimeout() where the delay is automatically set to to an optimal value by the browser.** | ||
+ | |||
+ | Pendant longtemps, setTimeout() et setInterval() furent la seule façon pratique de lancer du JavaScript aux intervalles réguliers nécessaires à une animation. Dans les dernières années, cependant, les navigateurs ont disposé d'un support pour les technologies nécessaires pour faire tourner des jeux : canevas 2D en bitmap, affichage 3D et une petite chose appelée requestAnimationFrame(). Au cas où le nom ne vous dit rien, cette fonction a tendance à faciliter la réalisation d'une animation. En particulier, | ||
**In human terms 1/60 of a second is a pretty short delay, so to test this in the console you will probably want to increate the “delta” variable again, so that it’s more obvious that your square moves. | **In human terms 1/60 of a second is a pretty short delay, so to test this in the console you will probably want to increate the “delta” variable again, so that it’s more obvious that your square moves. | ||
Ligne 88: | Ligne 116: | ||
Now you might be expecting me to introduce an equivalent animation function to setInterval(), | Now you might be expecting me to introduce an equivalent animation function to setInterval(), | ||
+ | |||
+ | À l' | ||
+ | |||
+ | var delta = 10; | ||
+ | |||
+ | requestAnimationFrame(moveSquare); | ||
+ | |||
+ | Maintenant, vous attendez peut-être de moi que je vous présente une fonction d' | ||
**We’ll create a different animation function (shown above) for this next example. It’s similar to the previous one, except that it always moves the square by 1 unit, and stops when it reaches the right-hand side, rather than looping back round. This latter change is mainly so that the code doesn’t keep running indefinitely, | **We’ll create a different animation function (shown above) for this next example. It’s similar to the previous one, except that it always moves the square by 1 unit, and stops when it reaches the right-hand side, rather than looping back round. This latter change is mainly so that the code doesn’t keep running indefinitely, | ||
+ | |||
+ | Nous créerons une fonction d' | ||
**Now we’ve got an animation running, but we don’t really have any control over it. The duration of the animation will depend on how frequently requestAnimationFrame() fires in your browser, and all we can do is change “+ 1” to a different value to make the square move more or less on each iteration. But really that’s all we need to be able to do. So long as we know the exact time that the function is called, we can calculate how far into the animation we are, and therefore what position the square should be at. To achieve this, the function that is called by getAnimationFrame() receives a single parameter: a high-resolution timestamp.** | **Now we’ve got an animation running, but we don’t really have any control over it. The duration of the animation will depend on how frequently requestAnimationFrame() fires in your browser, and all we can do is change “+ 1” to a different value to make the square move more or less on each iteration. But really that’s all we need to be able to do. So long as we know the exact time that the function is called, we can calculate how far into the animation we are, and therefore what position the square should be at. To achieve this, the function that is called by getAnimationFrame() receives a single parameter: a high-resolution timestamp.** | ||
+ | |||
+ | Maintenant, notre animation tourne, mais nous n' | ||
**Let’s work on a practical example: suppose we want our animation to take 10 seconds. At 60 frames per second that’s about 600 movements our square will make, each of them a fraction of a unit. We could divide the total distance by 600 to calculate the exact amount of movement, but that will fail if we run the code on something that refreshes at 30 or 120 frames per second, or if some frames get dropped due to the load on the machine. A better idea is to track how long has passed since the start of the animation, and use that to calculate where the object should be. We can then set the coordinates to the new value, before we fire off another requestAnimationFrame() for the next step in the animation.** | **Let’s work on a practical example: suppose we want our animation to take 10 seconds. At 60 frames per second that’s about 600 movements our square will make, each of them a fraction of a unit. We could divide the total distance by 600 to calculate the exact amount of movement, but that will fail if we run the code on something that refreshes at 30 or 120 frames per second, or if some frames get dropped due to the load on the machine. A better idea is to track how long has passed since the start of the animation, and use that to calculate where the object should be. We can then set the coordinates to the new value, before we fire off another requestAnimationFrame() for the next step in the animation.** | ||
+ | |||
+ | Travaillons sur un exemple pratique : supposez que nous voulons que notre animation prenne 10 secondes. À 60 trames par seconde, notre carré effectuera à peu près 600 mouvements, chacun d'eux d'une fraction d' | ||
**The parameter that gets passed to our function is a value in milliseconds since the document was loaded. We don’t really care about that specific point in time – we need to know how long the animation itself has been running. What we need to do, therefore, is to record the timestamp the first time our function is called. On subsequent calls we can subtract that value from the latest timestamp to work out how far along the animation timeline we have progressed.** | **The parameter that gets passed to our function is a value in milliseconds since the document was loaded. We don’t really care about that specific point in time – we need to know how long the animation itself has been running. What we need to do, therefore, is to record the timestamp the first time our function is called. On subsequent calls we can subtract that value from the latest timestamp to work out how far along the animation timeline we have progressed.** | ||
+ | |||
+ | Le paramètre qui a été passé à notre fonction quand le document a été chargé est une valeur en millisecondes. Nous ne nous soucions vraiment pas de ce moment spécifique, | ||
**Let’s start by initialising a few variables. We’ll create a variable to hold our starting position, setting it to 10. Next we have a “duration” (in milliseconds) to hold the time we want our animation to run for, and “endX” for the X coordinate we want to end up with. Putting these into variables makes it easier to modify the animation to run at a different speed or cover a different distance. Finally we’ll include a “startTime” variable, with an “undefined” value initially, into which we’ll store a copy of the timestamp we receive the first time our animation code is called. | **Let’s start by initialising a few variables. We’ll create a variable to hold our starting position, setting it to 10. Next we have a “duration” (in milliseconds) to hold the time we want our animation to run for, and “endX” for the X coordinate we want to end up with. Putting these into variables makes it easier to modify the animation to run at a different speed or cover a different distance. Finally we’ll include a “startTime” variable, with an “undefined” value initially, into which we’ll store a copy of the timestamp we receive the first time our animation code is called. | ||
Ligne 104: | Ligne 148: | ||
var duration = 10; | var duration = 10; | ||
var startTime = undefined; | var startTime = undefined; | ||
+ | |||
+ | Commençons par initialiser quelques variables. Nous créerons une variable pour conserver notre postion de départ, en la réglant à 10. Ensuite, nous avons « duration » (durée) pour conserver la durée pendant laquelle nous voulons que tourne notre animation et « endX » (fin de X) pour la valeur de la coordonnée X à laquelle nous voulons arrêter l' | ||
+ | |||
+ | var startX = 10 | ||
+ | var endX = 90; | ||
+ | var currentX = 0; | ||
+ | var duration = 10; | ||
+ | var startTime = undefined; | ||
**Now for our reworked animation function. The main animation code is fairly similar to the previous incarnation, | **Now for our reworked animation function. The main animation code is fairly similar to the previous incarnation, | ||
+ | |||
+ | Pour ce qui est de notre fonction d' | ||
**By storing the initial timestamp outside the function, we can calculate how long the animation has been running. Since the two timestamps are in milliseconds, | **By storing the initial timestamp outside the function, we can calculate how long the animation has been running. Since the two timestamps are in milliseconds, | ||
+ | |||
+ | En enregistrant l' | ||
**Running this should produce a smooth animation that takes 10s to complete. Re-run the previous block of “var” lines to reset everything, then the final requestAnimationFrame() call to kick it off again. Try changing the values in the variables to alter the distance the square moves, or the time it takes to perform the animation. In every case you should find that the animation is, if not smooth, at least a lot smoother than you saw with setTimeout() and setInterval().** | **Running this should produce a smooth animation that takes 10s to complete. Re-run the previous block of “var” lines to reset everything, then the final requestAnimationFrame() call to kick it off again. Try changing the values in the variables to alter the distance the square moves, or the time it takes to perform the animation. In every case you should find that the animation is, if not smooth, at least a lot smoother than you saw with setTimeout() and setInterval().** | ||
+ | |||
+ | Une fois lancé, il produira une animation fluide qui prendra 10 s. en tout. Relancez le bloc précédent des lignes « var » pour tout remettre à zéro, puis finissez avec un dernier appel requestAnimationFrame() pour redémarrer. Essayez de changer les valeurs des variables pour modifier la distance de déplacement du carré, ou le temps pris pour dérouler l' | ||
**Creating all these variables outside a function (so-called “global” variables) is generally seen as bad form in the programming world. It also makes it tricky to animate more than one thing, as they’ll all potentially be sharing the same global variables. A better approach is to encapsulate all the variables in a single JavaScript object, then attach that to the SVG element you’re trying to manipulate. Here’s the code above rewritten to work in this way (shown right).** | **Creating all these variables outside a function (so-called “global” variables) is generally seen as bad form in the programming world. It also makes it tricky to animate more than one thing, as they’ll all potentially be sharing the same global variables. A better approach is to encapsulate all the variables in a single JavaScript object, then attach that to the SVG element you’re trying to manipulate. Here’s the code above rewritten to work in this way (shown right).** | ||
+ | |||
+ | La création de toutes ces variables en dehors d'une fonction (appelées variables « globales ») est généralement vu comme une mauvaise pratique dans le monde de la programmation. Cela rend difficile l' | ||
**Notice that I’ve removed the “X” from the end of the parameter names, and created a new “attribute” entry with a value of “x”. This starts to make the code more generic: you could change the “x” to a “y” in order to animate movement in the vertical direction, or “r” to animate the radius of a circle. | **Notice that I’ve removed the “X” from the end of the parameter names, and created a new “attribute” entry with a value of “x”. This starts to make the code more generic: you could change the “x” to a “y” in order to animate movement in the vertical direction, or “r” to animate the radius of a circle. | ||
For a truly generic solution you could turn this JS object into an array of objects. The animation code would loop over each entry in the array, allowing you to animate more than one attribute at a time – essential if you want your images to move at an angle, for example. I’ll leave it as a challenge for the reader to implement this.** | For a truly generic solution you could turn this JS object into an array of objects. The animation code would loop over each entry in the array, allowing you to animate more than one attribute at a time – essential if you want your images to move at an angle, for example. I’ll leave it as a challenge for the reader to implement this.** | ||
+ | |||
+ | Notez que j'ai supprimé le « X » à la fin des noms des paramètres et créé une nouvelle ligne « attribute » avec la valeur de « x ». Ce début rend le code plus générique : vous pouvez changer « x » en « y » pour obtenir un mouvement vertical, ou pour « r » pour animer le rayon d'un cercle. | ||
+ | |||
+ | Pour une solution vraiment générique, | ||
**At the moment our animation is also strictly linear: the attributes are changed at a constant rate over time. More “natural” animation can be achieved with rates that vary – accelerating and decelerating | **At the moment our animation is also strictly linear: the attributes are changed at a constant rate over time. More “natural” animation can be achieved with rates that vary – accelerating and decelerating | ||
+ | |||
+ | Pour l' | ||
+ | |||
+ | |||
+ | |||
+ | |||
issue150/inkscape.1572875634.txt.gz · Dernière modification : 2019/11/04 14:53 de d52fr