Saturday, January 9, 2010

Snowflake SVG developer release

Recently, I have been learning SVG scripting by porting my old branching-web AS3 script to Javascript. This time around, I wanted to remedy some of the shortcomings of the previous incarnation. Here's a list of some of my goals and how they turned out.

Goals

  • Allow the user to customize each node individually, but don't add too much complexity.

    Success. The interface has become slightly more complex, but it's still relatively simple.

  • Let a node have only one child, allowing the user to taper the branches.

    Success. This effect is highly useful for creating snowflake patterns.

  • Improve the demo interface, enabling interactive editing of each node.

    Pending. I plan to tackle this feature next.

Demos

Classic snowflake

Screenshot of a classic snowflake drawn by my library
Click to view as SVG.


function startup(evt) {
    var svgDocument = evt.target.ownerDocument;
    
    var rect = svgDocument.createElementNS(svgNamespace, 'rect');
    rect.setAttributeNS(null, 'fill', 'skyblue');
    rect.setAttributeNS(null, 'width', '100%');
    rect.setAttributeNS(null, 'height', '100%');
    svgDocument.documentElement.appendChild(rect);
    
    var endPoint = createDataNode(0, 0, 0, []);
    var endCap = createDataNode(0, 5, 10, [endPoint]);
    var middleNode = createDataNode(60, 50, 10, [endCap, endCap, endCap]);
    var centerNode = createDataNode(360, 30, 10, [middleNode, middleNode, middleNode, middleNode, middleNode, middleNode]);
    
    var web = createWeb(centerNode, createPoint(0, 0), 0);
    
    var snowflake = createSnowflake(web);
    
    var snowflakeSVG = snowflake.toSVG(svgDocument);
    snowflakeSVG.setAttributeNS(null, 'fill', '#fff');
    snowflakeSVG.setAttributeNS(null, 'transform', 'translate(250 250)');
    svgDocument.documentElement.appendChild(snowflakeSVG);
}

Gothic cross snowflake

Screenshot of a gothic snowflake drawn by my library
Click to view as SVG.


function startup(evt) {

    var svgDocument = evt.target.ownerDocument;
    
    outerPoint = createDataNode(0, 0, 0, []);
    
    taperFork = createDataNode(0, 5, 10, [outerPoint]);
    
    bigFork = createDataNode(180, 25, 10, [taperFork, taperFork, taperFork]);
    
    nextFork = createDataNode(180, 25, 10, [taperFork, bigFork, taperFork]);
    
    innerFork = createDataNode(360, 15, 10, [nextFork, nextFork, nextFork, nextFork]);
    
    var web = createWeb(innerFork, createPoint(0, 0), 0);
    
    var snowflake = createSnowflake(web, innerFork);
    
    var snowflakeSVG = snowflake.toSVG(svgDocument);
    snowflakeSVG.setAttributeNS(null, 'transform', 'translate(250 250)');
    svgDocument.documentElement.appendChild(snowflakeSVG);
}

Nodes displayed as points

Screenshot of a web of nodes drawn by my library
Click to view as SVG


function startup(evt) {

    var svgDocument = evt.target.ownerDocument;
    
    var endPoint = createDataNode(0, 0, 0, []);
    var middleNode = createDataNode(180, 50, 0, [endPoint, endPoint, endPoint, endPoint]);
    var originNode = createDataNode(360, 50, 0, [middleNode, middleNode, middleNode, middleNode]);
    
    var web = createWeb(originNode, createPoint(0, 0), 0);
    var webSVG = web.toSVG(svgDocument);
    webSVG.setAttributeNS(null, 'transform', 'translate(250 250)');
    svgDocument.documentElement.appendChild(webSVG);
}

Download

I've packaged up all the necessary scripts and SVGs into one tiny .zip archive for your hacking pleasure. If you'd like to see what I'm working on next (and possibly help), you can view my Google Code project repository. Everything is licensed under the Apache 2.0 license, so you can use it in a proprietary application, modify it in any way you choose, or pass it to all your friends provided you indicate where it initially came from. If you do anything interesting with it, tell me about it. Happy hacking!