Troubleshooters.Com®, Code Corner, and SVG Clickmaps Present:

SVG Clickmap Landmines

Contents:

Introduction

This document was first written in 2017, and later updated in February 2021 in order to add and clarify information, and to identify some of the changes (mostly bad) in the ways modern browsers respond to SVG clickmap situations.

This document describes a bunch of landmines you could run into when making clickmaps with SVG and HTML. Some folks might call me a pessimist, a "Debbie Downer", or an ingrate griping about free software. I have no comment about such accusations.

What I will comment on is that when making SVG/HTML clickmaps, there are tens of mistakes that could each take an hour or more to troubleshoot. Documentation on SVG/HTML clickable maps is sparse, usually incomplete, and often contradictory. The best way to save time when learning SVG/HTML clickmapping is to learn the landmines before learning the technology.

Learning to creat clickable maps with SVG graphics is different from most skills. To learn most skills, you learn a little, master it, learn a little more, master it, and so on. Trying this with SVG clickable images takes at least an order of magnitude longer than starting with a map of the landmines. Prepared with a landmine map, when you hit a landmine, you'll simply invoke the solution or workaround, instead of drawn out troubleshooting that begins to look like trial and error, and web searches yielding solutions to problems you don't have.

For these reasons, don't start building your SVG clickmap until you've read this whole document.

Use a Debugger

Javascript brings web pages alive, but when used in a web page viewed on a regular browser, Javascript mistakes fail silently. This isn't so bad if it stopped working after a very small and contained change, but if it fails after typing in 20 lines of Javascript, get ready for hours of trial and error debugging.

Unless you use a debugger.

If you use a debugger, Javascript's about as easy as any other procedural language with OOP tacked on. If you have no debugger, view the page in Chromium and open the Javascript Console. Click the triple-colon thing, then "More tools" and then "Developer Tools". Observe the headings of the thing that just appeared on the right of the screen. If one of them is "Console", you're all set. Otherwise, click the double right angle bracket in the headers, and when the dropdown appears, choose "Console".

If the preceding sounds like a hassle, that's OK: You haven't seen true hassle till you try to debug web-based Javascript without a debugger.

Use alert() commands

alert() commands are a crutch, and like crutches you get from the doctor, you use them only when you're grossly injured, and as soon as you're better, you change them out for something less limiting. In the world of medicine, it might be one of those kneel-scooters. In the world of Javascript, it might be a diagnostic message paragraph or something in your debugger.

The alert() gives you two pieces of information:

  1. Did javascript execution get to this point?
  2. What was the value of a variable when it did?

What I do is start with an alert("dia4"), meaning the fourth diagnostic string. This tells me nothing except whether execution got to this point. If it didn't, that's either because it's in an if() statement that never got executed, or because the program bombed before getting to your alert() function. If execution doesn't get that far, I move my alert() function around till it does execute, and keep moving around till I find where it bombed (if for some reason the debugger didn't already tell me this).

Once I get the alert() function producing results, I might use it to show off an object or an object's property. For instance, alert(e.target.style.fill).

alert() functions are trustworthy: If execution reaches them, they will display information and wait for a click, regardless of situation. This makes them priceless when things get insanely confusing. But their value is limited, because alert() functions are an inefficient way to debug. They stop execution and make you keep clicking. You can lose track. Like a crutch, use them only when necessary, and only as long as absolutely needed.

Make a message paragraph

Always put something like the following in your web page:

<p id="msg">init</p>

The preceding paragraph is your window into your Javascript or DOM. All you need to do is have your Javascript write to it as follows:

  msgelm = document.getElementById("msg");
  msgelm.innerHTML = myvariable;

You can even put the preceding Javascript inside a button, so clicking the button updates the message paragraph.

Obviously, you can have more than one message paragraph. Perhaps they could have ids msg1 through msg4. Nor do they need to be called "msg": That's just a human readable convenience. You could have a message paragraph whose ID is "myaunthilda".

Be Careful of IDs

Would you like a problem that really has you talking to yourself? Code that should have worked as written, but mysteriously doesn't? No problem, just have two elements with the same id value. You can wander around such a house of mirrors for hours, wondering what's going wrong.

Always be vigilant to not re-use an id value. It's easier than you think. Imagine the following situation in the HTML file:

function showcontents(elm_id) {
   msg=document.getElementById(elm_id).innerHTML;	
}

And later in the HTML file the following button:

<button id="restore" onclick="showcontents('restore')>Restore</button>

And still later in the HTML file you define the <div> holding the restoration message content:

<div id="restore">
<p>Click one of the buttons above<p>
<div>

You're dead meat. Both the <button> and the message <div> have the same id. Depending on which order these elelements appear in the HTML file, things will screw up in a different way. Always ask yourself whether you've used an id before, and remember, ids are ids, regardless of the type of element they identify.

Another obvious tip: Make sure any ids you use in function calls actually exist and point to what you think they point to.

Snug up image to 0,0

I think the most common method of making SVGs is with Inkscape: An extremely powerful and standardized artistic human interface to make SVG graphics. As of May 4, 2017, Inkscape is at version 0.92.1, and has the 0,0 origin set at the bottom left of the page, with the Y axis increasing as you go up. This is the opposite of the SVG specification's Y axis, which shows Y increasing as you go down. According to the Inkscape Roadmap at http://wiki.inkscape.org/wiki/index.php/Roadmap, Inscape version 0.93 will change the Y axis to conform to the SVG standard.

Either way, you need to snug your drawing up to the 0,0 axis intersection. With versions before 0.93, you do this by making sure the bottom most part of your drawing is at the bottom of the page (y==0), and the leftmost part of your drawing is at the left (x==0). With versions 0.93 and after, make sure the top of your drawing snugs up to the top of the page (y==0).

You need to do this snugging up before you alter the image size to match the actual size of what you've drawn. Failure to do so can cause parts of the image to not appear within the HTML, or for clicks to "miss" their target within the SVG.

After you've snugged your drawing properly, select everything, File->Document_properties, click the Resize_page_to_drawing_or_selection button. The height and width values on the dialog box decrease, and the page in the drawing shrinks to just accommodate the drawing elements. Now, to give yourself a tiny border and guarantee that nothing gets cut off, add six pixels to the height and width, and after that select and move the drawing elements slightly away from the page borders, then save.

The preceding procedure gives you an excellent clipmap. Doing it otherwise sends you down the highway of heartache.

<img> doesn't work for clickmapping

You can't just insert the SVG as an <img> tag tree and expect it to work for clickmapping. There are several ways of incorporating the SVG: Most of them fairly complex and argued about on the Internet. This document describes only one method: A couple scripts to place the SVG file's <svg> code within the HTML document by use of a template file with a token.

First, place the following two Awk scripts, called insertsvg.awk and justsvg.awk, respectively, into a directory on the executable path and permissioned executable:

#!/usr/bin/gawk -We

{printthisline = 1}
/<div\s\s*class="token"\s*>\s*[^<]*\s*<\/div>/{
	printthisline = 0
	svgfile = \
	  gensub(/\s*<div\s\s*class="token"\s*>\s*([^<]*)\s*<\/div>\s*/, \
	  "\\1", "1")
	system("justsvg.awk " svgfile)
}
printthisline == 1 {print}

The preceding code is insertsvg.awk, the following code is called justsvg.awk.

#!/usr/bin/gawk -We

BEGIN {insvg = 0}

/\s*<svg/ { insvg = 1 }

insvg == 1 { print }

/\s*<\/svg\s*>/ { insvg = 0; exit 0 }

Now, make your HTML file a template file, with the space for the SVG reserved by the following:

<pre class="token">myfile.svg</pre>

The preceding token means that everything between and including the <svg> and the </svg> from file myfile.svg is substituted for the token line. Be sure that token line is on its own line, and just to be sure, put a blank line before and after it.

Finally, assuming your template HTML file is called myfile_template.html and the final result should be in a file called myfile.html, execute the following command:

includesvg.awk  myfile_template.html   >  myfile.html

After the preceding command, which can be put in a shellscript with a very short name so as to be run over and over again, myfile.html has the SVG directly included, which means all Javascript will work with minimal namespace problems.

If you need to change the SVG, just change the template in Inkscape, rerun the command, refresh the browser, and boom, you're working with the changed file. It's almost as fast as having it included by reference, which is more complicated to do.

Quicker debugging

Earlier it was recommended that editing be done in a template file, named myfile_template.html containing the following as a place holder for the SVG code:

<p class="token">myfile.svg</p>

The place holder in template file myfile_template.html is replaced by the SVG code, to form file myfile.html, via the following command:

includesvg.awk  myfile_template.html  >  myfile.html

The idea is that you can keep editing your SVG file in Inkscape, and then run the preceding command to form a new myfile.html based on the updated SVG file. This is a must, because materially changing an SVG image via a text editor is a horrible task. But...

When it comes to debugging events, it's probably easier to work with the finished file, myfile.html, rather than keeping on changing the event Javascript within Inkscape and re-compiling myfile_template.html. Later, when the Javascript problem has been solved, you can apply the fix to the SVG file, either in Inkscape or in a text editor. It's just faster to do Javascript debugging within myfile.html.

Include build documentation in the HTML file

Time passes. People forget. People change jobs and new people replace them. The AWK on Template method introduced in this section is the most universal way to make SVG clickmaps, but it's complex and error prone. Documentation is a must, and I think the documentation is best within the HTML file. The documentation can be in comment form, or in a <div>, or whatever. The documentation can refer to a more complete document outside the HTML file. But do yourself and your organization a favor, have obvious documentation to this AWK on Template method so it can be changed, repaired or reproduced.

Shrinking amount of SVG code

The AWK on Template method introduced in this section copies everything in the SVG file from the <svg> tag to the <.svg> tag. This includes a lot of unnecessary metadata and other irrelevancies. It's conceivable that you could substitute a much more complex program in place of justsvg.awk in order to deliver only the necessary portions of the SVG, thus delivering a much less bulked up HTML file. This could be a noble goal, and very possibly essential in a high volume, professional, situation, and it's doable, but it's beyond the scope of this document to discuss.

Color testing an object is browser dependent and fraught with error

Why doesn't the following turn circle mycircle green?

mycircle.style.fill = "#ff0000";
if (mycircle.style.fill == "#ff0000"){
    mycircle.style.fill == "00ff00";
}

The first line sets the circle's fill color to red (#ff0000). The second line tests to see if the circle's fill is still "#ff0000", and if it is (why shouldn't it be?), the third line sets it to green (#00ff00). It never gets set to green, and in fact if you place an alert() right above the line that sets it to green, that alert doesn't happen.

Note:

Actually, if you're using the Surf browser from Suckless Tools, it does turn green. But with Firefox, Chromium, Qupzilla, Palemoon and Midori it doesn't.

So now do this: Right between the set to red and the check for red, insert the following line:

alert(mycircle.style.fill)

The result, for most browsers, is the following:

rgb(255, 0, 0)

The preceding is a string, folks. It's "rgb(255, 0, 0)", not "rgb(255,0,0)" or rgb(255, 0, 0) or "#ff0000" (unless you're using the Surf Browser). Before I learned this, I spent 3 hours trying to get color testing to work, with a looming presentation on clickmaps, and didn't figure it out until after the presentation.

Color testing is ugly and browser dependent: There are more reliable methods to do what you need to do. But if you ever need to do color testing, the following is the best way:

<script language="javascript" type="text/javascript">
myred = "rgb(255, 0, 0)";
mygreen = "rgb(0, 255, 0)";

function initcolor() {
mycircle.style.fill = myred;	
}

function togglecolor(){
if (mycircle.style.fill != mygreen) {
  mycircle.style.fill = mygreen;
}else {
  mycircle.style.fill = myred;
}

</script>

Crude, but effective on some browsers. The following is one way to do it without color testing, by keeping a parallel flag of the color:

<script language="javascript" type="text/javascript">
isred = 0;

function initcolor() {
mycircle.style.fill = myred;	
isred = 1;
}

function togglecolor(){
if (isred != 1) {
  mycircle.style.fill = "#ff0000";
  isred = 1;
}else {
  mycircle.style.fill = "#00ff00";
  isred = 0;
}

</script>

The preceding works on any browser with a half descent respect for Javascript. Note that many times, you'll have many same-typed objects whose colors (or more likely whose state) need to be tracked, so you'll probably substitute something like one or more array in place of isred.

Use the Inkscape property Set button

Be very careful while working on the Object Properties dialog box. Some of its fields are persistent the minute you type information into them, while others aren't persistent until you click on the set button to the right of the hide and lock checkboxes. Two I know for a fact aren't persistent are the ID and the Label, so if you're changing these, be sure to use the set button after every change.

One Layer and No Groups Please!

Inkscape has multilayer capability, but SVG doesn't, at least as of 2/26/2021. Inkscape implements layers using multiple object groups, which introduces all sorts of potential troubles when creating clickable SVG files.

As a matter of fact, when creating a clickable SVG, try hard not to use object groups at all. Doing so invites all sorts of translation problems, as discussed in the Snug up image to 0,0 section. If your drawing is so complicated that you feel the need to use object groups, I suggest you either create several simpler drawings to be presented as a matrix, or construct your grouped objects as beziers instead.

Every Inkscape-authored drawing contains an automatic object group. That's fine. Just don't deliberately make more. Don't use "object->group" in the Inkscape menu.

User Interface Considerations

Hover is soooo cool. You mouse hover part of your SVG, and the contents of a nearby <div> change accordingly. Wikipedia's use of hover is second to none. When they hover a link, it gives a little information on that link so you can decide whether to click it. When your mouse leaves the link, the information goes away. The way Wikipedia uses hover is a thing of beauty. But Wikipedia's takes advantage of some of Wikipedia's advantages:

If you're using a <div> to contain the "popped up" text, hover presents some problems:

So what I suggest is this: Use only onmouseout events, and next to the graphic have a "Restore" button so that if the person wants to deliberately restore the text, he or she can do so.

But what if the user forgets which element they clicked? No problem: The title of every message should identify, in words, the element that was clicked.

There's one possible use for hovering in these situations: You can make less transparent the hovered element, which is probably a transparent rectangle above the element the user thinks they're hovering or clicking. This isn't really necessary, but in certain circumstances it can make more clear which places are clickable.

The SVG/HTML Javascript Interface

This section is a vast landmine field. Read it again and again and again. This section even has its own table of contents. Keep this section open whenever you're interfacing SVG object events to an HTML file's Javascript functions. The more mistakes you head off by continually paying attention to this section, the less you'll need to debug, and the faster you'll work.

CHAPTER CONTENTS:

Setting events via object properties

The best way to put events on objects is to use the object properties dialog box, but that dialog box isn't easy to to find. Here's how you find it:

  1. Click the object to select it
  2. Click "Object" on the menu bar
  3. Click "Object properties" on the resulting dropdown menu
  4. Click the "Interactivity" expansion label
  5. Below that label you'll now see several fill-in fields, including:
    1. onclick
    2. onmouseover
    3. onmouseout
    4. onmousedown
    5. onmouseup
    6. onmousemove
    7. onfocusin
    8. onfocusout
    9. onload

The next subsection tells you exactly how to fill in those events...

The top and evt words

LANDMINE!

The "onmouseover", "onmouseout" and perhaps some other events don't fire when you're using the Chromium browser's debugger. So until everything's all debugged, use the "onclick" event, which does work in the Chromium debugger.

When you set events in the "Interactive" part of the object properties dialog box, your click, mouseover and mouseout events should be as follows, respectively, assuming you're calling the HTML file's Javascript functions myfcn_onclick(), myfcn_onmouseover(), myfcn_onmouseout() respectively:

LANDMINE!

If you use strings for arguments in any of your event function calls, surround them with single quotes, not doublequotes. Inkscape automatically wraps the entire call, from top. to the final paren, in doublequotes. Therefore, if you wrap any arguments in doublequotes, Inkscape changes the doublequotes to &quot;, which might not play nicely with all browsers. Therefore, be sure to wrap any string arguments in singlequotes, which pass right through as singlequotes.


LANDMINE!

Remember, the "onmouseover", "onmouseout" and perhaps some other events don't fire when you're using the Chromium browser's debugger. Use only "onclick" for debugging.

Notice the top. prepended to each? That's what causes the javascript in your html to be run. Without those, the javascript in your SVG file itself would be run. As a matter of fact, sometimes it's beneficial to put some or all of the javascript inside the SVG, and if so, then you'd not use the word top.

Next, notice the argument evt. It must be evt. Not e. Not myevent. It has to be evt. Perhaps there's a variable named evtin scope at that point. Whatever, I'll let smarter people explain it: Just be aware that you need to use evt to represent the event argument.

Note:

Some experiments I've tried indicate you can also use the word event instead of evt. I don' t know the difference between using those two, but absent a reason to do otherwise, I'd use evt. That seems to be the way most examples in the web do it.

Target functions for SVG interaction are different

The following is how an onclick event in an SVG element calls a Javascrpt function in the HTML file:

onclick="top.load_message_from_svg(evt, 'enp40s0')"

In the preceding, the HTML file's Javascript function load_message_from_svg is called with arguments evt, and please remember it must be called "evt", which is the click event, as well as 'enp40s0', which is a string. The function takes the string, finds an element with an id matching the string, and displays the contents of that element.

The call from the SVG file requires a compatible function declaration. That declaration follows:

function load_message_from_svg(the_event, the_string) {
/* statements*/
}

In the preceding function declaration, notice that "the_event" could be name, as long as it corresponds to what was inside the function's function implementation. This is different from the function call, where "evt" was the name of an existing variable within the SVG and so needed to be named "evt". Easy peezy.

But let me ask you this: What if, besides being called from the SVG, load_message_from_svg() needed to be called from within the HTML file? There's no evt variable within the HTML scope.

It turns out to be pretty simple if load_message_from_svg() doesn't use evt internally. When you call it from within an HTML element, you do it as follows:

<button class="side" id="normalz" 
onclick="load_message_from_svg('junk', 'enp40s0')">Normal</button>

The preceding simply substitutes a throwaway argument for evt, which the load_message_from_svg() function doesn't use anyway. This is typical, because the main info contained by evt are the type of event (mousee, keyboard, whatever), the coordinates, both relative to the element and the whole drawing, and whether it's trusted. If you're like me, you don't use info like that, you just know that a SVG element requested load_message_from_svg(). If load_message_from_svg() needs to know which SVG element, or other odd info, that odd info can be passed in as an additional argument.

But most of the time, when calling from the HTMLs javascript a javascript function, in the HTML file, that's meant to service calls from an SVG element, the easiest way to do it is just call it with a throwaway first argument.

Complete an object before duplicating

It takes between 30 seconds and 2 minutes of complicated, error prone mouse operations to add a class="whatever" to an object. Adding mouseover, mouseout and mouseclick events is another 30 seconds. To the best of your ability, the time to do these things is when there's only one of these objects: Not after you've duplicated 50 copies of the original. Anything that gets clicked, or anything that changes color or size during use, needs events. Adding class="whatever" to an object future-proofs it, enabling future invocations to use document.getElementsByClassName() instead of document.getElementsByTagName(), whose results are inconclusive if a group contains several objects with the same tag name (circle or ellipse or path, for instance).

It takes next to no time to put this kind of information, most of which doesn't change when you duplicate the object, on one object, and then duplicate it to your heart's content. But going back later and putting it into 100 objects is boring, error prone, and time consuming.

Object classes aren't Object Oriented Programming

Just in case you've been around Object Oriented Programming (OOP) more than you've been around HTML or Document Object Model (DOM), please take a minute to contemplate the fact that classes in HTML and SVG, you know, the code that looks like class="whatever", are not at all the same thing as OOP classes. OOP classes are an architectural specification for objects to be create within a programming language. Classes in HTML and SVG are names given to (usually) several elements that generally serve the same conceptual function. HTML/SVG classes are translated into appearance via CSS (Cascading Style Sheets).

Object classes make later improvements easier

One of my projects involves a SVG drawing with 116 screw heads. Each screw head is a group containing the round screw head outline, a crossed notch path to accommodate a Philips screwdriver, and an ellipse used to portray a highlight reflection. Desired behavior is to click any part of the screw head group and have the fill of its round screw head outline changing color, leaving the highlight and the cross notch as they were.

Right now that's a pretty easy job, because the screw head outline is the only circle in the group, so once I have the group element, I can just do the following:

bulbgroup.getElementsByTagName("circle")[0].style.fill = "#ff0000";

No sweat. But suppose a few months from now each screw head needs to include a logo consisting partially of a circle. Now, because there are multiple circles, you can't know which is which, without a lot of logic. However, if I had previously assigned the class name "outline" to the screw head outline (and no other elements within the screw head), I can use the following code:

bulbgroup.getElementsByClassName("outline")[0].style.fill = "#ff0000";

With class names, you can identify whole groups by what they do: Not by what type of element they happen to be. Any time you think any element, whether a group or not, might either receive clicks and hovers, or need to change its appearance, give it a class name. And for sure, if there are multiple copies of such an item, class names become absolutely vital.

Object's class setable only from the xml editor in Inkscape

Ugh! The only practical way to set up class names is in Inkscape, and in Inkscape, the only way you can set an object's class name is to invoke the XML editor. We're talking Edit->XML_editor. And on my computer, Inkscape's Ctrl+Shift+x hotkey doesn't work because it's reserved by the window manager for other things. Unless you're very familiar with it, the XML editor is a very non-intuitive and confusing interface: Another one with that infamous set button.

When you run the XML editor, it docks, which is the last thing you want. Skimping on screen real estate with an interface that does so much is silly. So your first task is to pull it off the dock and use it as a window. Just click and hold in the docked XML editor's gray "titlebar" and drag left, out of the dock area. Now make it big enough to work with. You can move the XML editor to see and click the drawing, as needed. Click different elements on the drawing, and they'll be highlighted in the XML editor.

The following steps add a class name to a given element within Inkscape's XML editor:

  1. In the left hand pane, select the element to receive the class name.
  2. Notice that the right pane has a list of attributes and values on top, and on the bottom has a single line edit with a set button to its right, and below those is a multiline edit.
  3. Type the word class into the single line edit.
  4. Type the desired class name into the multiline edit. For instance, if you want its classname to be "lightbulb", type lightbulb into the multiline edit.
  5. Now click the set button! Yes, I'm shouting: Failure to click the set button fails to set the class. Be sure that the new class with its value now shows up in the upper part of the pane.

Weird Genius Alert:

The XML editor interface at first seems as weird as a psychedelic science fiction movie. The attribute name and value stay where they are, even as you highlight different elements in the left pane. And they only take effect if you click the set button. Alice fell down the rabbit hole, and Dorothy's not in Kansas anymore.

And yet, this interface is a perfect way to assign the same attribute name and value to a bunch of different elements. Fill them out once, navigate the left pane, and on any element you want to add the new attribute, just click the set button. If you ever find yourself needing to add class="outline" to every larger circle in every screw head group, this behavior of the XML editor is probably the least painful way to do so.

I recommend you leave the XML editor undocked forever. It has so much stuff going on that it's useless when docked. But if you ever find yourself wanting it docked, just grab the gray titlebar below the window manager titlebar, and drag it to the dock area. Note that even in there, you can drag it around to be to the right, left, top or bottom of what's already there.

Group clicking gotchas

If you want good looking clickmaps, often you'll need to have your clickable objects be groups. And when you're clicking groups, Alice falls down the rabbit hole, gets sucked into a black hole, which sends her through a wormhole, which spits her out in Kansas, to replace Dorothy, who has taken a job with a flying monkey rock band. Yeah.

Let me start with this piece of advice: You'll probably never want to put events on the group itself. Doing so leads to a life that's just a little too exciting. In most cases, the best solution is to create a circle, ellipse, rectangle or path that's the same size and shape as the whole group, make it zero opacity, and put it on top of everything else in the group before actually grouping them. Put all your events on that zero opacity cover, and only that zero opacity cover. Unless for some reason you want different things to happen when you click on different parts of a group, the zero opacity cover is the best, simplest, and most predictable.

Now for a little theory: When an SVG has several objects stacked on top of each other, the last to be stacked is the one that is visible, and the one that gets clicked. Take the following, for instance:

Flag image

The preceding image consists of a paragraph that says "init" and a group, looking like a simple flag, formed from a blue rectangle in back of all else, a red circle above that, and a zero opacity (full transparency) rectangle above that. See the relevant XML at flag_grp_xml.txt.

Because it's above the other elements in the group, the rectangle with id "cover1" receives all clicks anywhere on the flag. Because it has an opacity of 0, you can see the circle and rectangle below it. If the "cover1" rectangle were completely opaque, you wouldn't see the circle or the blue rectangle, only the "cover1" object. But because it's transparent (0 opacity), you get the best of both worlds: All clicks and hovers name it as the target, but you see only what's below it.

The following is the same graphic, but incorporated in such a way that on some browsers, like Firefox, Chromium, Palemoon and Qupzilla, hovering and clicking it actually perform actions.

NOTE:

As of 2/27/2021, Firefox no longer shows images with the <embed> tag. Nor do Eolie, Epiphany, Midori, Otter Browser, Netsurf, Vimb (gripes about missing plugin), or Dillo. Chromium and Falkon shows these images and interacts perfectly when hovered and clicked. Unbelieveably, so does lightweight QuteBrowser.

Given the lack of progress since this page was originally written in 2017, the most universally usable way to include clickable/hoverable images in an HTML page remains the AWK workaround in section <img> doesn't work for clickmapping. That's unfortunate.

Depending on your browser, the following might be invisible. But if you can see it, try it:

In the preceding image, if you were able to see it, as mentioned, I used a transparent cover with events onmouseover, onmouseout and onclick attached to it. Here are some other designs I could have used, and why I didn't:

The following is a clickable rocker switch, which, depending on your browser, you may or may not be able to see:

Notice in the preceding graphic, assuming it was visible to you, hovering over either side of the switch slightly lightens it. Clicking anywhere on the 0 side turns the switch's edge blue, while clicking the 1 side turns it black.

You might want to download this graphic to take it apart and see how it's built. Right click the following copy, which is included with a <img> instead of <object> to download:

Rocker switch graphic, right click to download

The Inkscape Javascript function shuffle

You want to install Javascript functions into your Inkscape file , so you go to the Embedded Script Files subtab of the Scripting tab of the Document Properties dialog. You click the plus sign, a script ID appears in the Script ID list, so you say "good, now I'll type in all the functions into the Content field."

Bzzzt, you've just lost time, and without just the right moves it will be all the time you spent typing into that little, unenlargeable Content field. You had forgotten to highlight the script ID, and the second you do, all the functions you typed into the Content field vanish. Or, if you save and go on to other things, you lose all your functions.

ALWAYS make sure you highlight the script ID BEFORE typing into the Content field.

Better yet, type your functions in an editor, where you have all the room you need and all your familiar editing facilities. Then, click the plus sign, highlight the new script ID, and then copy your functions from your editor and paste them into the little Content field.

If you ever notice that you've typed functions into the content field without highlighting the script ID, copy all your work out of the content field, paste it into an editor, highlight the script ID, and then copy from the editor and paste back into the content field.

Internal SVG Javascript gotchas

If you want, you can do all your Javascript within the SVG file. Here are items to remember:

Animated SVG Javascript landmines

Things like changing colors, toggling visibility, and performing calculations on click or hover are actually pretty easy, once you get the hang of them. But when you get into things like moving elements, making calculations based on element position, connecting elements, and creating new elements, you're at a whole new level of difficulty and bad documentation. For this reason, animated SVG Javascript landmines have their own web page.


[ Training | Troubleshooters.Com | Email Steve Litt ]