sufograph/index.html
2017-07-21 07:21:10 -05:00

214 lines
7.9 KiB
HTML

<!DOCTYPE html>
<!--
Copyright © 2017 Jeff Epler <jepler@unpythonic.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-->
<html>
<head>
<title>SuFoGraph - Super Formula Guilloché patterns</title>
<meta charset="UTF-8">
<script type="text/javascript" src="main.js"></script>
<style>
body { margin: 0; padding: 0; overflow:hidden; }
svg { display: block; border: 0; position: absolute; top: 0%; left: 0%; width: 100%; height: 100%; background: #fff; }
table { position: absolute; z-index: 1; }
#showhide { position: absolute; z-index: 2; }
body.hide form { display: none; }
@media print { form, #showhide { display: none; } }
</style>
</head>
<body height="100%" id="body">
<div id="showhide" onclick="toggleshowhide()"></div>
<form>
<table>
<tr><th colspan="2">Drawn Curve</th></tr>
<tr><td>m</td><td><input type="number" name="cm" id="cm"/></td></tr>
<tr><td>n₁</td><td><input type="number" name="cn1" id="cn1"/></td></tr>
<tr><td>n₂</td><td><input type="number" name="cn2" id="cn2"/></td></tr>
<tr><td>n₃</td><td><input type="number" name="cn3" id="cn3"/></td></tr>
<tr><td>scale</td><td><input type="number" name="cscale" id="cscale"/></td></tr>
<tr><th colspan="2">Translating Curve</th></tr>
<tr><td>m</td><td><input type="number" name="sm" id="sm"/></td></tr>
<tr><td>n₁</td><td><input type="number" name="sn1" id="sn1"/></td></tr>
<tr><td>n₂</td><td><input type="number" name="sn2" id="sn2"/></td></tr>
<tr><td>n₃</td><td><input type="number" name="sn3" id="sn3"/></td></tr>
<tr><td>scale</td><td><input type="number" name="sscale" id="sscale"/></td></tr>
<tr><th colspan="2">Offset Properties</th></tr>
<tr><td>repetitions</td><td><input type="number" name="n" id="nn"/></td></tr>
<tr><td>rotations</td><td><input type="number" name="r" id="rr"/></td></tr>
<tr><td>show paths</td><td><input type="checkbox" name="showpath" id="showpath"/></td></tr>
<tr><td><input type="button" onclick="update()" value="Update"></td><td><a id="view">View</a> or <a download="sufo.svg" id="dl">Download SVG</a></tr>
<tr><th colspan="2">What is …</th></td>
<tr><th colspan="2"><a href="https://en.wikipedia.org/wiki/Superformula">Superformula</a></td></tr>
<tr><th colspan="2"><a href="https://en.wikipedia.org/wiki/Guilloch%C3%A9">Guilloché</a></td></tr>
<tr><td colspan="2"><a href="https://github.com/jepler/sufograph">source on github</a></th></td>
</table>
</form>
<svg id="s" preserveAspectRatio="xMaxYMid meet">
<defs>
<path id="p" fill="none" stroke="inherit"/>
</defs>
<g id="g"/>
<g id="h" stroke-width="3px"/>
</svg>
<script>
var c = new Curve(1, 1, 3, 5, 18, 18, 100);
var s = new Curve(1, 1, 3, 2, 8, 3, 100);
var r = 1
var n = 200
var showpath = 0
var main = function (c, s, r, n) {
document.getElementById("p").setAttribute("d", c.svgpath(128))
var cmr = c.maxr(256), sbbox = s.bbox(256)
var x0 = sbbox[0] - cmr,
y0 = sbbox[1] - cmr,
x1 = sbbox[2] + cmr,
y1 = sbbox[3] + cmr;
var dx = x1-x0, dy = y1-y0;
x0 -= .05*dx; y0 -= .05*dy
dx *= 1.10; dy *= 1.10
document.getElementById("s").setAttribute("viewBox",
fix(x0) + " " + fix(y0) + " " + fix(dx) + " " + fix(dy) )
var g = document.getElementById("g")
var html = ''
s.preppathlen(4*n)
for(var i=0; i<n; i++) {
var xy = s.xypathlen(i / n);
var rr = 360 * r * i / n
html += "<use xlink:href=\"#p\" fill=\"none\" stroke=\"black\" transform=\"translate(" + fix(xy[0]) + "," + fix(xy[1]) + ") rotate(" + fix(rr) + ")\"/>"
}
g.innerHTML = html
if(showpath) {
var sxy = s.xypathlen(0);
var cxy = c.xypathlen(0);
document.getElementById("h") .innerHTML = (
"<use transform=\"translate(" + fix(sxy[0]) + "," + fix(sxy[1]) +")\"xlink:href=\"#p\" fill=\"none\" stroke=\"blue\"/>"
+ "<path fill=\"none\" stroke=\"red\" d=\"" + s.svgpath(128) + "\"/>"
+ "<line x1=\"" + fix(sxy[0]) + "\" y1=\"" + fix(sxy[1]) + "\" x2=\"" + fix(cxy[0]+sxy[0]) + "\" y2=\"" + fix(cxy[1]+sxy[1]) + "\" stroke=\"green\">"
)
} else
document.getElementById("h") .innerHTML = ""
var svg = document.getElementById("s")
var pre = ("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" "
+ "xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\""
+ svg.getAttribute('viewBox') +"\" preserveAspectRatio=\"xMidYMid meet\">")
var post = "</svg>"
document.getElementById("dl").setAttribute("href", todatauri(pre + svg.innerHTML + post, "image/svg+xml"))
document.getElementById("view").setAttribute("href", todatauri(pre + svg.innerHTML + post, "image/svg+xml"))
}
var urlParams;
(window.onpopstate = function () {
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
query = window.location.hash.substring(1);
urlParams = {};
while (match = search.exec(query))
urlParams[decode(match[1])] = decode(match[2]);
})();
var getform_putquery = function(id) {
var el = document.getElementById(id)
var v;
if(el.type == "checkbox") {
v = el.checked;
} else {
v = Number(document.getElementById(id).value)
}
urlParams[id] = v
updatequery()
return v;
}
var updatequery = function() {
var hash = ""
for(var k in urlParams) {
if(hash) hash += "\x26"
hash += k + "=" + urlParams[k]
}
document.location.hash = hash // (does not call onpopstate as side effect)
}
var getquery_putform = function(id, v) {
v = Number(urlParams[id] || v)
var el = document.getElementById(id)
if(el.type == "checkbox") {
el.checked = v == "true";
} else {
el.value = v
}
return v
}
s.m = getquery_putform("sm", s.m)
s.n1 = getquery_putform("sn1", s.n1)
s.n2 = getquery_putform("sn2", s.n2)
s.n3 = getquery_putform("sn3", s.n3)
s.scale = getquery_putform("sscale", s.scale)
c.m = getquery_putform("cm", c.m)
c.n1 = getquery_putform("cn1", c.n1)
c.n2 = getquery_putform("cn2", c.n2)
c.n3 = getquery_putform("cn3", c.n3)
c.scale = getquery_putform("cscale", c.scale)
r = getquery_putform("rr", r)
n = getquery_putform("nn", n)
showpath = getquery_putform("showpath", showpath)
main(c,s,r,n)
var update = function() {
s.m = getform_putquery("sm")
s.n1 = getform_putquery("sn1")
s.n2 = getform_putquery("sn2")
s.n3 = getform_putquery("sn3")
s.scale = getform_putquery("sscale")
c.m = getform_putquery("cm")
c.n1 = getform_putquery("cn1")
c.n2 = getform_putquery("cn2")
c.n3 = getform_putquery("cn3")
c.scale = getform_putquery("cscale")
r = getform_putquery("rr")
n = getform_putquery("nn")
showpath = getform_putquery("showpath")
main(c, s, r, n)
}
var showstate = (urlParams['ui'] || "true") == "true";
var syncshowstate = function() {
if(showstate) { document.getElementById("body").setAttribute("class", ""); document.getElementById("showhide").innerHTML = "«"; }
else { document.getElementById("body").setAttribute("class", "hide"); document.getElementById("showhide").innerHTML = "»"; }
}
var toggleshowhide = function() {
showstate = !showstate
urlParams["ui"] = showstate
syncshowstate();
updatequery();
}
syncshowstate();
</script>
</div>
</body>
</html>