214 lines
7.9 KiB
HTML
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>
|