. In that post I mentioned that my JavaScript book had only built games using canvas drawing and I wondered now if readers of that book would be interested in a general introduction to SVG. There are many instances where SVG rather than canvas drawing would be the most appropriate tool for displaying and animating particular images.
We position the start on the lower ruler’s scale at one of the two values (in this case 3) and read off the sum of 3 and 8 on the scale of the upper ruler (see the red line). It should also be obvious that the same positioning could be used to calculate 11 minus 8 or any other pair of values on the two ruler scales.
The logarithm (base 10) of a number is the number expressed
as a power of 10.
1.65 = 100.2175 so
log(1.65) = 0.2175
3.45 = 100.5378 so log(3.45) = 0.5378
0.5378 + 0.2175 = 0.7553 (sum the logs)
100.7553 = 5.6925 which is the product of 1.65 and
3.45.
Thus simple addition can be used to multiply two decimal fractions.
Fortunately, when I was at school, we did not need to calculate these powers of 10 – we were issued with books of tables for looking them up. The tables included a host of trigonometric tables as well as the vital “antilogarithms” needed to establish that 100.7553 was 5.69 (which was about as accurate as the ones I had could get.
If instead of having pages of tables we were to draw a logarithmic scale on a pair or rulers instead of the linear scale illustrated above we could use them to multiply two values by adding the logs. Indeed we could also do division by subtracting one logarithmic scale position from another. So, what does a logarithmic scale look like in action?
You will notice that as the values increase (from 1 to 10 in
this instance) the distance between the log of those values decreases. You can
probably also see that two rules with logarithmic scales can be used to make
our calculation. Slide rules were fast and accurate enough for most purposes.
Why does the log scale start at 1? Well ten to the power of
zero is 1 and zero is a good place to start. In fact any number to the power of
zero is 1. Feel free to debate about zero to the power of zero;
Wikipedia has a page on it.
As it was way easier to use JavaScript and SVG to create the
illustrations in this “aside” than to draw them using something like Paint.NET
it is probably time now to cut back to the chase as they say.
</Aside>
We could start some SVG development with an HTML page and a
short CSS file.
main.css looks like:
html { padding: 0; margin: 0; border: 0;}
#dvViewer {
width: 300px;
height: 200px;
}
svg {
height: 100%;
width: 100%;
}
and the index.html file has all the SVG action and plagiarises the Mozilla documentation (at least in part).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible">
<title>Basic SVG Demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
</head>
<body>
<div id="dvViewer">
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
<style>
.normal { font: normal 15px sans-serif; }
.bold { font: bold 30px sans-serif; }
.bright { font: italic 40px serif; fill: red; }
</style> <!-- font colour is the fill -->
<text x="10" y="35" class="normal">Welcome</text>
<text x="75" y="35" class="bold">readers</text>
<text x="55" y="65" class="normal">to</text>
<text x="70" y="65" class="bright">SVG!</text>
</svg>
</div>
</body>
</html>
The HTML <body> contains a single <div>. Within the <div> there is an <svg> element that is structured in a pretty familiar way. XML is a “markup language” just like HTML. The <svg> element contains a <style> tag that defines three classes that can be used for CSS type styling. The <style> object is followed by four text objects with the “x” and “y” attributes setting the bottom left for the text content. The “x” and “y” units relate to the “viewBox” attribute that sets the dimensions of the viewport.
If you load the HTML file into a browser then you should see:
The <svg> viewBox attribute read viewBox="0 0 200 100". This defined the upper left hand corner as having coordinates 0,0 with a width of 200 units and a height of 100 units. This is not the same as the dimensions of the <svg> object set by the CSS. Try resetting the viewBox values so that they match the size (300 by 200) set in the CSS and reload the page. You should observe some instant scaling.
Next step is to try drawing something just a little bit technical. Add another <div> and some enclosed <svg> to the HTML file.
<div id="dvScale">
<svg viewBox="0 0 510 30" xmlns="http://www.w3.org/2000/svg">
<style>
.normals { font: normal 10px sans-serif; text-anchor: middle;}
.tl {stroke: black; stroke-width: 0.5;}
</style>
<line x1="5" y1="20" x2="5" y2="30" class="tl" />
<text x="5" y="19" class="normals" >1</text>
<line x1="155.5" y1="20" x2="155.5" y2="30" class="tl" />
<text x="155.5" y="19" class="normals" >2</text>
<line x1="243.5" y1="20" x2="243.5" y2="30" class="tl" />
<text x="243.5" y="19" class="normals" >3</text>
<line x1="306" y1="20" x2="306" y2="30" class="tl" />
<text x="306" y="19" class="normals" >4</text>
<line x1="354.5" y1="20" x2="354.5" y2="30" class="tl" />
<text x="354.5" y="19" class="normals" >5</text>
<line x1="394" y1="20" x2="394" y2="30" class="tl" />
<text x="394" y="19" class="normals" >6</text>
<line x1="427.5" y1="20" x2="427.5" y2="30" class="tl" />
<text x="427.5" y="19" class="normals" >7</text>
<line x1="456.5" y1="20" x2="456.5" y2="30" class="tl" />
<text x="456.5" y="19" class="normals" >8</text>
<line x1="482" y1="20" x2="482" y2="30" class="tl" />
<text x="482" y="19" class="normals" >9</text>
<line x1="505" y1="20" x2="505" y2="30" class="tl" />
<text x="505" y="19" class="normals" >10</text>
</svg>
</div>
and back that up with a small addition to the CSS file.
#dvScale {
width: 510px;
height: 30px;
}
Reload the HTML file in your browser and you should see the new addition rendered like.
Clearly that was a lot of XML added to the web page and it should also be fairly clear that some calculations had been hand cranked to place the vertical lines and numbers. This would be much better achieved using code so the next step will be to switch to creating our SVG graphical output using JavaScript. Before that though, take a look at the two new classes added between the <style> tags. The text style (normals) has a text-anchor attribute to centres the numbers over their defined "x" position. The <line> tags are probably what you would expect with a defined start and end point. One thing though, the style class applied defines the stroke colour as if this is omitted then the line will not be drawn.
The next step minimises the HTML but adds a couple of short JavaScript files.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible">
<title>SVG and JavaScript</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
<script src="svg.js"></script>
</head>
<body>
<div id="dvScale">
</div>
<script src="main.js"></script>
</body>
</html>
There is a very good chance that you will decide to use a JavaScript library to manipulate SVG graphics. [If there is a lot of HTML to manipulate then you might well decide to make use of jQuery so similarly, if a lot of SVG is going to be created then a library designed to make that simpler is likely to appeal.] As a placeholder for such a library, I created a JavaScript file called svg.js with one function,
function createSvgElem(svgTag, svgAttr, svgStyle, addTo) {
const nSpace = "http://www.w3.org/2000/svg";
let nElem = document.createElementNS(nSpace, svgTag);
for (let atrib in svgAttr) {
nElem.setAttributeNS(null, atrib, svgAttr[atrib]);
}
if (svgStyle) {
for (let atrib in svgStyle) {
nElem.style[atrib] = svgStyle[atrib];
}
}
if (addTo) {
addTo.appendChild(nElem);
}
return nElem;
}
That function is passed an SVG tag name, an object containing relevant attributes, an object containing style attributes (or null if there are none) and an object to which the new SVG object created should be added. For the main <svg> object that will be an HTML element but things like <line> and <text> tags will be added to a preexisting <svg> element.
All the creative action is in the main.js file.
var div = document.getElementById("dvScale");
function initialise(){
let svgStyle = {
small: { "font": "normal 10px sans-serif", "text-anchor": "middle"},
tl: {"stroke": "black", "stroke-width": "0.5"}
};
let svgAttr = {"viewBox": "0 0 510 30"};
let svg = createSvgElem("svg", svgAttr, null, div);
for(let i = 1; i < 11; i++){
let x = (Math.log10(i) * 500 + 5).toFixed(1); // log of number * scale length + scale start
svgAttr = {"x1": x, "x2": x, "y1": "20", "y2": "30"};
createSvgElem("line", svgAttr, svgStyle.tl, svg);
let lab = createSvgElem("text", {"x": x, "y": "19"}, svgStyle.small, svg);
lab.innerHTML = i.toString();
}
}
initialise();
That code takes a bit of a scatter gun approach to show a couple of techniques for attributes and styles. The <svg> object is created with an attribute detailing the viewBox. Then a sequence of <line> and <text> tags are added within the for loop but note that the content of each <text> tags is added after it is created.
If you open the revised web page in your browser and then open the "Developer Tools" (<F12>) you can take a look at the content of the <div> with the id dvScale using the "elements" tab in Chrome and Edge or the "Inspector" tab in FireFox. You should see the nicely laid out <svg> tag that starts:
<svg viewBox="0 0 510 30">
<line x1="5.0" x2="5.0" y1="20" y2="30" style="stroke: black; stroke-width: 0.5;"></line>
<text x="5.0" y="19" style="font: 10px sans-serif; text-anchor: middle;">1</text>
<line x1="155.5" x2="155.5" y1="20" y2="30" style="stroke: black; stroke-width: 0.5;"></line>
<text x="155.5" y="19" style="font: 10px sans-serif; text-anchor: middle;">2</text>
<line x1="243.6" x2="243.6" y1="20" y2="30" style="stroke: black; stroke-width: 0.5;"></line>
<text x="243.6" y="19" style="font: 10px sans-serif; text-anchor: middle;">3</text>
<line x1="306.0" x2="306.0" y1="20" y2="30" style="stroke: black; stroke-width: 0.5;"></line>
<text x="306.0" y="19" style="font: 10px sans-serif; text-anchor: middle;">4</text>
<line x1="354.5" x2="354.5" y1="20" y2="30" style="stroke: black; stroke-width: 0.5;"></line>
<text x="354.5" y="19" style="font: 10px sans-serif; text-anchor: middle;">5</text>
...continues...
Looking just as it might have been typed in the hard way.
Enough of these logarithmic scales -
time to sample some of the other things we can do with SVG - all in part 2.
Further reading:
SVG JavaScript Libraries (web search for others):
Snap.svg