Building an SVG interface to MediaWiki

Creating a web-based map of interpersonal relations in the sphere of culture

Peter Edwards

Technical Director
e-2.org limited


London

64A Regent Studios, 8 Andrews Road

E8 4QN
United Kingdom
+44 (0) 20 7249 1800

Peter Edwards is co-director of e-2.org limited, a digital arts organisation based in London, U.K.

Peter graduated in 1988 from Leicester University with a BSc (Hons) Chemistry degree (2[ii]), worked in the merchant navy for 2 years followed by jobs as a milliner, music journalist and postal worker before becoming a librarian.

After receiving a Postgraduate qualification in Library and Information Science in 1997, he left libraries in 1999 to pursue a career as a computer programmer. Interests include contemporary music, art, cookery, 20th/21st century literature. Peter has two children with his partner, the artist Sally Barker, and lives in East London.


Abstract


In 2006, e-2 started a project with artist Nat Goodden which maps key cultural figures by using information about their acquaintanceship with others to link them together. The name of the project is Who knew Whom, and the first working prototype of the SVG interface can be found at http://culturalcartography.net/ (the SVG "view" can be activated from within each of the biographical pages).

The ideal tool for the artist to input entries was a wiki, so we used MediaWiki, the software behind WikiPedia. The capability to engage large numbers of contributors in the future was one of the criteria for this, as was the ability of the software to map links between pages. The artist wanted an interface similar to ThinkMap's visual thesaurus( http://www.visualthesaurus.com/ ), which shows how an imaginative understanding of both visual and conceptual semantics can draw the viewer in to an understanding of highly complex interrelationships. In our case, individual names are animated amongst a field of other connected names, and can be clicked to move them to the foreground, and potentially change most of the interface elements. We chose SVG for the interface, as we had previous experience of using SVG to animate text and had found that it out-performed all alternatives.

This paper focuses on the way in which we developed custom solutions for font handling, animation and the use of AJAX in realising the project. Font embedding in SVG viewers is badly supported, and we needed to include a cursive font in the interface and have it display correctly in SVG viewers which did not support SVG fonts. We therefore embedded the font definition as a set of paths, themselves derived from the TrueType font. Kerning information was derived in the same way and made available to the application as a JSON object, and all text operations were carried out using scripts. Animation of the interface was to be handled entirely using scripts, as declarative animation suffered from a similar lack of support. AJAX was needed to constantly update the interface, and to retrieve more in-depth information about each subject.

The project illustrates the efficacy with which SVG can lend itself to interface design, and it also indicates that the fledgling support for SVG in modern browsers such as Safari and Firefox is very good, and can be harnessed in ways which can sidestep the lack of certain features in their implementations.


Table of Contents

Introduction
Project Outline
Technical Infrastructure
Interface design
Fonts
Embedding the font in SVG
Font embedding using AJAX
Skinning MediaWiki
Interfacing with MediaWIki
Rendering names in the interface
Animating the interface
Current status of the project
Future of the project

In 2006, e-2 started a project with artist Nat Goodden which maps key cultural figures by using information about their acquaintanceship with others to link them together. The name of the project is Who knew Whom, and the first working prototype of the SVG interface can be found at http://culturalcartography.net/ (the SVG "view" can be activated from within each of the biographical pages).

Digital information systems that take advantage of dynamic forms of screen display allow complex bodies of information to be presented with a degree of clarity and responsiveness that can otherwise be hard to achieve. Such information systems are also well suited to dealing with data-sets that grow by the day. When designed for online access, they can in addition benefit from external user input, and take advantage of connectivity with existing web-based resources.

Who Knew Whom is a new project that takes advantage of all of these factors. It is a web-based map of interpersonal relations in the sphere of culture. Culture, viewed in terms of individual contributors and their acquaintanceships, is a multi-connective territory, a complex and active network of links and nodes extending through space and time. As far as can be determined, a mapping of these has not been attempted on this scale before.

Throughout this project, culture is taken to be a pluralistic and fluid domain, constantly evolving; a collective endeavour that nonetheless can be examined through the individuals (working singly or in groups) who have made significant contributions to its evolution. Among other things, the project is interested in revealing the cross-disciplinary nature of many personal acquaintanceships in this arena. It aspires to offer a quality of user experience that is already well-exemplified by the likes of good dictionaries, atlases and so on: compilations of information whose structure benefits not only the reader who wishes to search, but also the reader who wishes to browse, or who comes for one thing and emerges some time later having taken a pleasant if unanticipated imaginative diversion. Who Knew Whom sets out to be a serious cultural-cartography resource - an emergent atlas of individuals and their significant links - but equally to be a place to go when random stimulus is the order of the day.

Who Knew Whom is being launched as a long-term project, designed to be expanded indefinitely, and comfortable with its permanently incomplete status. It remains primarily a personal project of its originator Nat Goodden, with Peter Edwards and Peter Moore of the London digital arts agency e-2 significant partners in turning the idea into reality.

The brief for the project required a system which would enable multiple authorship, whilst allowing for a single author for the initial prototyping phase. The system had to be able to handle version control (in the multiple authorship phase), enable editing of content easily by people with no knowledge of markup languages, and most importantly, hold a map of the links created within different pages. It would also be an advantage to be able to extract information from the system via an API rather than having to write a custom library of functions to access information.

MediaWiki was chosen as the storage mechanism for the data because it was free and open source, and actively maintained by a large developer community. Its feature set was well suited the task for a number of reasons:

  1. The biographical entries and linked names needed to be input by the artist, and the tools for doing so in MediaWiki were well developed and easy to use.

  2. The system needed to be able to store non-english characters, and MediaWiki uses UTF-8 for all text, and is used as a multi-lingual application.

  3. The application needed to be able to identify which pages linked to other pages, and vice versa, which is all handled internally by MediaWiki.

  4. MediaWiki excels at both version control and and multiple authorship.

Scalable Vector Graphics (SVG) was chosen as the presentation mechanism because we had used it before and were impressed by the results. The only other method under consideration was Flash, which was rejected in favour of SVG for the following reasons:

  1. The SVG graphics format is text-based, and can therefore be edited in any text editor, whereas the Flash format is a proprietary, binary format which requires a commercial authoring tool to create.

  2. Another consquence of SVG being text based is that it makes them easier to generate dynamically. Flash files could be created dynamically, using software such as the Ming PHP Extension, but the complexity of the files needed to run the animation would have been too great for this software to do so at the time.

  3. The SVG format is a W3C Recommendation, and is therefore is a royalty-free vendor-neutral open standard, i.e. not tied to any software platform. Flash, however, is tied to the Flash Player for its display, and there would be no guarantee that future versions of the Flash Player would be capable of displaying the interface without alterations and adjustments having to be made.

The font chosen for the interface was the OpenType script face Handsome Pro , designed by Nick Shinn and available through the Shinntype Type Foundry ( www.shinntype.com ). Font embedding in SVG viewers at the time was badly supported - the only viewer capable of displaying embedded SVG fonts was the Adobe SVG Viewer (Adobe have since announced that customer support for Adobe SVG Viewer will be discontinued on January 1, 2009). Even now, support for the <font> element is not implemented in Firefox 3 .


In order to embed the font in the SVG file, it was necessary to devise a method of utilising the font as a set of paths (rather than using the <font> element) to ensure maximum support in current SVG Viewer Implementations. This was achieved by first converting the OpenType font to an SVG font using the SVG Font Converter - part of the Batik SVG Toolkit . Once the conversion had taken place, the font was represented by an SVG font file which looked like this:

					
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" > <svg width="100%" height="100%">
<defs >
<font id="HandsomeProRegular" horiz-adv-x="374" ><font-face
    font-family="Handsome Pro"
    units-per-em="1000"
    panose-1="3 5 5 2 4 2 7 7 12 4"
    ascent="650"
    descent="-350"
    alphabetic="0" />
<missing-glyph horiz-adv-x="1000" />
<glyph unicode=" " glyph-name="space" horiz-adv-x="270" />
.......
other glyph definitions - followed by kerning data
.......
<hkern g1="space" g2="t" k="-28" />
.......
</font>
</defs>
</svg>
                
				

Once the SVG font had been derived from the original, it was processed by a PHP script, which extracted all the path data for each glyph, and all kerning data for the font. All glyphs defined in the font were stored as <path> elements in a single file (the contents of which could later be pasted into the <defs> section of an SVG file), and additionally in separate files, each one containing a single <path> element and named after the character code of the letter it defined. The kerning data for the font was stored in a JSON file.

The resulting <path> definitions can now be used in an SVG file, along with kerning data, to render letters in sequence by adding <use> elements to the SVG through the SVG DOM. The following figure illustrates this by taking the pangram of the earlier example, but this time rendering the text in an SVG file:


NOTE: Paths derived from <glyph> elements need to be transformed in order to render as expected.

Creating an interface to MediaWiki proved difficult at first, because the MediaWiki API hadn't been sufficiently developed to enable the interrogation of MediaWiki via AJAX in the version installed on our host (1.6). It proved necessary to create a simple API using PHP, which queried the MediaWiki database directly for information about entries, and all other entries which were linked to them. As the MediaWiki API developed through to version 1.11 (the version currently installed on our host), the API functions needed to query MediaWiki for this information had developed sufficiently to support the application, so the PHP API was abandoned in favour of it.

Information about the cultural figures contained in the MediaWiki installation was obtained via the MediaWiki API through AJAX calls. Three different API queries were used to perform this:

  1. The first MediaWiki API query (executed when the interface has loaded) needed to retrieve data for the name being searched for/linked to. The following MediaWiki API call gets a JSON formatted string containing all the information about a page needed to propagate the animation of the interface:

    							
    api.php?action=query&prop=info|categories&clprop=sortkey&format=json&titles=<name of the person>                   
                            
    						

  2. The main query needed to retrieve the linked names for a given person. The following MediaWiki API call gets a JSON formatted string containing all names linked to <named of the person> by using the links on a page as the generator for the data:

    							
    api.php?action=query&prop=info|categories&clprop=sortkey&generator=links&format=json&titles=<name of the person>                      
                            
    						

  3. Another query needed to retrieve the full text of the page for a person, so the text and links on the page could be displayed in the interface. The following MediaWiki API call gets a JSON formatted string containing the raw wiki text of the page by accessing the most recent revision of the page:

    							
    api.php?action=query&prop=revisions&rvprop=content&rvlimit=1&format=json&titles=<name of the person>                      
                            
    						

Retrieving the data in JSON format reduced the complexity of the application significantly (the custom PHP API had originally returned XML formatted data to the scripts). The MediaWiki API also provided a way to retrieve the text for a page - something the PHP API hadn't been able to achieve.

Early in the project, it was decided that the animated interface would consist of three layers:

  1. The top layer, which would hold a graphical representation of a person's name using the embedded font. This was to be centred on the screen and rendered in the largest typeface in the interface.

  2. The middle layer, which would hold the names of all the people who were acquainted with the top layer name. These were to be distributed semi-randomly around the top layer name and rendered in a typeface about a third of the size of the top layer name.

  3. The background layer, which would hold the names of all the people who were acquainted with all of the middle layer names. These were to be distributed randomly in a typeface around a third of the size of the middle layer names.

As well as being rendered in different sizes, the names would be rendered in different colours to increase legibility and improve distinction between the three layers.

If you took an average of 20 acquaintanceships per person, you would therefore need to render up to 421 names in the interface. In initial trials of this model, rendering the names was reasonably fast, but the amount of processing needed to render the names in the interface adversely affected the speed of any animations, bringing the interface to a grinding, processor thrashing halt. It was therefore decided to decrease the number of layers to two, using just the middle and top layers, and rendering the background layer as a static graphic. A simple PHP script was used to create a background PNG image, using the font and a snapshot of the names currently stored in the database, and distributing the names randomly on the image. Once a suitable image had been generated (the results of the random spatial distribution were not always ideal, which was one of the reasons why the PHP script was not used to do this in the application), it was saved as a PNG and used as the background image.

The decrease in the number of names rendered on the screen made the task of managing the interface a lot easier, as far fewer names needed to be tracked and animated. It also meant that so-called 'super-connectors' (people who seemed to be acquainted with a disproportionately high number of other cultural figures, such as William S. Burroughs ) would be less likely to cause problems.

Rendering the names in SVG involved the use of a custom font, embedded using the techniques described above . In order to do this in the most efficient way, two JavaScript objects were defined:

  1. wkwBank - the main purpose of which is to monitor the positions of names in the interface by storing a set of pre-defined coordinates and tracking their use. In the original 3-layer scheme, this object also had garbage collection responsibilities and ensured duplications were not made.

  2. wkwWord - this is the name object, responsible for setting up names in the interface and animating them. It contains references to the SVG <g> element which contains all the <use> elements to represent the name as a set of paths.

All animation of the interface was to be achieved using scripts, due to a lack of support for declarative animation in most SVG viewers. The names needed to be animated between the central position and any middle layer position, with the scale and position changing to make the name appear as though it were travelling towards/away from the viewer. They also needed to be animated between the background layer and middle layers in the same way. All transitions needed to change the colour (fill) of the paths to change the font colour so it was different for each layer.

Because all transformations are roughly equivalent, a similar method was employed for all - the code listing below serves to illustrate the animation method used (the example here is used for animating a name from the middle layer to the centre):

					
wkwName.prototype.toCentre = function(callback)
{
    /* nullify click events on the target */
    this.group.onclick = null;
    /* length of animation in milliseconds */
    this.slideTime = 1000;
    /* target scale */
    this.scaleTarget = 0.12;
    /* target coordinates */
    this.xTarget = ((512-((this.width * this.scaleTarget)/2)));
    this.yTarget = 340;
    /* displacement */
    this.xA = this.xTarget - this.x; 
    this.yA = this.yTarget - this.y;
    this.sA = this.scaleTarget - this.scale;
    /* frequency */
    this.B = Math.PI / (2 * this.slideTime);
    /* initial position */
    this.yD = this.y;
    this.xD = this.x;
    this.sD = this.scale;
    /* start time */
    this.C = new Date().getTime();
    /* callback function */
    this.cb = (typeof callback == 'function')? callback: false;
    /* set object variable so it is available in the nested funtion */
    var o = this;
    /* animation function */
    var tmr = setInterval(function()
        {
        var elapsedTime = new Date().getTime() - o.C;
        if (elapsedTime < o.slideTime) {
            var s = Math.abs(Math.sin(elapsedTime * o.B));
            o.x = Math.round(o.xA * s + o.xD);
            o.y = Math.round(o.yA * s + o.yD);
            o.scale = (o.sA * s + o.sD);
            col = 'rgb('+Math.round(((o.cCol.r - o.fCol.r) * s + o.fCol.r))+','+Math.round(((o.cCol.g - o.fCol.g) * s + o.fCol.g))+','+Math.round(((o.cCol.b - o.fCol.b) * s + o.fCol.b))+')';
            o.group.setAttributeNS(null, 'fill', col);
            o.group.setAttributeNS(null, 'transform', 'translate('+o.x+','+o.y+') scale('+o.scale+','+o.scale+')');
        } else {
            clearInterval(tmr);
            o.x = o.xTarget;
            o.y = o.yTarget;
            o.scale = o.scaleTarget;
            o.group.setAttributeNS(null, 'transform', 'translate('+o.x+','+o.y+') scale('+o.scale+','+o.scale+')');
            o.group.setAttributeNS(null, 'fill', 'rgb('+o.cCol.r+','+o.cCol.g+','+o.cCol.b+')');
            o.group.onclick = infoClickFunction(o);
            if (o.cb) {
                o.cb();
            }
        }  
    }, 10);
}; 
                
				

First of all, the click event on the name is nullified to prevent further user interaction with the name in the interface. Then a set of properties is defined on the name object to facilitate a time-based animation which follows a sine curve - this proved to be the most realistic in terms of giving the illusion of the name travelling in three-dimaensional space. Next, the callback function (to be called when the animation is complete) is stored as a property of the name object. Prior to calling the setInterval function, the name object is copied to a local variable to facilitate its use as part of a closure within the function called by setInterval . The body of the anonymous function called by setInterval implements the animation by being called at 10 millisecond intervals (i.e. as fast as the viewer can manage), and once the time set for the animation has elapsed, the final position of the name is set, and the callback function executed.

The following figure illustrates how the animations in the interface work. This uses modified versions of the scripts used in the prototype to illustrate the animation using a small sub-set of names.


The prototype for the SVG Interface can be accessed at http://culturalcartography.net/ by following the links on each of the wiki pages. The interface has been tested on the Windows platform using Firefox 2, Opera 9, and Safari 3, all of which display the Interface correctly, albeit with their own limitations. The main surprise was in testing the Interface using Safari 3, which produces the closest experience to the desired one through its smooth, and fast rendering of the animations. Unfortunately, the same cannot be said of Safari 3 running on a Macintosh.

Some work still needs to be carried out to get the interface working in the Adobe SVG Viewer and Batik's Squiggle browser, although it is hoped that it will work eventually in these two environments.

Although the SVG version of the interface is almost complete, and the results are initially quite good, a decision to move the interface to a Flash-based model was taken with the advent of ActionScript 3.0 and the Flash 9 player.

The main reason for this decision is the rendering of the font in SVG which, although it has been coerced into working adequately, will be very difficult to get it to support the number of characters needed by the application. The reason for this is that the font conversion tool cannot convert more than the first 256 characters of a TrueType font, so the number of characters available to the interface is limited. Having said this, additional characters could be added at any time by including the relevant path information in the <defs> part of the document, or even by retrieving the path information using AJAX. However, this would entail re-engineering the typeface in an SVG editing programme such as Inkscape, or manipulating the font in other ways. With Flash, the entire font could be embedded in the Flash player.

Another reason for changing to Flash as the display technology is that the majority of script authored in the project can easily be ported to ActionScript and the whole interface authored as ActionScript classes. There will be no need to resort to the Flash authoring platform to create the interface, and compilation of the scripts can be done using freely available tools.