<!--
    Demo for this article:
    http://blustemy.io/making-svg-patterns-with-javascript/
-->

<svg id="illustration"
     width="768" height="340" viewBox="0 0 768 340"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
    <symbol id="triangle" viewBox="0 0 100 100">
        <polygon points="0,100 100,100 50,0"/>
    </symbol>
    <rect width="768" height="340" fill="#1098ad"/>
</svg>

<p>
    <button type="button" class="button-redraw">Redraw</button>
    <button type="button" class="button-clear">Clear</button>
    <a href="#" class="link-download">Download generated SVG</a>
</p>
/*
    Demo for this article:
    http://blustemy.io/making-svg-patterns-with-javascript/
*/

svg {
    /* Make sure browsers don't draw anything outside the <svg> element */
    overflow: hidden;
}
/*
    Demo for this article:
    http://blustemy.io/making-svg-patterns-with-javascript/
*/

class Patterns {
    constructor({ svg, symbol }) {
        this.svgElement = svg;
        this.symbolElement = symbol;
        this.symbolLink = `#${symbol.id}`;
    }
    
    static get svgNamespace() {
        return "http://www.w3.org/2000/svg";
    }
    
    static get xlinkNamespace() {
        return "http://www.w3.org/1999/xlink";
    }
    
    /* Return a random integer between min (included) and max (excluded). */
    static getRandomInt(min, max) {
        const minInt = Math.ceil(min),
              maxInt = Math.floor(max);
        return Math.floor(Math.random() * (maxInt - minInt)) + minInt;
    }
    
    /* Return a random number between min (inclusive) and max (exclusive). */
    static getRandomArbitrary(min, max) {
        return Math.random() * (max - min) + min;
    }
    
    addRandomSymbol(parentNode, fill = "#000000", opacity = 0.5) {
        const useElement = document.createElementNS(Patterns.svgNamespace, "use"),
              width = this.symbolElement.viewBox.baseVal.width,
              height = this.symbolElement.viewBox.baseVal.height,
              x = Patterns.getRandomArbitrary(0, this.svgElement.viewBox.baseVal.width),
              y = Patterns.getRandomArbitrary(0, this.svgElement.viewBox.baseVal.height),
              angle = Patterns.getRandomArbitrary(0, 360),
              scale = Patterns.getRandomArbitrary(1, 4);
        useElement.setAttributeNS(Patterns.xlinkNamespace, "xlink:href", this.symbolLink);
        useElement.setAttribute("width", `${width}`);
        useElement.setAttribute("height", `${height}`);
        useElement.setAttribute("fill", fill);
        useElement.setAttribute("fill-opacity", `${opacity}`);
        useElement.setAttribute("transform", `translate(${x} ${y}) scale(${scale}) rotate(${angle})`);
        parentNode.appendChild(useElement);
    }
    
    drawRandomSymbols(n = 10, fill = "#000000", opacity = 0.5) {
        // Prepare a group element containing all the symbol instances.
        const gElement = document.createElementNS(Patterns.svgNamespace, "g");
        for (let i = 0; i < n; i++) {
            this.addRandomSymbol(gElement, fill, opacity);
        }
        gElement.classList.add("patterns");
        
        // Add the group.
        this.svgElement.appendChild(gElement);
    }
    
    clearSymbols() {
        const gElements = this.svgElement.querySelectorAll("g.patterns");
        for (let i = 0; i < gElements.length; i++) {
            this.svgElement.removeChild(gElements[i]);
        }
    }
    
    get svgString() {
        return this.svgElement.outerHTML;
    }
    
    exportAsSvgFile(clickedLinkElement) {
        const blob = new Blob([this.svgString], {
                  type: "image/svg+xml"
              }),
              url = window.URL.createObjectURL(blob);
        
        clickedLinkElement.target = "_blank";
        clickedLinkElement.download = "Patterns.svg";
        clickedLinkElement.href = url;
    }
}

document.addEventListener("DOMContentLoaded", () => {
    const patterns = new Patterns({
        svg: document.getElementById("illustration"),
        symbol: document.getElementById("triangle")
    });
    
    patterns.drawRandomSymbols(40, "#000000", 0.15);
    patterns.drawRandomSymbols(30, "#ffffff", 0.4);
    
    document.querySelector(".button-redraw").addEventListener("click", () => {
        patterns.clearSymbols();
        patterns.drawRandomSymbols(40, "#000000", 0.15);
        patterns.drawRandomSymbols(30, "#ffffff", 0.4);
    });
    
    document.querySelector(".button-clear").addEventListener("click", () => {
        patterns.clearSymbols();
    });
    
    document.querySelector(".link-download").addEventListener("click", (evt) => {
        patterns.exportAsSvgFile(evt.target);
    });
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.