Creating optimized and reusable SVG applications

The SVG format is well known as a format for icons and static designs. It is less so as an application format for the WEB.
However, it includes all the features needed for creating graphics-focused applications such as CSS styles and JavaScript code with an important additional feature which is its reusability between various websites.

The components of the drawsvg editor are mainly made according to this practice, such as its gradient editor.

In this article we explain the principles of this practice to you with two examples.

Conditions for reusability of an SVG application

To be simply reusable, the application must:
  • Be full autonomous, that is to say not have dependencies with files other than its SVG document
    and therefore embed its CSS styles and its javascript code
  • The content of the SVG document (JS code, CSS class and element IDs) must not conflict with the code of the inserting website
    For this, the deployment mode on client WEB sites via an embed tag is preferred.
    Otherwise, for direct insertion of the SVG document into the client site's HTML, the document must have a specific namespace for its javascript code, CSS classes, and element IDs. This mode is therefore too restrictive for an industrial deployment of the application.
  • The dimensions of the SVG document (width, height) must be set to 100% to cover the application insertion area in the client site.
  • Be compatible with desktop and touch devices
    for user interactions to manage both mouse and touch events

JavaScript code of an application

For a well-structured and scalable application, it is advisable to place the javascript source code in a js file:
  • The code is structured in the form of a JavaScript object with its methods, like the following snippet of clock app code:
    // app clock code
    let clock = {};
    /**
    * Initialize app clock
    * @param {Event} evt onload event
    */

    clock.init = function(evt) {..}
    ..
    // export event handlers
    window['clock_init']=clock.init;
  • The code must include an application initialization method to handle the load event
    The event processing methods are necessarily exported in the window context to be called from the SVG document :
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="100%" width="100%" 
    onload="clock_init(evt)" preserveAspectRatio="xMidYMid meet" viewBox="0 0 140 140" >
  • To control and optimize the code, it is advisable to use a tool such as the Google closure compiler with its source code annotations to type the variables
    During the build phase of the application in its final deployed form, the code is optimized and inserted into the SVG document

Optimizing the SVG document

In good practice, the SVG document is also deployed in an optimized form.
Here are recommended principles :
  • Limit the number of decimal places of coordinates (x,y)
    Choose a coordinate system (viewBox) of the svg document extended x10, for example (0,0,140,140) instead of (0,0,14,14)
  • Favor path elements instead of line and polyline elements
    Use relative path commands (l, h, v, a, c, s, q, t)
  • Always set the vector-effect style property to non-scaling-stroke to maintain a constant stroke thickness regardless of the application's display size
  • Factor style properties with CSS classes
  • Removal of unnecessary characters, spaces and newlines between elements, by an XML task when constructing the document in its deployed form

Animated clock app

This application represents a traditional clock with its hour, minute and second hands:

  • It displays the current time and date with AM/PM indicator
  • Rotates the hands with animateTransform elements and refreshes the date and PM indicator using a timer
  • The size of the optimized application is less than 10 kilobytes (including less than 1 kilobyte for the javascript code)
  • To display the clock add the following embed element inside a div element of an HTML page of your site:
    <embed type='image/svg+xml'
    src='https://storage.googleapis.com/draw-svg.appspot.com/posts/app-clock-cc.svg'>

Other digital version:

  • three wheels (hours, minutes, seconds)
    with three timers for hours, minutes, date and a permanent animation for the seconds
  • Use clipPath element
  • The size of the optimized application is less than 24 kilobytes
  • To display the clock add the following embed element inside a div element of an HTML page of your site:
    <embed type='image/svg+xml'
    src='https://storage.googleapis.com/draw-svg.appspot.com/posts/app-clockn-cc.svg'>

Rubik 2D game app

Simplified version of the Rubik's cube:

  • Generates 16 squares of 4 different colors randomly
  • Each square has 2 to 4 arrow-shaped buttons to be swapped with an adjacent square
  • The translation of each square is carried out with an animateTransform element
  • The game is won when the squares of the same color are aligned horizontally or vertically
  • The number of translations carried out is displayed as the score achieved
  • The game can be restarted with the circular arrow placed on the left
  • The size of the optimized application is less than 16 kilobytes (including less than 10 kilobytes for the javascript code)
  • Is compatible with desktop and touch devices
  • To display the game add the following embed element inside a div element of an HTML page of your site:
    <embed type='image/svg+xml'
    src='https://storage.googleapis.com/draw-svg.appspot.com/posts/app-rubikrec-cc.svg'>

Interactions with the client HTML page

The embed tag has the advantage of allowing the use of the context of the document included from the parent page, provided that the document is in the same domain to avoid the cross-domain error (for example the svg file of the application can be deployed in the same directory as the client page).

It is thus possible to register an external API on the parent window from the javascript code to interact with the application.

The 'game restart' button above interacts with the app-rubikrec application by calling the game.restart method which was registered on the parent window context:

<button onclick="window.game_restart()">Restart game</button>

The game_restart function has been registered by the application :

// export game API on parent window (only on same domain)
try {
window.parent['game_restart'] = game.restart ;
}
catch(ex) {
console.log("Export game API "+ex);
};