Langbahn Team – Weltmeisterschaft

User:Cmglee/Dynamic SVG for Wikimedia projects

Interactive map of Wikimania 2016 venues using SMIL and CSS

This article describes an initiative by user:cmglee to explore techniques to employ dynamic Scalable Vector Graphics to enhance content on Wikimedia projects.

Rationale

SVG feature compatibility in most common Web browsers in descending popularity from left to right, and version from top to bottom, as listed on caniuse.com as of 16 Jan 2016

S = SMIL not supported
C = CSS animation not supported
Chrome Chrome for Android Internet Explorer Firefox IOS Safari Opera Mini Android Browser
 8 S C 4.3
45  9 S C 4.4
46 10 S 42 8.4 4.4.4
47 47 11 S 43 9.2 S C 46
48 44 9.3
49 45
50 46

Though Wikimedia projects such as Wikipedia, Wikibooks and Wikiversity are excellent in describing concepts textually and graphically, some are better explained interactively, such as when comparing members of a set or showing components of a system. We have been traditionally limited to video clips and GIF animations but now that Scalable Vector Graphics (SVG) is becoming well-supported in web browsers (see table),[1][2][3] the author believes that these Wikimedia projects stand to gain by exploring ways to enhance articles with dynamic SVG.

JavaScript or ECMAScript allow almost limitless interactivity, but uploads with it are barred, understandably for security reasons — on popular sites like Wikipedia, cross-site scripting issues are a concern. Fortunately, SVG provides two other techniques for interactivity and animation, each of which has its pros and cons:

  1. Synchronized Multimedia Integration Language (SMIL), and
  2. Cascading Style Sheets (CSS).

The author has explored applications, techniques and best practice for the last two years and contributed over 300 SVGs, some with animated and interactive, and aim to create demonstrations and tutorials to allow users to create their own dynamic content.

The following are some areas identified. As the author is learning as he goes along, some of his images, especially earlier work, violate his own guidelines, so the developer is requested to exercise caution when studying the examples provided.

Animation

SVG animations show how a system changes with time and are an alternative to video clips. Advantages are

  1. Has much smaller file size,
  2. Can be enlarged without getting blocky, and
  3. Potentially allows interaction besides pause and seek.

Non-interactive animation

The simplest type of animation starts running automatically and optionally repeats. Examples:

One-off animation using SMIL
Endless animation using CSS demonstrating pseudo-3D rotation
Endless SMIL animation demonstrating change in transformation and CSS attributes
Endless SMIL demonstrating motion along a path and simulation of 3D

As the author wrote in the SVG animation article, the following code snippets demonstrate two techniques to create animated SVG on compatible browsers. The relevant parts are in bold green.

SVG animation using SMIL

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
 width="100%" height="100%" viewBox="-4 -4 8 8">
 <title>SVG animation using SMIL</title>
 <circle cx="0" cy="1" r="2" stroke="red" fill="none">
  <animateTransform
   attributeName="transform"
   attributeType="XML"
   type="rotate"
   from="0"
   to="360"
   begin="0s"
   dur="1s"
   repeatCount="indefinite"/>
 </circle>
</svg>

SVG animation using CSS

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
 width="100%" height="100%" viewBox="-4 -4 8 8">
 <title>SVG animation using CSS</title>
 <style type="text/css">
  @keyframes         rot_kf { from { transform:         rotate(0deg);   }
                              to   { transform:         rotate(360deg); } }
  @-moz-keyframes    rot_kf { from { -moz-transform:    rotate(0deg);   }
                              to   { -moz-transform:    rotate(360deg); } }
  @-webkit-keyframes rot_kf { from { -webkit-transform: rotate(0deg);   }
                              to   { -webkit-transform: rotate(360deg); } }
  .rot { animation:         rot_kf 1s linear infinite;
         -moz-animation:    rot_kf 1s linear infinite;
         -webkit-animation: rot_kf 1s linear infinite; }
 </style>
 <circle class="rot" cx="0" cy="1" r="2" stroke="blue" fill="none"/>
</svg>

Note: the -moz and -webkit styles are pre-CSS3 browser-specific styles.

Interactive animation

Interactivity can be easily combined with animation. The Interactivity section describes interactivity in more detail. Example:

CSS animation highlighting features of interest on hover and linking to Wikipedia on click

Interactivity

The real power of dynamic SVG comes from interactivity. At its simplest, tooltips can display supplementary information, or with cunning trickery, one can write a simple applet, such as these examples:

The 21 game with AI using SMIL
A simple action game implemented in SMIL

Tooltips

Neither CSS nor SMIL is needed — four methods have been identified:

  1. Title tag — the recommended method, supported on all Chrome, Firefox and Internet Explorer: add an attribute <title>TOOLTIP TEXT</title> inside an element, such as <use xlink:href="#object"><title>TOOLTIP TEXT</title></use> to show "TOOLTIP TEXT" in a tooltip when the user hovers over the element. Newlines can be inserted using \n but Internet Explorer shows them as spaces.
  2. Anchor link, supported on all Chrome, Firefox and Internet Explorer: enclose the element in a hyperlink (described in the section below) to an non-existent anchor in the same document e.g. <a xlink:href="#MESSAGE"> … </a> — highest compatibility though the text is not displayed adjacent to the element, and includes the URL of the SVG.
  3. Embedded custom cursor, supported on Chrome and Firefox: Base64-encode a 32×32 image and include it in the cursor attribute of the element, e.g. cursor="url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAADFBMVEUAAABVVVWqqqr////Bf2LRAAAAUUlEQVR42t2TMQ4AIAgDLfz/zw4OTSRCqkze2htKgNELfIE8phJzgjSnEQUbyAXQ3DBVcPwocPxCILWgrZM9wQ4HBOFx3XZzctJZQ3ucOGEnEyz6BGX+V2aMAAAAAElFTkSuQmCC),auto" — tedious to generate and not easily changed though allows an image to be displayed.
  4. CSS hover selector: add a transparent SVG element as a child of the element and a CSS :hover selector in its style to make it visible. pointer-events:none; prevents the invisible tooltip itself triggering the hover effect. The element can be any SVG element — not necessarily text. A drawback is that CSS is needed, but all Chrome, Firefox and Internet Explorer support it. Example stylesheet:
 <style type="text/css">
  .parentclass       .tooltip { opacity:0; pointer-events:none; }
  .parentclass:hover .tooltip { opacity:1; }
 </style>

Examples:

Using multiline titles with Chinese characters and highlighting on hover
Using titles and anchor links to show digits' decimal place (position) on hover
Using custom cursors to show number of units on hover
Using CSS and titles on hover

Neither CSS nor SMIL is needed — enclose the element to be hyperlinked in <a xlink:href="URL" target="FRAME"> and </a> to link to "URL" on the frame or window named "FRAME". If target="FRAME" is omitted, the page loads over the SVG and the user has to click Back to return to it, and this resets any changes the user has made to the SVG. On Internet Explorer, the element enclosed cannot be in a block which is inserted using the use tag. Example:

Airline codes are hyperlinked to their Wikipedia articles
Hyperlinks to Wikipedia articles with progressive disclosure

Progressive disclosure

Some infographics are better absorbed in small bites!

Changing an element's appearance when the user moves the mouse pointer over it can be done in CSS, but responding to clicks (other than on hyperlinks) requires SMIL, which is not supported on Internet Explorer.

In the File:Comparison_of_pyramids.svg example above, the overlapping shapes can appear overwhelming. Highlighting just the pyramid hovered over lets the user see its shape much more clearly. File:CIE1931xy_ColorChecker_SMIL.svg below takes it a step further: SMIL allows an object to change state when clicked, so that the user can select any combination of objects to compare. The objects toggled need not be the objects clicked. The File:Milky_Way_multispectral_SMIL.svg example demonstrates mixing photographs taken at different wavelengths of light by clicking on thumbnails.

Complex graphs, too, can benefit from progressive disclosure. In File:Doubling_time_vs_half_life.svg below, individual graphs can be isolated to aid readability.

Hover over a colour swatch to highlight it; click it to select and deselect it (SMIL + CSS)
Click a thumbnail in the SVG to add/remove it from the mix (SMIL)
Hover over a graph to highlight it (CSS)
Click to expand and collapse parts (SMIL)

The following code combines CSS and SMIL for maximum compatibility and functionality, and demonstrates how two selectable objects can be created, the first initially unselected and the second preselected. The opacity values can be tweaked to taste.

 <style type="text/css">
  /* Styles for interactivity: */
  #main:hover   { stroke-opacity:0.1; fill-opacity:0.1; }
  .nofade       { stroke-opacity:1;   fill-opacity:1;   }
  .base         { cursor:default; cursor:-webkit-grab; cursor:grab; }
  .base:hover,
  .active:hover { stroke-opacity:0.9; fill-opacity:0.5; }
  .active       { stroke-opacity:0.8; fill-opacity:0.5; visibility:visible;
                  cursor:-webkit-grabbing; cursor:grabbing; }
 </style>
 <!-- Event-handlers to link clicks to the state of active parts: -->
 <set xlink:href="#object1a" attributeName="class" to="active" begin="object1b.click"    end="object1a.click"/>
 <set xlink:href="#object2a" attributeName="class" to="active" begin="object2b.click;0s" end="object2a.click"/>
 <!-- Element which triggers general fade when hovered over: -->
 <g id="main">
  <!-- Elements which do not fade when general fade is triggered -->
  <g class="nofade">
   ...
  </g>
  <!-- Selectable elements, each comprising a base part and an active part, and a tooltip: -->
   <g>
    <g id="object1b" class="base"><!-- Selectable element when unselected --></g>
    <g id="object1a" visibility="hidden"><!-- Selectable element when selected --></g>
    <title>Tooltip for object1</title>
    <a xlink:href="URL1"><!-- Element to load URL1 when clicked --></a>
   </g>
   <g>
    <g id="object2b" class="base"><!-- Selectable element when unselected --></g>
    <g id="object2a" visibility="hidden"><!-- Selectable element when selected --></g>
    <title>Tooltip for object2</title>
    <a xlink:href="URL2"><!-- Element to load URL2 when clicked --></a>
   </g>
 </g>
Sample SVG with annotated code

With reference to the code of the sample SVG on the right, the #main:hover style fades the image when elements in it are hovered over, providing greater contrast for selected elements. The nofade class is applied to elements which should not fade such as the background and user interface elements.

Each selectable object has up to four elements:

  1. A base part (suffixed "b") provides its unselected appearance and a trigger to click to select it
  2. An active part (suffixed "a") provides its selected appearance and a trigger to click to deselect it.
  3. An optional tooltip appears when the object is hovered over.
  4. An optional hyperlink loads a URL when clicked.

The base and active parts can be two instances of the same object (such as a triangle or bridge silhouette in the File:6-set_Venn_diagram_SMIL.svg or File:Comparison_of_notable_bridges_SMIL.svg examples), or separate objects (such as the glow and photograph mix in File:Milky_Way_multispectral_SMIL.svg). For the former, the object can be defined separately and instanced using use tags.

The active part is initially hidden by default and is revealed when the base part is clicked. Appending ;0s to an object's set tag selects it by default, as in the example code for object2a above. When the revealed active part is clicked, it hides itself. The cursor is also appropriately changed to reflect the object's state in Firefox and Chrome.

As Internet Explorer does not support SMIL, a CSS hover effect is added to highlight the base part when the user hovers over it.

Demonstration SVG using groups
Interactive map with groups of selectable objects
Interactive semi-log plot of historical population of the 50 states of USA and the District of Columbia from 1900 to 2015

It is possible to group selectable objects by category, as in this demo and interactive map; each group button highlights/selects all its members. The interactive map also shows how certain elements (such as the lines joining the map locations with its photo) can be made unresponsive to hover or click by adding pointer-events:none; to their styles to avoid flashing when the pointer briefly passes over them.

The SVG can be modified to deselect members on a second click, as in the above graph, but its use may be unintuitive: if the user clicks the group button to select the entire group then manually deselects each member, the group will still be selected, and clicking the button again appears to do nothing. It should decrement a counter and turn off the group button when every member has been deselected and vice versa, but the author does not know of a way to do this.

Interactive timelines

While animations are often enough to show changes in a system through time, it is sometimes useful to let the user move through it at his or her own pace, even in a non-linear fashion. The File:Evolution_of_the_European_Union_SMIL.svg example below lets the user highlight countries by year of accession or departure. The simpler File:BlueMarble_monthlies_SMIL.svg lets the user jump to specific frames of a sequence by hovering over the appropriate part of the graphic.

Hover over or click buttons on the timeline to shade and unshade countries (SMIL + CSS)
Hover over or click a year on the left to highlight its graph (SMIL + CSS)
Hover over the legend to step through time (CSS)
Hover over the timeline to step through time (SMIL)

Simple 3D viewer

At a Cambridge Wikimedia meetup, a participant suggested that photographs of 3-dimensional artifacts could be displayed as part of a GLAM initiative. There are certainly QuickTime VR and Adobe Flash-based viewers, but these tend to be proprietary. The author has created two prototypes below: one of a rendered globe and the other a museum piece, which lets the user virtually rotate an object but lacks support for zoom and drag.

A large composite of multiple frames tracks the mouse pointer (SMIL)
At the top and bottom rows, the respective pole's image is shown and rotated according to the pointer's position; elsewhere, a large composite of multiple frames tracks the mouse pointer (SMIL)
Each contour line is rotated corresponding to the pointer's position, then moved upwards and vertically scaled (SMIL)
Each frame is a separate image which initially has zero opacity; when its trigger is hovered over, the opacity is set to 1 (CSS only, so works in IE)

GIF animation to SVG converter

The author has written the Python script below which uses ImageMagick to download a GIF animation, extract its frames as PNGs and compile Base64-encoded versions into an SVG with a row of thumbnails at the bottom.

Moving left and right over the SVG image rotates the 3D model. As it uses CSS (no SMIL), it supports Internet Explorer. Below are some fields of study that can benefit:

Chemistry
Geography
Mathematics/crystallography
Astronomy
Anatomy/biology
Mechanical engineering/history
Aerospace engineering/technology
Structural engineering/physics

Some categories containing GIF animations that can be converted are

User:Shyamal suggested using it to navigate through a timeline. Additionally, it can be used to control the position of an object in the scene. As examples, I've converted the following:

History
Astrophysics
Physics/optics
Mechanical engineering/thermodynamics

Limitations

Backward compatibility

Thumbnails are often used to link to a media file, and so the SVG should be presentable when rendered as a thumbnail and on browsers which support SVG but not animations or interactivity. One method the author has used is to first create a static SVG, but leaving space or structuring the code for dynamic parts to be added later.

A link can be added to the thumbnail caption to inform the user that an interactive version is available, as in this example:

Comparison of the side elevations of some notable bridges at the same scale. (click for interactive version)

As CSS is more widely supported than SMIL, CSS methods are preferred, where possible. For example, in File:Comparison_of_notable_bridges_SMIL.svg above, CSS hover effects are used to highlight a bridge profile or label when the user moves the mouse-pointer over it. If his or her Web browser supports SMIL, the profile or label can also be clicked to keep it highlighted. This lets Internet Explorer users use the hover effect while letting Chrome users use both hover and click.

Touchscreen support

Most tablets and smartphones break the hover and click model as it is almost impossible (except by clicking and cancelling the "Open with" menu) to hover without also clicking. The File:Comparison_of_notable_bridges_SMIL.svg example above puts the link to the bridges' Wikipedia articles in an icon button. As both hover and click highlight a bridge, the touchscreen user can operate the user interface without handicap.

Editor support

As the author handcrafts his SVG files (or write Python or Perl programs to generate them), they are currently not editable on editors such as Inkscape. The author will endeavour to provide support for at least Inkscape if this project takes off.

See also

References