Scenery in SVG: programming a drawing surface

Making a landscape with a script from SVG components taken in a library.

1) Creating a library of models

Consider first the case where the library is in the page. It is realized with a svg tag containing several shapes, in our demonstration, a rectangle and a circle.

<svg id="repository">
<rect id="rect" width="200" height="100" style="fill:rgb(100,150,200);" />
<circle id="circle" cx="300" cy="80" r="60" style="fill:rgb(0,160,0);";/>
</svg>
Shape library

It would also be possible to create images dynamically. The following example creates a circle that is filled with the red color.

var cir = document.createElementNS("http://www.w3.org/2000/svg", "circle");
cir.setAttribute("cx", 40);
cir.setAttribute("cy", 60);
cir.setAttribute("r", 35);
cir.setAttribute("fill", "red");

Another solution is to use images stored in svg files, which have been generated by software such as Inkscape or SVG-Edit.

A svg image may be integrated in several ways. For example with the xlink property of image:

<svg width="96" height="96">
<image xlink:href="code/boat.svg" src="code/boat.png" width="100" height="100"/>
</svg>

The advantage of this method that integrates an image tag in a svg tag is that you can display a bitmap replacement if the browser is too old to support SVG. We will see how to use this method in the article: SVG: Car on a road and event programming. A second method is to use the object tag.

<object width="100" height="100" data="code/plane.svg"></object>
<object width="100" height="100" data="code/boat.svg"></object>
<object width="100" height="100" data="code/building.svg"></object>
File Library

This is ideal to load and display SVG images on the page. We may also have recourse to a third method, iframes:

<div style="display:none">
<iframe id="iplane" width="100" height="100" src="code/plane.svg"></iframe>
<iframe id="iboat" width="100" height="100" src="code/boat.svg"></iframe>
<iframe id="ibuilding" width="100" height="100" src="code/building.svg"></iframe> </div>

In an object tag, the image is automatically resized to fit the container, it is not the case for the iframe. The iframes are placed in a layer that has the property display:none because we want just use their content and not display it, so it is not important here.

Using content of iframes or objects is very easy as we shall see.

2) Building a composition

We create a surface like it is done for Canvas, but the container here is a svg tag:

<svg class="surface" id="surface"></svg>

The components are inserted with the appendChild method of DOM:

var surface = document.getElementById("surface");

var rect = document.getElementById("rect");
var clonerect = rect.cloneNode();
clonerect.setAttribute("x", 100);
clonerect.setAttribute("y", 200);
surface.appendChild(clonerect);
var circle = document.getElementById("circle");
var clonecir = circle.cloneNode();
surface.appendChild(clonecir);

We create a clone of the two shapes to prevent them to disappear from the gallery above, as appendChild otherwise displaces the tag in the DOM from the gallery to the svg tag.

We also adds the shape created dynamically:

surface.appendChild(cir);

This gives the following composition:

We will now create a composition from object stored in svg files. A new surface is created with the ID "city":

<svg class="surface" id="city"></svg>

The getSVG function is defined to extract the file contents once loaded in the iframe.

function getSVG(iframeID, objID)
{
var ifr = document.getElementById(iframeID);
var graphics = ifr.contentWindow || ifr.contentDocument;
return graphics.document.getElementById(objID);
}

The arguments are the ID of the iframe in which we load the file, and the ID of the content in the svg file. The file contains a <g> tag with an ID to identify the content to be inserted in our container, for example:

<g id="boat"> ... </g>

It is important to display svg content after complete loading of the page, so we use the onload property of window.

Before adding the components to the landscape, they are given a color and a position. Since the <g> tag has no x and y attributes, we instead use the translate property.

function displaySVG() 
{
var city = document.getElementById("city");
var building = getSVG("ibuilding", "building");
building.setAttribute("transform", "translate(360,126)");
building.setAttribute("fill", "#ccc");
city.appendChild(building);
var boat = getSVG("iboat", "boat");
boat.setAttribute("fill", "#090");
boat.setAttribute("transform", "translate(10,247)");
city.appendChild(boat);
var plane = getSVG("iplane", "plane");
plane.setAttribute("fill", "blue");
plane.setAttribute("width", "120");
plane.setAttribute("height", "50");
plane.setAttribute("transform", "translate(60,30)");
city.appendChild(plane);
}
window.onload=displaySVG;

Here is the final landscape:

We can go further, add animations, allowing the user to interact with the landscape, this is the advantage of svg ... it will be the subject of other articles ... In SVG: Moon landing and programming by goal you have a demo of a moving SVG object in a scenery.