Tirol Atlas Topo

SVG on top of a dynamic mapping system

Klaus Förster
Department of Geography, University of Innsbruck
Innrain 52
A-6020 Innsbruck


Klaus Förster is technical director of the Tirol Atlas, works in the fields of application programming & database administration and teaches web mapping courses at the University of Innsbruck, Department of Geography.


The Tirol Atlas (an Interreg IIIa project funded by the European Union and the regional governments of Tirol, Austria and South Tirol, Italy, carried out by the Department of Geography, University of Innsbruck) has been using SVG for three years now to visualize thematic maps, charts, diagrams and highly interactive learning applications for kids. The latest efforts target creation of a topographic map with a scale reaching from 1:1.6000.000 Mio to about 1:100.000 at the most detailed level. PostgreSQL with PostGIS, University of Minnesota mapserver (UMN), GRASS-GIS, Perl and last but not least SVG at visualization level are the main components of the application that will be outlined in this paper.

Table of Contents

1. The basic interface
     1.1 General features
     1.2 UI.js - the central interface javascript library
2. Adding the map
     2.1 Create background image with UMN-mapserver
     2.2 Query geometry & styles from PostgreSQL/PostGIS database
     2.3 Create SVG-Code and send it back to the Interface
3. Adding functionality
4. Conclusion
Appendix 1. Links

1. The basic interface

1.1 General features

The basic Tirol Atlas Topo interface is more than yet another SVG mapping interface with standard components like main and overview map, zoom and pan controls, scalebars and a display showing coordinates as you move the mouse in the main, or overview map. In addition, a view-history indicated by arrows below the wind rose allows you to navigate to previous or next extents whenever available. Coordinate display may be switched from UTM-WGS84 32N to latitude/longitude and back by clicking on the control itself. A simple tooltip system with border-detection converts custom namespaced ta:hint-attributes of any element within the interface receiving pointer-events to tooltips.

Interface texts may be translated onload to different languages according to translation-arrays. These hold the type of the node or attribute (e.g. text, tspan or ta:hint), node-ID and language variants per entry. Key-value pairs from the URL's query string (if present) are extracted as well, enabling calls to the interface with additional parameters. You may specify the desired language or a custom map-extent defined by x,y,width and height or cx,cy instead of x,y if you want to set focus on a certain element.

User hints, warn- or error-messages with simple line-breaking can be displayed in the semi-transparent area at the top of the main map. A tabbed-style help system with up to five tabs may be filled with arbitrary extern SVGs using image-tags and last but not least a "loading ..." animation may be switched on and off, whenever data has to be loaded to indicate that "something's going on" and the user should wait for it to be completed. All these features are implemented by UI.js, the central user interface javascript library that exposes interface relevant basic attributes and methods in a global UI-object that can be accessed by other parts of the interface at any time

1.2 UI.js - the central interface javascript library

Line numbersContent / description / remarks (click her for code)
1-24GNU General Public License disclaimer, CVS-tag
26-65Definition of the global UI-object with attributes and references to nodes
67-176Constructor. Define coordinate-systems, add eventListeners, initialize zoom and pan, main and overview map, coordinate display, view-history, parse query-string
179-228Method to parse query-string if any and extract key/value pairs
230-253Method to narrow viewport onload or on demand
255-291Method for translating terms within the interface according to language
293-302Method to show or hide a "loading ..." animation
304-335Methods to show or hide info-, warn-, or error-messages. Up to two lines with simple text-wrapping at word-boundaries according to number of chars
337-355Method for custom debug-messages during development
357-528Central event-handler method. This is the place where all eventListener triggered events arrive. Actions are taken according to where they came from and cover tasks like: permanently record mouse-positions in UTM and SVG viewport, handle zoom and pan via zoom-rectangle or overview map, handle coordinate display and view-history
530-605Methods for zoom and pan within main or overview map
607-687Methods for size and viewBox handling. Set viewBox in main and overview map, adjust viewBox size to match width/height ratio of map, set base font-size for map-texts according to current scale. Whenever the viewBox is changed, a request to load appropriate geometry is sent to a function in LOAD.js (this will be explained in more detail within the next section)
689-760Methods for view-history. Stores viewBoxes in an array that is widened, shortend on demand
762-864Methods for coordinate and scale display. Credits go to Steven Dutch, University of Wisconsin-Green Bay who provides a spreadsheet for UTM to degree conversion - these formulas have been "reverse engineered" and implemented in javascript
866-947Methods for a simple tooltip system that also allows to fix auto-resizing tooltips within the map
950-975Method for basic text-wrapping at word-boundaries
977-1010Private helper functions to convert strings to arrays and back and the like
1018Initialize and expose the new UI.interface object

Table 1: UI.js - the central interface javascript library

2. Adding the map

2.1 Create background image with UMN-mapserver

The process of adding a map starts with a getURL-request to, a Perlscript within LOAD.js passing the current map-viewPort, language and optional background image or map composition as arguments. It is triggered onload, onresize and whenever the viewPort of the main map changes due to zoom- or pan-events. Within several tasks are accomplished. At first, a background JPEG-image according to the current map-extent is created on-the-fly with UMN-mapserver. It combines a shaded relief, generated out of a 50m resolution DEM with transparent settlement-, forest- and glacier-layers in ESRI's shape-format derived from Corine land cover level 3 data. Communication between Perl and UMN-mapserver is managed by the mapscript module. The following listing provides links to the Perl code snippet, the sample UMN-mapfile used and the resulting image.

2.2 Query geometry & styles from PostgreSQL/PostGIS database

In a second step attributes like feature-names, styles and geometry are queried from a PostGIS enhanced PostgreSQL database. At this point it is necessary to take a short look at the underlying database-schema. Geometry is kept in three tables according to feature-type point, line or polygon with unique-ID, feature-ID to identify objects, level of detail (LOD) and a class attribute to specify how a feature should appear in the output. Levels of detail follow a "quadtree-like" structure - starting at a scale of ~1.1.600.000 in full view and ending with scale 1:100.000 at the most detailed level. Styles are represented in a more complex system consisting of six tables and two views that allow to control and specify stacking order of layers, CSS-styles, symbols, patterns and marker-symbols independently for each map composition. The following table tries to give a simplified overview of the table structure used to store geometry along with style information.

Table nameContent / description / remark
featureDistinct features with unique FIDs like a river, lake, village, mountain, castle ...
feature_langLanguage variants for feature names
geom_point(Multi)Point features with FID, LOD, style(s) and geometry. Styles can be combined - e.g. "highway" or "highway tunnel"
geom_line(Multi)Line features with structure as above
geom_poly(Multi)Polygon features with structure as above
mapID and name of a map composition (e.g. Topographic Map)
map_langLanguage variants of map composition names
stylesAbbreviations for styles: "highway", "lake", etc. along with name
styles_langLanguage variants for names of abbreviations
map_contentID of map composition, three style columns that define the class of a layer (e.g. style1=highway, style2=tunnel) along with zindex for sorting and active true/false switch. Additional LOD column to specify first appearance of the layer
map_content_markupID of map composition, abbreviation of a style present in one of the three style-columns of map_content, the type of markup (css,symbol,pattern,marker) and a column with the actual markup. Examples:
  • highway / css / stroke:red;stroke-width:0.4%;
  • castle / symbol / <symbol id="castle" ... />
  • lake / pattern / <pattern id="reservoir" ... />
  • liftchair / marker / <marker id="chairlift" ... />
  • liftchair / css / stroke:black;marker-start:url(#chairlift);
  • village / css / font-size:0.9em;

Table 2: Database tables

Geometry is delivered using the AsSVG() function of PostGIS. AsSVG(), originally written by the author, is now part of the standard distribution and allows to output absolute and relative SVG-path notation for lines and polygons and cx,cy or x,y notation for point features. The importance of the ability to specify relative path-notation is illustrated in the example below. To further reduce output-size, coordinate-precision may be specified as well.

absolute path notation:
M 706219 -5256092 706201 -5256089 705825 -5256133 705207 -5256342 704043 -5256995
  703878 -5257417 703640 -5258188 703526 -5261762 703574 -5263748 703871 -5264205
  703939 -5264299 704147 -5263966 704395 -5263361 704445 -5262850 704399 -5262757
  704253 -5262632 704190 -5262368 704524 -5258819 704602 -5258225 704651 -5258146
  704896 -5257827 705344 -5257395 705969 -5256906 706094 -5256800 706343 -5256542
  706393 -5256393 706354 -5256227 706219 -5256092

relative path notation for the same polygon:
M 706219 -5256092 l -18 3 -376 -44 -618 -209 -1164 -653 -165 -422 -238 -771 -114 -3574
  48 -1986 297 -457 68 -94 208 333 248 605 50 511 -46 93 -146 125 -63 264 334 3549
  78 594 49 79 245 319 448 432 625 489 125 106 249 258 50 149 -39 166 -135 135

circle-notation: cx="684968" cy="-5196199"

x/y notation for text, symbols, use-elements: x="684968" y="-5196199"

Example 1: Examples for the usage of AsSVG()

2.3 Create SVG-Code and send it back to the Interface

The actual generation of SVG-Code within happens in three phases. In a first step all styles are queried and put together in a <defs /> code block holding css styles, symbols, patterns and markers for to the current map-composition and LOD (see Example). In the second step, geometry along with style-attributes and names is queried from the point, line and polygon tables according to LOD and current extent. <path />, <text /> or <use /> elements are created with ta:hint set to the features name and put together in <g /> elements with the same style(s). During the last step the stacking order for the created groups is queried from the map_content table. An <image /> element for the freshly generated background JPG is added, styles & geometry are put together, encoded in UTF-8 and sent back to getURLs callback function within LOAD.js where it is converted to XML using parsXML and appended to a group within the main map. Existing content in this group is erased beforehand.

3. Adding functionality

To provide further functionality, it is intended to add tools to the map. One of these tools allows the user to draw and explore interactive elevation-profiles. To activate it, the user has to click on the yellow profile-icon in the top-right corner. This starts an eventListener that records any click in the main map and builds a profile-line with up to 10 points or 70 kilometers length. Length is limited for performance reasons - nevertheless the first segment can be longer since there's no truncating of line segments. Double clicking finishes the line and calls, a Perlscript via getURL that executes GRASS-GIS' r.profile command with the given line.

export GISBASE=/usr/local/grass5;
export GISRC=/path/to/grassrc5;
/usr/local/grass5/bin/r.profile -g input=dem profile="642160,5241440,651340,5231030" res=50 out=-

Example 2: sample r.profile command

The out=- parameter in the above example causes GRASS to return an ASCII representation of the elevation profile containing point-coordinates, distances and elevations that looks as follows.

Using Resolution 50.000000
Output Format:
[Easting] [Northing] [Along Track Dist.(m)] [Elevation]

Approx. transect length 13879.499023 m.

642160.000000 5241440.000000 0.000000 1072.300049
642193.070357 5241402.498647 50.000000 1072.300049
642226.140715 5241364.997294 100.000000 1080.199951
651254.348257 5231127.127957 13750.000000 1908.699951
651287.418614 5231089.626604 13800.000000 1899.099976
651320.488972 5231052.125251 13850.000000 1908.099976

Example 3: ASCII output of r.profile

This output is parsed and converted to SVG-elements and animations that are sent back to getURL's callback function, appended to a group within the main map and started onload (see Example). One animation follows the profile-contour line using calcMode="discrete", a second one runs along the profile-baseline with calcMode="linear" and a third visualizes the profile-line within the main map using calcMode="paced". As soon as the user moves the mouse over the semi-transparent profile area, running animations are stopped and a javascript function displays height-values as tooltips and a position-marker on the profile-line. Mouseout restores the initial status and starts with the original animations again. Clicking anywhere in the main map will start a new profile-line, clicking the profile-icon will deactivate the tool.

4. Conclusion

The presented application and thus this paper is not complete yet. One can expect that it will further change within the next few months. Besides profile generation, additional tools like data-, image- or info-text display have been implemented since the paper-abstract was posted. A tool for uploading lat/lon ASCII-GPS-tracks is in preparation and thematic layers for earth-quake events, slope stability and flow accumulation will be added by the end of June. Nevertheless it's a fine example of SVG in a real-world environment trying to integrate outstanding open-source programs like PostgreSQL, PostGIS, UMN-mapserver or GRASS and thus form an advanced dynamic mapping-system. SVG1.2 (if it ever happens ;-) will add to that and further push the limits.

Appendix 1. Links;slides=on

XHTML rendition made possible by SchemaSoft's Document Interpreter™ technology.