--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>SVG and Koch's Fractal</title>
+ <script type="text/javascript" src="koch.js"></script>
+ </head>
+<body>
+ <h1> Koch's Snowflake </h1>
+ <p> An example of using the DOM to make a fractal --- an interactive document.</p>
+ <p> <b>Warning:</b> If you iterate too many times you will likely crash your browser </p>
+ <svg
+ id="kochSVG"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="400"
+ height="400"
+ >
+ <path
+ id="line"
+ style="stroke:#000000; fill:none; stroke-width:1px;"
+ d = "M 100,100 300,100 200,273.2051 100,100"
+ />
+ </svg>
+ <p></p>
+ <table>
+ <tr> <td> Inwards <input type="radio" name="dir" id="dir_in"/> Outwards <input type="radio" name="dir" value="dir_out" checked="yes"/> </td> </tr>
+ <tr> <td> Insert <input type="radio" name="mode" id="mode_insert" checked="yes"/> Append <input type="radio" name="mode" id="mode_append"/> </td> </tr>
+ <tr> <td> <input type="text" value="1" id="iterations"/> <button onclick="iterateKoch();">Koch Iterate</button> </td> </tr>
+ <tr> <td> <input type="text" value="#000000" id="stroke"/> <button onclick="stroke();">Stroke Colour</button> </td> </tr>
+ <tr> <td> <input type="text" value="none" id="fill"> <button onclick="fill();">Fill Colour</button> </td> </tr>
+ <tr> <td> <input type="text" value="1" id="stroke-width"/> <button onclick="strokeWidth();">Stroke Thickness</button> </td> </tr>
+ <tr> <td><button onclick="reset();">Reset</button> <button onclick="svgToText();">Standalone SVG</button></td></tr>
+ </table>
+ <p id="debug"></p>
+</body>
+</html>
--- /dev/null
+/**
+ * This code will perform the koch snowflake iteration on svg paths
+ * Wierd things might happen if the path isn't a straight line path
+ */
+
+
+function koch(direction, mode)
+{
+ var svgs = document.getElementsByTagName("svg");
+ for (var i = 0; i < svgs.length; ++i)
+ {
+ var paths = svgs[i].getElementsByTagName("path");
+ for (var j = 0; j < paths.length; ++j)
+ {
+ var d = paths[j].getAttribute("d").split(/[\s,]+/);
+ var x = [];
+ var y = [];
+ for (var k = 0; k < d.length; ++k)
+ {
+ var asfloat = parseFloat(d[k]);
+ if (isNaN(asfloat)) continue;
+ var coord = (y.length == x.length) ? x : y;
+ coord.push(asfloat);
+ }
+ var result = "M";
+ for (var k = 0; k < x.length-1; ++k)
+ {
+ var s = [x[k+1]-x[k], y[k+1]-y[k]];
+ var dist = Math.pow(Math.pow(s[0],2) + Math.pow(s[1],2),1/2);
+ var n = [-s[1]/dist, s[0]/dist]; // normal vector
+ var a = [0,0];
+ var b = [0,0];
+ var c = [0,0];
+ for (var ii = 0; ii < 2; ++ii)
+ {
+ var p = (ii == 0 ? x : y);
+ a[ii] = p[k] + s[ii]/3;
+ b[ii] = p[k] + 2*s[ii]/3;
+ if (direction == "in")
+ {
+ c[ii] = p[k] + s[ii]/2 + dist/3 * n[ii];
+ }
+ else if (direction == "out")
+ {
+ c[ii] = p[k] + s[ii]/2 - dist/3 * n[ii];
+ }
+ }
+
+ result += " " + x[k]+","+y[k] + " "+a.join(",") + " " + c.join(",") + " " + b.join(",");
+ if (mode == "append")
+ result += " " + a.join(",") + " " + b.join(",");
+
+
+ }
+ result += " " + x[x.length-1]+","+y[x.length-1];
+
+
+ //document.getElementById("debug").innerHTML = paths[j].getAttribute("d") + " to " + result;
+ paths[j].setAttribute("d", result);
+ }
+ }
+}
+
+/** Helper lets us repeat the iteration **/
+function iterateKoch()
+{
+ var iterations = parseFloat(document.getElementById("iterations").value);
+ var direction = (document.getElementById("dir_in").checked) ? "in" : "out";
+ var mode = (document.getElementById("mode_insert").checked) ? "insert" : "append";
+ if (!isNaN(iterations))
+ {
+ for (var i = 0; i < iterations; ++i) koch(direction, mode);
+ }
+}
+
+/** Change stroke thickness **/
+function strokeWidth()
+{
+ var thickness = parseFloat(document.getElementById("stroke-width").value);
+ if (isNaN(thickness)) return;
+
+ var svgs = document.getElementsByTagName("svg");
+ for (var i = 0; i < svgs.length; ++i)
+ {
+ var paths = svgs[i].getElementsByTagName("path");
+ for (var j = 0; j < paths.length; ++j)
+ {
+ paths[j].style.strokeWidth = thickness+"px";
+ }
+ }
+}
+
+
+/** Change fill **/
+function fill()
+{
+ var fill = document.getElementById("fill").value;
+
+ var svgs = document.getElementsByTagName("svg");
+ for (var i = 0; i < svgs.length; ++i)
+ {
+ var paths = svgs[i].getElementsByTagName("path");
+ for (var j = 0; j < paths.length; ++j)
+ {
+ paths[j].style.fill = fill;
+ }
+ }
+}
+
+/** Change stroke colour **/
+function stroke()
+{
+ var stroke = document.getElementById("stroke").value;
+
+ var svgs = document.getElementsByTagName("svg");
+ for (var i = 0; i < svgs.length; ++i)
+ {
+ var paths = svgs[i].getElementsByTagName("path");
+ for (var j = 0; j < paths.length; ++j)
+ {
+ paths[j].style.stroke = stroke;
+ }
+ }
+}
+
+function reset()
+{
+ document.getElementById("line").setAttribute("d", "M 100,100 300,100 200,273.2051 100,100");
+ document.getElementById("line").setAttribute("style", "stroke:#000000; fill:none; stroke-width:1px;");
+}
+
+function svgToText()
+{
+ var data = "<svg id=\"kochSVG\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"400\" height=\"400\">";
+ data += "<path id=\"line\" style=\"stroke:"+document.getElementById("stroke").value+"; fill:"+document.getElementById("fill").value+"; stroke-width:"+document.getElementById("stroke-width").value+"px;\" d=\""+document.getElementById("line").getAttribute("d")+"\"/>";
+ data += "</svg>"
+ var win = window.open("image/svg+xml");
+ win.document.write(data);
+ win.focus();
+}