Ceci est une ancienne révision du document !
Over the past few months, you’d be forgiven for thinking that this column has morphed from an Inkscape tutorial to a more general “SVG in HTML” series. In practice, I’ve been introducing a little background knowledge before delving into the (limited) JavaScript features that are already present in Inkscape. But that requires just a little more background information about JavaScript itself, and its use in SVG on the web… JavaScript (JS) is the de facto programming language used in web pages. It’s an implementation of a language called ECMAScript, so you might occasionally see that term mentioned. It’s nothing to do with the Java programming language – it just shares a similar name thanks to someone in marketing at Netscape many years ago deciding that ‘brand awareness’ was more important than ‘avoiding decades of confusion’.
Dans les quelques derniers mois, vous seriez pardonné si vous avez pensé que cette rubrique s'était transformée d'un tutoriel sur Inkscape en une série plus généraliste sur « le SVG dans le HTML ». En pratique, j'avais présenté un peu de savoir de base avant de plonger des des fonctionnalités (limitées) du JavaScript qui sont déjà présentes dans Inkscape. Mais ceci réclame un peu plus d'information de fond sur le JavaScript lui-même, et son utilisation dans sVG sur le Web…
JavaScript (JS) est de fait le langage de programmation utilisé dans les pages du Web. C'est une implémentation d'un langage appelé ECMAScript ; aussi, vous pourrez peut-être rencontrer occasionnellement une mention de ce terme. Ça n'a rien à voir avec le langage de programmation Java - ils partagent simplement un nom similaire grâce à quelqu'un du marketing chez Netscape qui a, il y a pas mal d'années, décidé que la « notoriété commerciale » était plus importante que « d'éviter des années de confusion ».
Within a browser, JavaScript gives you the capability to write code that can modify the page and respond to interactions initiated by the user, or by external actions such as some data being pushed from a server. These triggers are referred to as ‘events’, and will form the core of the JS code we’ll be writing in this series. The basic approach is that we’ll use SVG to draw something to the browser window, then attach events to monitor for clicks, mouse movements, keypresses, and so on, each of which then triggers some JS code which can, in turn, modify the SVG. Because JavaScript can read keypresses from the user, and can talk to a server, it raises security concerns. You could, for example, use SVG to create a beautiful image, but as soon as the mouse moves over it, your JS could redraw the image to look like a legitimate username/password box has opened on the screen. Anything typed into the box could be sent back to your server and used for your own nefarious ends. As a technically aware reader of FCM, you may not be fooled by such an obvious scam, but a huge number of people will happily enter their credentials into such a dialog as an almost Pavlovian response.
Dans un navigateur, JavaScript vous donne la possibilité d'écrire du code qui peut modifier la page et répondre aux interactions initiées par l'utilisateur, ou par des actions externes telles des données envoyées depuis un serveur. Ces déclencheurs sont référencés comme des « events » (évènements) et formeront le cœur du code JS que nous écroirons dans cet article. En gros, l'a approche va être d'utiliser SVG pour dessiner quelque chose dans la fenêtre du navigateur, puis d'y attacher des évènements pour gérer des clics, des mouvements de la souris, des appuis au clavier et autres, chacun d'eux déclenchant un peu de code JS qui peut, à son tour, modifier le SVG.
Comme JavaScript peut lire les appuis de l'utilisateur sur des touches, et peut converser avec un serveur, il pose des problèmes de sécurité. Vous pourriez, par exemple, utiliser SVG pour créer une belle image, mais, dès que la souris passe au-dessus, votre JS pourrait redessiner l'image pour qu'elle ressemble à une vraie boîte de dialogue pour identifiant et mot de passe qui s'ouvre à l'écran. Tout ce qui serait taper dans la boîte serait alors renvoyé au serveur et utilisé malheureusement à vos dépens. Comme vous êtes un lecteur techniquement averti du FCM, vous ne vous feriez pas avoir par une telle arnaque, mais un très grand nombre des gens entreraient gentiment leurs identifiants dans une telle boîte de dialogue, presque comme un réflexe pavlovien.
To prevent such attacks, browsers limit the ability of SVG to run JavaScript, depending on how the SVG has been included in the page. I’ve talked about this previously, but it’s worth recapping: SVG in an <img>: This is how images are usually displayed in a web page, and is used in countless bulletin boards and social media sites. Because anyone can upload any image, there’s a huge potential security hole, so JavaScript in SVG is blocked entirely. SVG as a CSS background-image: Although less frequently used as a way for users to upload images, the code paths used in browsers are pretty much the same for CSS images as for <img> elements, so the previous rule still applies: no JavaScript. Inline SVG: This requires the actual code of the page to be edited, so it’s assumed that the work is being done by someone in a trusted position, and therefore the browser allows JavaScript.
Pour empêcher de telles attaques, les navigateurs limitent la possibilité pour le SVG de lancer du Javascript, suivant comment le SVG a été incorporé dans la page. J'en avais parlé précédemment, mais c'est bien de récapituler :
SVG dans un <img> : C'est ainsi que les images sont généralement affichées dans une page Web, et c'est utiliser dans un nombre incalculable de sites de murs d'affichage et de médias sociaux. Comme n'importe qui peut téléverser n'importe quelle image, il y a un énorme trou de sécurité potentiel, ; aussi, le JavaScript dans du SVG est entièrement bloqué.
SVG comme image d'arrière-plan du CSS : Bien que moins fréquemment utilisée par les utilisateurs pour téléverser des images, les bouts de code utilisés dans les navigateurs sont à peu près les mêmes pour les images du CSS que pour les éléments <img> ; aussi, les règles précédentes s'appliquent donc : pas de JavaScript.
SVG en ligne : Ceci requiert que le vrai code de la page soit édité ; aussi, il est admis que ce travail doit être fait pas une personne de confiance et, donc, le JavaScript est autorisé.
SVG in an <object> This is the W3C standard way to include “foreign” content into a web page – including Flash, Java applets, and other potentially dangerous code. As such, it’s always had a more lax set of security rules than <img>, and no sensible website developer allows user-uploaded content to be displayed in an <object>. Therefore it’s considered to be something that is added only by someone in a trusted position, and JavaScript is allowed. SVG in an <iframe>: Using an <iframe> has a simple syntax, similar to an <img>, but still allows JavaScript like an <object>. I tend to use <object> as that’s the officially recommended approach by the W3C, but there are times when an <iframe> is a better option.
SVG dans un <object> : C'est la façon normative du W3C pour inclure du contenu « étranger » dans une page Web - y compris du Flash, des applets Java, et d'autres codes potentiellement dangereux. Comme tel, il a toujours eu un ensemble de règles de sécurité plus souple que <img> et aucun développeur de site Web sensible n'autorise que du contenu téléversé par l'utilisateur soit affiché dans un <object>. Ainsi donc, c'est considéré comme quelque chose qui est ajouté uniquement par une personne de confiance, et JavaScript est autorisé.
SVG dans une <iframe> : Une <iframe> a une syntaxe simple d'utilisation, voisine de celle d'une <img>, mais le JavaScript est autorisé comme pour un <object>. J'ai tendance à utiliser un <object> car c'est l'approche recommandée par le W3C ; mais il y a des moments où une <iframe> est une meilleure option.
There’s one final way to display an SVG image in a browser which doesn’t involve embedding it into an HTML file in any way, and that’s simply to load the SVG file directly. For an SVG file on your local machine, you can just press CTRL-O and find it in the file selector. For one sent by a web server, the browser’s URL field just has to point directly at the SVG image, and the browser will load it in the same manner as if you pointed directly at a PNG or JPEG file… …except it won’t. Not unless the server has been configured correctly. Which is a whole other story of politics and pain in which countless users and developers suffer from an ideological disagreement at a technical level. Brace yourself, this is going to get petty!
Il y a une dernière façon d'afficher une image SVG dans un navigateur qui ne nécessite d'aucune manière de l'incorporer dans un fichier HTML ; c'est de charger directement le fichier SVG. Si le fichier SVG est sur votre machine locale, vous avez juste à appuyer sur Ctrl-O pour le rechercher dans le sélecteur de fichier. Pour un fichier envoyé par un serveur Web, le champ pour l'URL dans le navigateur doit directement pointer sur l'image SVG et le navigateur la chargera de la même manière qui si vous pointiez sur une image PNG ou JPEG…
…sauf qui ne le fera pas. Sauf si le serveur a été configuré correctement. Ce qui est une toute autre histoire douloureuse de grands principes dans lesquels d'innombrables utilisateurs et développeurs ont souffert d'un désaccord idéologique au niveau technique. Accrochez-vous ; ça va devenir mesquin !
Serving an SVG file isn’t terribly tricky. Your web server has to be configured to send the right MIME type (a header that tells the browser what sort of file it’s receiving), but that’s usually a small configuration change. If you’ve got direct control over the configuration of your server, search online for some appropriate terms (e.g. “Apache SVG MIME”), and you should find suitable instructions. If your server is managed by someone else – such as the typical case of a website hosted by an ISP – first try putting an SVG image onto your site and accessing it, as there’s a good chance the configuration has already been done. If the file appears as text, the browser tries to save rather than display it, or there’s a message suggesting the browser’s treating it as an XML document, you’ll need to raise a support request with your host.
Se servir d'un fichier SVG n'est pas terriblement compliqué. Votre serveur Web doit être configuré pour envoyer le bon type MIME (une entête qui dit au navigateur quel est le type de fichier qu'il reçoit), mais c'est en général une petite modification de la configuration. Si vous avez directement le contrôle de la configuration du serveur, cherchez en ligne avec les termes appropriés (par ex., « Apache SVG MIME ») et vous devriez trouver des instructions convenables. Si votre serveur est géré par quelqu'un d'autre - ce qui est le cas typique pour un serveur hébergé par un ISP (Internet Service Provider - Fournisseur de services Internet) - essayez d'abord de mettre votre image SVG sur le site et d'y accéder, car il y a de bonnes chances que la configuration ait déjà été faite. Si le fichier apparaît comme du texte, si le navigateur essaie de le sauvegarder plutôt que de l'afficher, ou s'il y a un message suggérant que le navigateur le traite comme un document XML, vous devrez demander de l'aide à votre hébergeur.
Where it gets more complex is with SVGZ files – “compressed SVG” in Inkscape’s terms. These are literally just SVG files that have been compressed using the Gzip algorithm, and you can get the same effect by using the gzip program on your Linux box: gzip -k image.svg mv image.svg.gz image.svgz The first line creates a gzipped version of “image.svg” but doesn’t overwrite the original file (due to the -k switch). Gzip defaults to simply appending “.gz” to the filename, so the second line renames the file to the standard “.svgz” (this could also be done directly with the “–suffix” switch to gzip). The resultant file can be directly loaded into Inkscape for further editing – it’s indistinguishable from a “compressed SVG” file saved from Inkscape itself. On the surface, SVGZ seems like a great format, as it’s much smaller than an equivalent SVG file, but you can still open it in Inkscape, or even convert back and forth from the command-line if you do want to edit the XML content by hand. The problems come when you try to put an SVGZ file online.
Là où ça devienne plus compliqué c'est avec les fichiers SVGZ - « SVG compressé » en termes d'Inkscape. Ce ne sont vraiment que de fichiers SVG qui ont été compressés avec l'algorithme Gzip et vous pouvez obtenir le même résultat en utilisant le programme gzip sur votre appareil Linux :
gzip -k image.svg
mv image.svg.gz image.svgz
La première ligne crée une version « g-zippée » de « image.svg » mais ne modifie pas le fichier d'origine (du fait du commutateur -k). Par défaut, Gzip ajoute « .gz » au nom du fichier ; aussi, la seconde ligne renomme le fichier avec l'extension classique « .svgz » (ceci peut être fait directement avec le commutateur « –suffix » dans gzip). Le fichier résultant peut être chargé directement dans Inkscape pour une future modification - il n'y a aucune différence avec le fichier « SVG compressé » sauvegardé par Inkscape lui-même. En surface, SVGZ semble être un bon format, car il est beaucoup plus petit que le fichier SVG équivalent, mais vous pouvez toujours l'ouvrir dans Inkscape, ou même le convertir dans un sens puis dans l'autre avec la ligne de commande il vous voulez modifier le contenu XML à la main. Les problèmes arrivent quand vous essayez de mettre un fichier SVGZ en ligne.
The W3C working group that created SVG thought, quite rightly, that defining a compressed form of the format as part of the spec would be a worthwhile addition, especially back in 2001 when storage space and bandwidth were more expensive. Gzipping of content on-the-fly was already a standard feature of the web, so browsers had decompression code in place, making for an obvious choice of algorithm. Unfortunately, this is where an ideological divide took place: rather than treat SVGZ as a format in its own right, the browser vendors opted to natively support only uncompressed SVG. But saying that is like stating that browsers support only uncompressed HTML or CSS. In practice you can send any supported format with on-the-fly Gzip compression, provided your web server correctly sets the “content-encoding” header. This also means that you can send a pre-compressed SVGZ file if you also provide that header – the browser just thinks you’ve sent an SVG file using on-the-fly compression. Once again, search online for the instructions for your web server, or raise a support request with your ISP if necessary.
Le groupe de travail du W3G qui a créé SVG pensait, très correctement, que la définition d'une forme compressée du format comme partie intégrante de la spécif. serait un ajout valable, spécialement en 2001 quand l'espace de stockage et la bande passante étant plus coûteuses. Le « g-zippage » du contenu à la volée était déjà une fonctionnalité classique du Web, et les navigateurs avaient déjà mis en place le code de décompression, faisant le choix évident de l'algorithme. Malheureusement, c'est là qu'une division idéologique a pris jour : plutôt que de traiter SVGZ comme un format de plein droit, les fournisseurs de navigateurs n'optèrent nativement que pour le support du SVG non compressé.
Mais dire ceci, c'est comme faire état du seul support des HTML ou CSS non compressés par les navigateurs. En pratique, vous pouvez envoyer n'importe quel format avec un compression gzip à la volée, à condition que votre serveur Web mette correctement l'entête « content-encoding » (codage du contenu). Ceci signifie aussi que vous pouvez envoyer un fichier SVG pré-compressé si vous fournissez aussi l'entête - le navigateur pense simplement que vous avez envoyé un fichier SVG avec une compression à la volée. Une fois encore, recherchez en ligne les instructions pour votre serveur Web ou demandez un support à votre ISP, si nécessaire.
The summary, therefore, is that browsers don’t really support SVGZ, but with the right server configuration, you can trick them into using those files nevertheless. It also explains why you can’t load an SVGZ file directly into your browser from the local filesystem – if the file doesn’t come from a web server, there’s no “content-encoding” header, and the browser decides to play dumb. This situation could easily be fixed if browsers opted to treat SVGZ as a first class file format, and automatically unzip it even in the absence of the header. But as the situation is unlikely to change, I recommend sticking with SVG files and using on-the-fly compression from your web server, rather than trying to work directly with SVGZ files.
Personally, I think the browser vendors are wrong on this one. JPEG images, for example, are essentially just arrays of pixels that are compressed using a “discrete cosine transformation” (DCT) algorithm. Yet browsers don’t insist on a “content-encoding: DCT” header to display a JPEG. The philosophical difference between a file that has been compressed using Gzip by the server, and one that has been natively stored in a gzipped format, is a subtle one. But the result is that users suffer from the complexity and confusion of not being able to directly load an SVGZ file into the browser, even though that format has been explicitly sanctioned by the SVG Working Group.
To begin our journey into the world of Inkscape and JavaScript, I’ll assume that you are able to load an Inkscape-created SVG file into your web browser, either from a web server or from the local filesystem. Later on, we’ll look at some differences that apply when you use <object>, <iframe>, or inline SVG, but, right now, let’s keep things self contained in a simple SVG file. Remember those JavaScript ‘events’ I spoke of earlier? Let’s use Inkscape to add some JS code that listens for a “click” event – the result of the user clicking on an object in our image. Create a new image, draw a simple object, then right-click on it and bring up the Object Properties dialog. At the bottom of the dialog is a series of fields, all with labels that start with the word “on”. If they’re not visible, you’ll need to click on the “Interactivity” label to expose them. In the “onclick” field, enter the following JavaScript code: alert('Clicked')
Save the file and load it into your web browser. You should see the object you drew in Inkscape. Click on it to confirm that the browser presents you with a dialog that contains the word “Clicked”. This type of dialog, referred to as ‘an alert’, is the simplest form of output from JavaScript. You can display only a single string, and you can’t change the layout of the dialog or the label on the button. But writing even this most simplistic of code is a useful first step in any JavaScript application: it proves that Inkscape, your browser, and your web server (if you have one) are all working as expected, and it confirms that your code can respond to mouse clicks, which is a basic requirement for almost any interactive site. The single line of code you wrote above does one thing: it calls a function named alert() when the user clicks the left mouse button (or taps) on the object to which you attached your code. The function is given a single parameter – a string containing the word “Clicked” – which it displays on the screen in a dialog. Let’s see how that code in Inkscape manifests itself in the SVG file. Open the SVG file in a text edito and, towards the bottom of the file, you should find something similar to the code shown on the next page, top right.
You might have a different element than a <rect>, depending on what you drew – and therefore may have other attributes (the “rx” and “ry” attributes govern the roundedness of a rectangle’s corners, for example). I’ve also significantly abbreviated the “style” attribute. But the thing to note is the “onclick” attribute, which contains the JavaScript we typed into the dialog in Inkscape earlier. It’s worth getting familiar with the way that your JS appears in the file. Whilst the single-line text boxes in Inkscape are okay for typing very short amounts of code, if you need something even slightly more substantial, it’s often easier to edit the SVG directly. Here’s a modified version of my object (with extraneous attributes omitted), to show how you might deal with multiple lines: With those edits in place and saved, reload your page, and click on your object again. This time you should see a series of three alerts.
Unfortunately, edits made like this don’t reflect well back in the Inkscape UI. Your three lines will be present, but all put onto a single line, and with any white space that you used to align them included in the line. Generally it’s easiest to edit code in either a text editor, or in Inkscape, but not to go back and forth between them. As you’ve guessed from the Inkscape UI, there are other events you can react to. But, in most cases, using the alert() function will prevent you testing correctly. Consider trying the onmousemove option, which is supposed to fire events continuously as your mouse moves over your object: as soon as your mouse moves over the object you’ll get an alert which you’ll need to dismiss before you can continue; then another, and another, each time your mouse moves over the object, with you having to manually dismiss each one in turn. Hardly the constant stream of events you were interested in.
Back in the dim and distant past, debugging by throwing up alert messages was the de facto way to develop with JavaScript, but, thankfully, the tools have moved on a lot since then. Modern desktop browsers all have a developer toolbox which you can usually open by pressing F12. There are a variety of tools in here, but the one we’re interested in is the console – there should be a tab for it somewhere near the top of the toolbox. In Inkscape try adding a console.log('Mouse moved') call to the onmousemove section of the object properties: Now, with the file saved and the developer console open, reload your file in the browser. Clicking should throw up an alert, as before, but moving the mouse around over your object should generate a stream of messages in the console. Actually you’re likely to only see one message, plus a count to the right of the console indicating how many times the message has been logged. This is a convenience in modern tools to avoid filling your screen with duplicate messages. If you really want to see them streaming by, you can add a random number to your log entry so that each one becomes unique: console.log('Mouse moved', Math.random())
This demonstrates another huge advantage of console.log() over alert() – you can give it multiple parameters, and they don’t all have to be strings. That’s a very basic start to adding some interactivity to an Inkscape file. We’ll be exploring this topic a lot more over the coming months, so please do try the simple exercises above so that you’ve got a good basis to build on as we make our events do more interesting things than just printing some text to the screen.
A blatant plug! Mark and his colleague Vince have been using Inkscape and MyPaint to create the monthly Elvie cartoon strip, first in Linux Voice, then in Linux Magazine (Linux Pro Magazine in the US), for five years now. To celebrate this anniversary, Mark has written an article in issue #220 of Linux (Pro) Magazine which describes the process they use in some detail. If you’re interested in reading about the practicalities of creating a cartoon using FOSS, this issue should still be current by the time FCM#142 comes out, but it’s also available to buy as a digital edition from http://www.linux-magazine.com/