JavaScript SVG Library 1.1

This is version 1.1 of my ongoing JavaScript SVG Library, the first being here. In this version I have added the ability to insert styles or CSS classes which can be reused across multiple elements instead of having to specify colors etc. individually.

The project consists of the following two JavaScript files, as well as an HTML file, a CSS file and a banner graphic.

  • svglibrary.js
  • svglibrary_demo.js

The files can be downloaded as a zip file, or you can clone or download the Github repo.

Source Code Links

ZIP File
GitHub

This is the source code for svglibrary.js.

svglibrary.js

class SVGLibrary
{
    static fill(id, color)
    {
        document.getElementById(id).style.backgroundColor = color;
    }

    static clear(id)
    {
        document.getElementById(id).innerHTML = "";
    }

    static line(id, x1, y1, x2, y2, classname, strokeColor, strokeWidth)
    {
        const line = document.createElementNS("http://www.w3.org/2000/svg", "line");

        line.setAttributeNS(null, "x1", x1);
        line.setAttributeNS(null, "y1", y1);
        line.setAttributeNS(null, "x2", x2);
        line.setAttributeNS(null, "y2", y2);

        if(classname !== null)
        {
            line.setAttributeNS(null, "class", classname);
        }
        else
        {
            line.setAttributeNS(null, "stroke", strokeColor);
            line.setAttributeNS(null, "stroke-width", strokeWidth);
        }

        document.getElementById(id).appendChild(line);
    }

    static circle(id, cx, cy, r, classname, fillColor, strokeColor, strokeWidth)
    {
        const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");

        circle.setAttributeNS(null, "cx", cx);
        circle.setAttributeNS(null, "cy", cy);
        circle.setAttributeNS(null, "r", r);

        if(classname !== null)
        {
            circle.setAttributeNS(null, "class", classname);
        }
        else
        {
            circle.setAttributeNS(null, "stroke", strokeColor);
            circle.setAttributeNS(null, "fill", fillColor);
            circle.setAttributeNS(null, "stroke-width", strokeWidth);
        }

        document.getElementById(id).appendChild(circle);
      }

    static ellipse(id, cx, cy, rx, ry, classname, fillColor, strokeColor, strokeWidth)
    {
        const ellipse = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");

        ellipse.setAttributeNS(null, "cx", cx);
        ellipse.setAttributeNS(null, "cy", cy);
        ellipse.setAttributeNS(null, "rx", rx);
        ellipse.setAttributeNS(null, "ry", ry);

        if(classname !== null)
        {
            ellipse.setAttributeNS(null, "class", classname);
        }
        else
        {
            ellipse.setAttributeNS(null, "stroke", strokeColor);
            ellipse.setAttributeNS(null, "fill", fillColor);
            ellipse.setAttributeNS(null, "stroke-width", strokeWidth);
        }

        document.getElementById(id).appendChild(ellipse);
    }

    static rectangle(id, w, h, x, y, classname, fillColor, strokeColor, strokeWidth)
    {
        const rect = document.createElementNS("http://www.w3.org/2000/svg", 'rect');

        rect.setAttributeNS(null, 'x', x);
        rect.setAttributeNS(null, 'y', y);
        rect.setAttributeNS(null, 'height', h);
        rect.setAttributeNS(null, 'width', w);

        if(classname !== null)
        {
            rect.setAttributeNS(null, "class", classname);
        }
        else
        {
            rect.setAttributeNS(null, 'fill', fillColor);
            rect.setAttributeNS(null, 'stroke', strokeColor);
            rect.setAttributeNS(null, 'stroke-width', strokeWidth);
        }

        document.getElementById(id).appendChild(rect);
    }

    static text(id, x, y, text, classname, fontFamily, fontSize, fontStyle, fontWeight, fillColor, strokeColor, strokeWidth)
    {
        const txt = document.createElementNS("http://www.w3.org/2000/svg", "text");

        txt.setAttributeNS(null, "x", x);
        txt.setAttributeNS(null, "y", y);

        if(classname !== null)
        {
            txt.setAttributeNS(null, "class", classname);
        }
        else
        {
            txt.setAttributeNS(null, 'stroke', strokeColor);
            txt.setAttributeNS(null, "fill", fillColor);
            txt.setAttributeNS(null, "font-family", fontFamily);
            txt.setAttributeNS(null, "font-size", fontSize);
            txt.setAttributeNS(null, "font-style", fontStyle);
            txt.setAttributeNS(null, "font-weight", fontWeight);
            txt.setAttributeNS(null, 'stroke-width', strokeWidth);
        }

        const textNode = document.createTextNode(text);
        txt.appendChild(textNode);
        document.getElementById(id).appendChild(txt);
    }

    static getStyleElement(id)
    {
        const svgelement = document.getElementById(id);
        let styleelement = svgelement.getElementsByTagName("style").item(0);

        if(styleelement === null)
        {
            svgelement.appendChild(document.createElement('style'));
            styleelement = svgelement.getElementsByTagName("style").item(0);
        }

        return styleelement;
    }

    static addLineClass(id, name, strokeColor, strokeWidth)
    {
        let classstring = `line.${name}{stroke: ${strokeColor}; stroke-width: ${strokeWidth}px;}`;

        const styleelement = this.getStyleElement(id);

        styleelement.appendChild(document.createTextNode(classstring));
    }

    static addCircleClass(id, name, strokeColor, strokeWidth, fillColor)
    {
        let classstring = `circle.${name}{stroke: ${strokeColor}; stroke-width: ${strokeWidth}px; fill: ${fillColor};}`;

        const styleelement = this.getStyleElement(id);

        styleelement.appendChild(document.createTextNode(classstring));
    }

    static addEllipseClass(id, name, strokeColor, strokeWidth, fillColor)
    {
        let classstring = `ellipse.${name}{stroke: ${strokeColor}; stroke-width: ${strokeWidth}px; fill: ${fillColor};}`;

        const styleelement = this.getStyleElement(id);

        styleelement.appendChild(document.createTextNode(classstring));
    }

    static addRectangleClass(id, name, strokeColor, strokeWidth, fillColor)
    {
        let classstring = `rect.${name}{stroke: ${strokeColor}; stroke-width: ${strokeWidth}px; fill: ${fillColor};}`;

        const styleelement = this.getStyleElement(id);

        styleelement.appendChild(document.createTextNode(classstring));
    }

    static addTextClass(id, name, strokeColor, strokeWidth, fillColor, fontFamily, fontSize, fontStyle, fontWeight)
    {
        let classstring = `text.${name}
                           {stroke: ${strokeColor}; stroke-width: ${strokeWidth}px; fill: ${fillColor};
                               font-family: ${fontFamily}; font-size: ${fontSize}px;
                            font-style: ${fontStyle}; font-weight: ${fontWeight}}`;

        const styleelement = this.getStyleElement(id);

        styleelement.appendChild(document.createTextNode(classstring));
    }
}

The library assumes the existence of one or more SVG elements on the page, each with an id attribute. This id is passed as an argument to each of the functions; the class therefore has no state and merely works on the element passed to each method.

fill

Here we simply set the background color to the required value.

line, rectangle, circle, ellipse, text

These methods create an element of the appropriate type and then either set their class if the classname argument is not null or their appearance attributes from the method arguments if classname is null. The new element is then added as a child of the parent SVG element.

clear

This method simply empties the SVG element.

getStyleElement

This function returns the style element of the SVG element, creating and appending it if it does not already exist.

addLineClass, addCircleClass, addEllipseClass, addRectangleClass, addTextClass

These five methods add a class to the SVG element's style. They all work in the same way but are slightly different to allow for the requirements of each element type.

The following file contains a few functions to try out the library.

svglibrary_demo.js

window.onload = function()
{
    classes();

    // randomPattern();
}


function classes()
{
    const w = document.getElementById("svgdiv").offsetWidth;
    const h = document.getElementById("svgdiv").offsetHeight;

    SVGLibrary.fill("svg1", "#8080FF");

    SVGLibrary.addLineClass("svg1", "redline", "#FF0000", 8);
    SVGLibrary.line("svg1", 16, h - 16, w - 16, 16, "redline");

    SVGLibrary.addEllipseClass("svg1", "blueellipse", "#0000A0", 6, "#0000FF");
    SVGLibrary.ellipse("svg1", w / 2, h / 2, (w / 3), h / 3, "blueellipse");

    SVGLibrary.addCircleClass("svg1", "greencircle", "#008000", 4, "#00FF00");
    SVGLibrary.circle("svg1", w / 2, h / 2, Math.min(w, h)  / 4, "greencircle");

    SVGLibrary.addRectangleClass("svg1", "orangerect", "#FF8000", 2, "#FFC000");
    SVGLibrary.rectangle("svg1", w / 8, h / 8, (w / 2) - ((w / 8) / 2), (h / 2) - ((h / 8) / 2), "orangerect");

    SVGLibrary.addTextClass("svg1", "purpletext", "#800080", 2, "#C000C0", "serif", 64, "italic", "normal");
    SVGLibrary.text("svg1", 16, 72, "SVG", "purpletext");
}


function randomPattern()
{
    const w = document.getElementById("svgdiv").offsetWidth;
    const h = document.getElementById("svgdiv").offsetHeight;

    SVGLibrary.fill("svg1", randomColor());

    const functions = [randomRectangle, randomEllipse, randomCircle];

    const shapeCount = randomBetween(128, 256);

    for(let i = 0; i < shapeCount; i++)
    {
        functions[randomBetween(0, 2)](w, h);
    }
}


function randomBetween(min, max)
{
    return Math.floor(Math.random() * (max - min + 1) + min);
}


function randomColor()
{
    const r = randomBetween(0, 255);
    const g = randomBetween(0, 255);
    const b = randomBetween(0, 255);

    return `rgb(${r}, ${g}, ${b})`;
}


function randomRectangle(w, h)
{
    const fillColor = randomColor();
    const strokeColor = randomColor();
    const width = randomBetween(16, 64);
    const height = randomBetween(16, 64);
    const x  = randomBetween(0, w);
    const y  = randomBetween(0, h);

    SVGLibrary.rectangle("svg1", width, height, x, y, null, fillColor, strokeColor, 1);
}


function randomEllipse(w, h)
{
    const fillColor = randomColor();
    const strokeColor = randomColor();
    const rx = randomBetween(8, 32);
    const ry = randomBetween(8, 32);
    const cx  = randomBetween(0, w);
    const cy  = randomBetween(0, h);

    SVGLibrary.ellipse("svg1", cx, cy, rx, ry, null, fillColor, strokeColor, 1);
}


function randomCircle(w, h)
{
    const fillColor = randomColor();
    const strokeColor = randomColor();
    const r = randomBetween(8, 32);
    const cx  = randomBetween(0, w);
    const cy  = randomBetween(0, h);

    SVGLibrary.circle("svg1", cx, cy, r, null, fillColor, strokeColor, 1);
}

window.onload

Here we simply call the following classes function, although you can edit it to call the randomPattern function if you wish.

classes

This function adds a class for each element type, and then adds an element of that type, using the newly added classes.

(The other functions are carried over from version 1.0, but have been edited to pass null as the classname argument.)

Open svglibrary.htm in your browser; this is a simple demonstration of the element-creating methods using classes.