Outils pour utilisateurs

Outils du site


issue187:inkscape

Ceci est une ancienne révision du document !


Over the past two articles, I’ve introduced the Web > Interactive Mockup extension, and gone on to show how it’s possible to create the same effect – and with fewer problems – with just a minimal amount of JavaScript. This time, I’ll be finishing this project by adding a little more code that will demonstrate some additional mock-up capabilities that simply aren’t possible using the extension. As a reminder, so far I’ve created a mock-up design consisting of three layers, each representing a different page in a website (which could equally well have been a design for an app, tutorial or presentation). By stacking the layers on top of each other, the JS code simply has to hide all the layers, then re-show the right one when the mock UI is clicked. This code is stored in the Inkscape document, and accessed via File > Document Properties, then the Scripting tab, the Embedded Scripts tab, and finally clicking on the randomly-generated Script ID in the list. Your code will appear in the Content pane at the bottom of the dialog – which is unfortunately not resizeable (you may wish to copy/paste between Inkscape and a text editor to make it easier to modify the code). After last month’s additions, the code looks like that shown above.

Within each interactive element, a single line of JS triggers the change to a different ‘page’ of the demo. These can be found by right-clicking on one of the elements, selecting Object Properties, then expanding the Interactivity section at the bottom of the dialog. For my examples, I’m just triggering changes on mouse clicks, so the ‘onclick’ field contains something like this: showLayer(“about”) That’s all we needed to do in order to create an interactive mock-up that scales with the size of the web browser, and doesn’t allow any non-active pages to be visible. Now let’s push things a little further with the addition of some new features. When looking at the pages of our mock website, it’s clear that they have some common elements – in this case the whole header section. Wouldn’t it be nice if we could keep those on a separate layer, so that any changes to those elements can be made in a single place, rather than having to apply them to each separate layer in our file? This is the sort of thing for which many applications use a ‘Master’ layer. Although not as politically charged as the use of ‘master-slave’ relationships in the computing world, it’s nonetheless a term that can offend people, and which is tending to be phased out. So rather than propagate a troublesome word for no real gain, I’ll be using the term ‘Main layer’.

Our first step, therefore, is to split the file into a single Main layer, plus one additional layer for each page. The Main layer will contain all the common elements, and the others will contain just the page-specific parts. We therefore want our Main layer to be at the bottom of the z-stack, and to remain visible at all times. Here’s how our existing three layers are split into the four we now need: On the left we have the previous three pages. On the right we now have our Main layer at the bottom, with the three content layers above. I’ve added a green border around each of the content layers to indicate their extents: they each now have a transparent background, so without that it wouldn’t be so clear exactly how they relate to the positions in the old pages. These green borders are a temporary addition while developing the mock-up, and are removed before the layers are actually used. Additionally, although I’ve spread the pages out for this image, in practice they’re all stacked on top of each other within the document’s viewBox, as before. By showing the Main layer, plus one of the others at a time, we can therefore reproduce the same appearance as the three layers in the old version. All we need to do now is to modify our code to do the same thing on our behalf. To make the new code a little more readable, we’ll first use the XML editor to change the ID of the new layer to ‘main’, in the same way that we changed the layer IDs previously. When viewed in the XML editor, the top level of our document now looks something like that shown above.

Looking back at our JavaScript file from earlier, we still want our function to perform the same basic task: hide all the layers, then show a specific one. Except now we also want it to show a second layer at the same time. It’s these two lines that are responsible for re-showing the specified layer in the existing code: const layerToShow = document.querySelector(“#” + id); layerToShow.style.display = “inline”; We could simply add a similar pair of lines, hard-coding the ID in the querySelector() call as “#main”. That would definitely do the job, but it’s not very flexible. What if we want to show two ‘main’ layers later, perhaps to separate the text from the graphic elements? To give us this extra flexibility let’s create an array of layers that we want to show, then loop over them to turn them all on. If you’re not a programmer you may not be familiar with arrays: for our purposes you can think of them as a special type of variable that can hold a list of things. For this simple mock-up, our list will always contain ‘main’ and the id that was passed into the function, but you should be able to guess how you might extend it to include ‘main-text’ and ‘main-graphics’: const layersToDisplay = [“main”, id];

Now we need to step through the array, pulling out one item at a time to work with. As we pull each of them out (using a forEach() loop), we get to assign the value to a variable. By naming this variable ‘id’, we are able to reuse our existing code for finding and showing the layer. The end result is something very similar to the code that was previously at the end of the showLayer() function, just with a little more wrapped around it (shown above). The last thing we need to do is to make sure that all the clickable elements still call the showLayer() function, passing the correct ID, after the re-working of layers that we did earlier. It’s particularly important to double-check any items that you’ve moved to the Main layer. Once you’re happy, load the page into a web browser and ensure each of the elements functions as you expect it to when you click on it – if any don’t, then double-check the code associated with them. So far, so good. But on trying out your interactive mock-up, you may have noticed that the mouse pointer doesn’t change to indicate that elements are clickable. It’s a minor visual thing, but we can definitely improve it. There are various ways to tackle this, but they all end up with us needing a line of CSS that tells the browser what cursor type to use. We want this to apply to all the elements with an ‘onclick’ handler. In our SVG, these are all implemented using ‘onclick’ attributes directly in the XML content – which means we should be able to add a style rule using an ‘[onclick]’ selector (matches any element with an ‘onclick’ attribute). That sounds like a perfect use for Inkscape’s ‘Selectors and CSS dialog’, right?

Wrong. As I mentioned in part 112 of this series, the dialog doesn’t recognise the attribute selector syntax. An alternative is to create a suitable <style> block directly in the XML, either using Inkscape’s built-in XML editor, or by editing the SVG file in a text editor. Both of these approaches are a little awkward, especially if you’re not already an XML aficionado. Instead, let’s take a similar approach to the one we used for setting the height and width attributes: we’ll write a short bit of JavaScript that will manipulate the document directly when it’s loaded into the browser. We want this code to run once, on page load, so the following snippet should be added to the JS outside the showLayer() function. Just appending it to the bottom of the existing code is probably the easiest option. let css = document.createElementNS(“http://www.w3.org/2000/svg”, “style”); css.textContent = “[onclick] { cursor: pointer; }”; document.documentElement.appendChild(css); The first line of this code creates a new <style> block (in the SVG namespace) and assigns it to the ‘css’ variable. The second line just inserts a single CSS rule into the block: if any element has an ‘onclick’ attribute, the mouse cursor should be set to ‘pointer’ mode when it moves over the element. Finally, the third line inserts our new style block as a child of the <svg> element, after all the other content, where the browser will pick it up and automatically apply the rules.

There’s one last thing I’d like to do to really make this mock-up work effectively. You may have noticed that each page includes a ‘hamburger menu’ at the top-right. Let’s see if we can make that work, at least to some extent. One approach would be to create six pages instead of three: a second version of each page would simply duplicate the original, but with the addition of the open menu. If you were solely using the Interactive Mockup extension, then that is pretty much your only option. But we’re already up to our elbows in real JavaScript, so we have more subtle tools at our disposal. We’ve already discovered that we can have more than one layer visible at a time, and rely on transparency to ensure that all the right parts are displayed at once. This is, after all, what we did when we added the Main layer. So why not do the same with the menu? In this scenario each ‘page’ consists of the Main layer, the relevant page layer, and an optional menu layer that sits on top of them all. Let’s begin by designing the menu as a new layer at the top of the z-stack (shown above). Each of the first three entries in the menu carries the same onclick handler as the equivalent on the main layer (in fact I copied and pasted the objects from there). We’ll deal with the ‘Sign Out’ option later. Now the question is how to make the menu pop-up when we click on the hamburger button – but that’s really not so tricky. If we use the XML editor to give the ‘Menu’ layer an ID of ‘menu’, then you can probably guess what this function (shown bottom right) will do.

All we need to do now is to call the showMenu() function from the onclick handler of the hamburger menu that lives on the Main layer. We’re not calling the existing showLayer() function, so none of the existing layers is hidden. All that happens is that the Menu layer is displayed in addition to the others that were already visible – exactly what we wanted. As it stands, the mock-up is good enough for demo purposes, but perhaps a little clunky in parts. When the menu is ‘opened’, for example, there’s no way to ‘close’ it other than to navigate to one of the pages. One possible enhancement might be to add an almost-transparent rectangle to that layer, behind the main content. A suitable closeMenu() function, and an onclick handler added to the rectangle, would allow you to click outside the menu to close it. I’ll leave that one as an exercise for the reader. And what of that ‘Sign Out’ option? You could create another layer containing a mocked-up sign-out dialog, but do you really need to? Once you’re comfortable with showing and hiding things in JavaScript, it’s always tempting to go a little too far, and turn your ‘interactive mock-up’ into something approaching a full UI demonstration. Sometimes that might be appropriate, but often it’s better to do the bare minimum you can to help people to visualise how the final website or application might work. Too much detail or functionality can actually be a distraction, and can even inhibit further discussions or ideas. In this case, therefore, the ‘Sign Out’ option will simply get an onclick handler containing this: alert(“You are now signed out”);

With that addition our simple mock-up is complete. The key thing to take away is that the code for doing something like this probably isn’t as complex as you thought. While the Interactive Mockup extension can definitely be useful, you can easily get more functionality, and certainly a lot more flexibility, by just learning enough JavaScript to be able to target some elements in the page and selectively change their ‘style.display’ properties. If you do want to reproduce something like my mock-up, perhaps as a bit of practice to get a feel for the JS side of things, here’s the complete code we ended up with in the Document Properties dialog for your convenience (see above). In addition to that, each clickable element on the page has a single function call in the ‘onclick’ field of the ‘Interactivity’ section at the bottom of the Object > Object Properties dialog. In most cases, this was just a call to the showLayer() function, passing in the name of the page to display (e.g. showLayer(“contact”) ). In the case of the hamburger menu, it was a call to the showMenu() function. And our final addition was a call to the browser’s built-in alert() function for the ‘Sign Out’ option. When you take a step back and look at it, that’s really quite a lot of functionality in this interactive mock-up, for not a huge amount of code. But we’re done with this now – and with ‘Interactive Mockup’ being the last of the new extensions, we’re done with the features that were added to Inkscape 1.x. Next month, I’ll start what is sure to be a long series on the new features and additions in Inkscape 1.2.x.

issue187/inkscape.1669564816.txt.gz · Dernière modification : 2022/11/27 17:00 de d52fr