Ceci est une ancienne révision du document !
Last time, we looked at some very basic JavaScript to alert or log a message when you click on an object in your drawing, or move the mouse over it. The one-line boxes in the object properties are okay for such short snippets of code, but you wouldn’t want to write anything too complex in there. Instead, Inkscape has a couple of other mechanisms for using larger amounts of code in your page: embedded scripts and external scripts. Both of these features live in the Document Properties dialog, so open that first (File > Document Properties, or CTRL-SHIFT-D), then switch to the “Scripting” tab. Within that area are two other tabs; in this article we’re going to look at the second one, “Embedded scripts”.
In my opinion, there are a few issues with the UI in this dialog. You might think you can just go ahead and type some JavaScript into the “Content” section, but that won’t actually create anything in your file. Instead you must first either select an existing entry from the “Embedded script files” section, or create a new one using the “+” button and then select it. I don’t know why the Content section isn’t disabled until something is selected, nor why a newly created entry isn’t selected by default, but so long as you remember that anything typed into the bottom section will be lost unless there’s an entry selected in the top, you’ll be okay. Let’s create a new entry by clicking the “+” button, then select it and enter a little JavaScript into the bottom. We’ll just call the alert() function a couple of times at this point.
Note that our alert() calls finish with semicolons, so the JavaScript interpreter knows where one statement ends and the next begins. Save your file, and open it directly in a web browser. You should immediately see two messages appear, even before the content of your document is rendered. JavaScript statements entered like this – outside of any function – are part of the global scope, and are executed as soon as the file is loaded. Now repeat the process to create a second embedded script file, with similar alert() calls, but the message changed to ‘Second embedded script…’. Save your file, and reload it in your web browser (F5). You should see four messages displayed in succession – but, if you read the details, you’ll notice that the ones from your second script are displayed first! This is something to be very careful with: the scripts appear in the XML file, and are therefore processed by the browser, in the order they appear in the list, not in the order you created them. In another UI faux-pas, however, it’s not possible to re-order the scripts in this dialog.
One way around this problem is to just use a single embedded script, and manually reorder your lines in the Content box. Multiple scripts are all just concatenated together by the browser anyway, so whether you use a single script, or a hundred, it doesn’t matter from a JavaScript perspective. Note, however, that the Content box is a little short, and can’t be resized (another UI fail). If you want to put a lot of code into your file, then, being able to see only a tiny sliver of it at a time will make it rather difficult to work on. Usually, the ordering of the scripts isn’t too much of a problem, as JavaScript code is typically arranged into functions. The order in which the code executes then depends on the sequence in which the functions are called, not the order they appear in the file. This also goes some way to explaining why the fields in the Interactivity section of the Object Properties dialog allow only a single line of code: typically they have to make only a single call to execute a separate multi-line function. As an example of this, let’s use a function in an embedded script to change the fill color of an object when it’s clicked on.
In a new file, create a simple object – a square or circle – with a visible stroke and an obvious fill color. I’ve stuck with the red rounded rectangle I used last time. Now create a new embedded script file, with the following content: function change_to_blue(elem) { elem.style.fill = 'blue'; } We’ve created a function named change_to_blue() which takes a single parameter that we’ve chosen to call “elem” as it represents a single XML element in your file. This parameter will be a reference to the object you click on, and the body of the function just sets the fill color on that object to “blue” (a valid CSS color name). By putting our fill change inside a function we prevent it from running as soon as the page is loaded. Instead we have to explicitly call it from somewhere else in our file. That somewhere else is the “onclick” field of the Object Properties dialog, which I covered last time. To call our function, we simply have to invoke it by name, but we also need to pass a reference to the object you clicked on. JavaScript has a keyword, “this”, which means different things in different contexts – but in the case of a simple event handler like this, it gives us the reference we need. Therefore the line to put into the onclick field is this: change_to_blue(this); Save and reload your file, then click on your red object. It should turn to blue. See, interactive SVG isn’t so tricky after all!
Try creating more objects, each with a different fill color, but each with the same line in their onclick field. Notice that clicking each one changes the color of only that specific element, thanks to the “this” keyword. Rather than just set the color to blue, how about creating a toggle between two colors each time the object is clicked. The code’s pretty straightforward: we just test to see if the fill color is currently ‘blue’ and, if so, set it to ‘red’. Otherwise we explicitly set it to blue. Here’s the code: function change_to_blue(elem) { if (elem.style.fill === 'blue') { elem.style.fill = 'red'; } else { elem.style.fill = 'blue'; } } If you’re not familiar with JavaScript, be particularly aware of the ‘===’ in the ‘if’ statement: this triple equals means “are both the value and the type of the variable identical?” It’s a more robust check than double equals (“are the values effectively the same, even if the types are different”), and is not the same at all as a single equals, which is used for assigning a value to a variable, not for testing it.
This new code is all well and good, but it would be better still if, instead of simply toggling between blue and red, we toggled between blue and whatever color the object previously had. To do this we need to store the old value of the fill color before we change it to blue, then use that stored value when we turn it back again. Fortunately for us, the “elem” reference that is passed in (“this” on the calling element) is a JavaScript ‘Object’ (not the same as an object you draw in Inkscape), which can hold additional custom properties. We’ll dynamically create a new property, called ‘previousFill’ to hold the value of the fill just before we change it. Our toggling code becomes this: function change_to_blue(elem) { if (elem.style.fill === 'blue') { elem.style.fill = elem.previousFill; } else { elem.previousFill = elem.style.fill; elem.style.fill = 'blue'; } } In the “else” section we store the old fill in our ‘previousFill’ property; in the “if” section we use that value instead of the string “red”. Strictly speaking, we should probably also rename the function to toggle_fill() or something similar – but that suggests we could toggle to a color other than blue, which the code doesn’t do at the moment.
Let’s extend it a little further so that we can toggle to a different color. By taking an optional second parameter we can let the calling code determine what the toggle color should be, but still fall back to blue as a default. The toggling code becomes this: function toggle_fill(elem, color) { if (color === undefined) color = 'blue'; if (elem.style.fill === color) { elem.style.fill = elem.previousFill; } else { elem.previousFill = elem.style.fill; elem.style.fill = color; } } Note that we test the color variable to see if it’s the special value ‘undefined’. Note that this is a primitive type in JavaScript, like ‘Number’, ‘String’ or ‘Object’, so we’re testing to see if color is this special type, not testing to see if it’s a string containing the word “undefined”. That’s why there are no quotes around the word in the code.
Whenever a parameter is missing in a function call, the corresponding value in the receiving function is given a value of ‘undefined’. By explicitly testing for this, we can therefore decide what to do if the parameter is omitted – in this case use a default value of ‘blue’ instead. There are various ways to handle missing and default parameters in JavaScript, but this particular syntax is clear, robust, and works even in older browsers. With this default value in place, the calling code can be any one of these examples: toggle_fill(this); toggle_fill(this, undefined); toggle_fill(this, 'yellow'); toggle_fill(this, 'red'); This toggle_fill() function can therefore work with just a single parameter – in which case ‘color’ is undefined and gets set to ‘blue’ – or with two parameters. If the second parameter is explicitly set to ‘undefined’ then it’s the same as using just one parameter; otherwise the value will be used to set the fill color. But see how already, with only a short function like this, we’ve exceeded the number of lines in the Content box in Inkscape. I hope you like coding through a letterbox!
Although this function is a lot more flexible than our original creation, you should be aware that not all valid CSS colors will work in this type of code: rgb() values might get returned by the browser as hexadecimal strings, for example, or the it might change the case, either of which will stop the equality test from working. Code like this, which makes assumptions about data without testing those assumptions rigorously, is fragile and easily broken. But writing this code in a less fragile way isn’t easy, and is certainly outside the scope of this tutorial series. For now you can play around with the code just to get a feel for embedding JavaScript into your SVG files. Next time, however, I’ll show you how to use CSS classes, in conjunction with JavaScript, to make toggling fill colors (and other styles) far more robust.