Last active
September 6, 2019 11:04
-
-
Save ia7ck/4b39ce1d14bd0e60fecc9c8fe8e04934 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<title>ABC108/ARC102 D</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.5/svg.js"></script> | |
<script src="./svg.path.js"></script> | |
<link href="https://fonts.googleapis.com/css?family=Inconsolata|Lato:400,400i" rel="stylesheet"> | |
</head> | |
<body> | |
<h3>ABC108/ARC102 D</h3> | |
<form id="input-form"> | |
<input name="l" type="number" min="2" max="256" /> | |
<button name="button" type="submit">set</button> | |
</form> | |
<form id="go-form"> | |
<button name="button" type="submit">go</button> | |
</form> | |
<div id="drawing0"> | |
</div> | |
<div id="drawing"> | |
</div> | |
<script defer src="./index.js"></script> | |
</body> | |
<style> | |
body { | |
font-family: "Lato", sans-serif; | |
} | |
button, | |
input { | |
font-family: inherit; | |
font-size: 100%; | |
} | |
form { | |
padding: .3rem 0 .3rem 0; | |
} | |
input[type="number"] { | |
min-width: 5rem; | |
} | |
</style> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const W = 800, H = 400; | |
const draw0 = SVG("drawing0").size(W, H / 4).style({ border: "solid 1px" }); | |
const draw = SVG("drawing").size(W, H).style({ border: "solid 1px" }); | |
const radius = 12; | |
const h = 50, span = 100; | |
const TEXT_SIZE = 14; | |
const BASE_TIMEOUT = 1000; | |
let timeout = BASE_TIMEOUT; | |
let L = randInt(2, 256); | |
let digit = encode(L); | |
let idx = 1; | |
let firstNode = { | |
circle: draw.circle(radius * 2).center(radius * 4, h).fill("none").stroke("black"), | |
text: mytext("1").move(radius * 4, h).dy(-TEXT_SIZE / 1.9), | |
} | |
let nodes = [firstNode]; | |
let edges = []; | |
let l = 1, ad = 1; | |
init(L); | |
function init(_L) { | |
L = _L; | |
digit = encode(L); | |
draw0.clear(); | |
draw0.text("L").font({ family: "Lato", size: TEXT_SIZE * 1.8, style: "oblique" }).move(radius * 4, H / 15); | |
draw0.text("L'").font({ family: "Lato", size: TEXT_SIZE * 1.8, style: "oblique" }).move(radius * 4, H / 15 + TEXT_SIZE * 1.8); | |
for (let i = 0; i < digit.length; i++) { | |
digit[i] = { | |
val: digit[i], | |
textGoal: draw0.text(String(digit[i])).font({ family: "Inconsolata", size: TEXT_SIZE * 1.8 }).move(radius * 4 + (i + 3) * 15, H / 15), | |
textCurrent: draw0.text(" ").font({ family: "Inconsolata", size: TEXT_SIZE * 1.8 }).move(radius * 4 + (i + 3) * 15, H / 15 + TEXT_SIZE), | |
} | |
} | |
draw.clear(); | |
idx = 1; | |
firstNode = { | |
circle: draw.circle(radius * 2).center(radius * 4, h).fill("none").stroke("black"), | |
text: mytext("1").move(radius * 4, h).dy(-TEXT_SIZE / 1.9), | |
} | |
nodes = [firstNode]; | |
edges = []; | |
l = 1; | |
ad = 1; | |
} | |
const sleep = (ms) => (new Promise(resolve => setTimeout(resolve, ms))); | |
async function suc(i) { | |
for (let edge of edges) { | |
const val = parseInt(edge.text.text(), 10); | |
edge.text.text(String(val * 2)) | |
} | |
await sleep(timeout); | |
const previousNode = nodes[nodes.length - 1]; | |
const currentNode = { | |
circle: draw.circle(radius * 2).center(previousNode.circle.cx() + span, h).fill("none").stroke("black").hide(), | |
text: mytext(String(nodes.length + 1)).attr({ visibility: "hidden" }).move(previousNode.circle.cx() + span, h).dy(-TEXT_SIZE / 1.9), | |
}; | |
nodes.push(currentNode); | |
const edge0 = { | |
path: draw.path().fill("none").stroke("black").M(previousNode.circle.cx() + radius, h).H(currentNode.circle.cx() - radius).drawAnimated(timeout).attr({ "stroke-width": 1 }), | |
text: mytext("0").move(Math.floor((previousNode.circle.cx() + currentNode.circle.cx()) / 2), h).dy(-TEXT_SIZE).attr({ visibility: "hidden" }), | |
}; | |
const first = i === 1, last = i + 1 === digit.length; | |
const edge1 = { | |
path: draw.path().fill("none").stroke("black").M(previousNode.circle.cx() + (first ? 0 : 4), h + radius).v(radius * 2).H(currentNode.circle.cx() - (last ? 0 : 4)).v(-radius * 2).drawAnimated(timeout).attr({ "stroke-width": 1 }), | |
text: mytext("1").move(Math.floor((previousNode.circle.cx() + currentNode.circle.cx()) / 2), h + radius * 2).dy(-3).attr({ visibility: "hidden" }) | |
}; | |
edges.push(edge0, edge1); | |
await sleep(timeout); | |
edge0.path.marker("end", 10, 10, (add) => { add.path().fill("none").stroke("black").M(0, 0).l(5, 5).l(-5, 5) }) | |
edge1.path.marker("end", 10, 10, (add) => { add.path().fill("none").stroke("black").M(0, 0).l(5, 5).l(-5, 5) }) // ??? | |
currentNode.circle.show(); | |
currentNode.text.attr({ visibility: "visible" }); | |
edge0.text.attr({ visibility: "visible" }) | |
edge1.text.attr({ visibility: "visible" }) | |
l *= 2; | |
update(l); | |
if (digit[i].val) { | |
await sleep(timeout); | |
const extraEdge = { | |
path: draw.path().fill("none").stroke("black").M(firstNode.circle.cx(), firstNode.circle.cy() + radius).v(radius * 3 * (ad + 1)).H(currentNode.circle.cx() - (last ? 0 : 4)).v(-radius * 3 * (ad + 1)).drawAnimated(timeout).attr({ "stroke-width": 1 }), | |
text: mytext(String(l)).move(Math.floor((firstNode.circle.cx() + currentNode.circle.cx()) / 2), h + radius * 3 * (ad + 1)).dy(-3).attr({ visibility: "hidden" }) | |
}; | |
edges.push(extraEdge) | |
await sleep(timeout); | |
extraEdge.text.attr({ visibility: "visible" }) | |
l += 1; | |
ad += 1; | |
update(l); | |
} | |
} | |
function mytext(str) { | |
return draw.text(str).fill("black").attr({ "text-anchor": "middle" }).font({ family: "Inconsolata", size: TEXT_SIZE }); | |
} | |
function encode(x) { | |
let ret = [] | |
while (x > 0) { | |
ret.push(x & 1); | |
x = x >> 1; | |
} | |
return ret.reverse(); | |
} | |
function update(l) { | |
const _digit = encode(l); | |
while (_digit.length < digit.length) _digit.unshift(0); | |
let found = false; | |
for (let i = 0; i < _digit.length; i++) { | |
if (_digit[i]) { | |
found = true; | |
} | |
digit[i].textCurrent.text(found ? String(_digit[i]) : " "); | |
} | |
} | |
function randInt(lb, ub) { | |
return Math.floor(Math.random() * (ub - lb)) + lb; | |
} | |
const inputForm = document.getElementById("input-form"); | |
const goForm = document.getElementById("go-form"); | |
inputForm.l.value = L; | |
inputForm.addEventListener("submit", (ev) => { | |
ev.preventDefault(); | |
const val = parseInt(ev.target.l.value, 10); | |
init(val); | |
goForm.button.disabled = false; | |
}); | |
goForm.addEventListener("submit", async (ev) => { | |
ev.preventDefault(); | |
ev.target.button.disabled = true; | |
inputForm.button.disabled = true; | |
await suc(idx++); | |
if (idx < digit.length) { | |
ev.target.button.disabled = false; | |
} | |
inputForm.button.disabled = false; | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** svg.path.js - v0.6.0 - 2014-08-15 | |
* http://otm.github.io/svg.path.js/ | |
* Copyright (c) 2014 Nils Lagerkvist; Licensed under the MIT license / | |
*/ | |
(function () { | |
var slice = Function.prototype.call.bind(Array.prototype.slice); | |
SVG.extend(SVG.Path, { | |
M: function (p) { | |
p = (arguments.length === 1) ? [p.x, p.y] : slice(arguments); | |
this.addSegment('M', p, this._redrawEnabled); | |
if (this._segments.length === 1) { | |
return this.plot('M' + p[0] + ' ' + p[1]); | |
} | |
return this; | |
}, | |
m: function (p) { | |
p = (arguments.length === 1) ? [p.x, p.y] : slice(arguments); | |
this.addSegment('m', p, this._redrawEnabled); | |
if (this._segments.length === 1) { | |
return this.plot('m' + p[0] + ' ' + p[1]); | |
} | |
return this; | |
}, | |
// TODO: Solve | |
L: function (p) { | |
p = (arguments.length === 1) ? [p.x, p.y] : slice(arguments); | |
return this.addSegment('L', p, this._redrawEnabled); | |
}, | |
l: function (p) { | |
p = (arguments.length === 1) ? [p.x, p.y] : slice(arguments); | |
return this.addSegment('l', p, this._redrawEnabled); | |
}, | |
H: function (x) { | |
return this.addSegment('H', [x], this._redrawEnabled); | |
}, | |
h: function (x) { | |
return this.addSegment('h', [x], this._redrawEnabled); | |
}, | |
V: function (y) { | |
return this.addSegment('V', [y], this._redrawEnabled); | |
}, | |
v: function (y) { | |
return this.addSegment('v', [y], this._redrawEnabled); | |
}, | |
C: function (p1, p2, p) { | |
p = (arguments.length === 3) ? [p1.x, p1.y, p2.x, p2.y, p.x, p.y] : slice(arguments); | |
return this.addSegment('C', p, this._redrawEnabled); | |
}, | |
c: function (p1, p2, p) { | |
p = (arguments.length === 3) ? [p1.x, p1.y, p2.x, p2.y, p.x, p.y] : slice(arguments); | |
return this.addSegment('c', p, this._redrawEnabled); | |
}, | |
S: function (p2, p) { | |
p = (arguments.length === 2) ? [p2.x, p2.y, p.x, p.y] : slice(arguments); | |
return this.addSegment('S', p, this._redrawEnabled); | |
}, | |
s: function (p2, p) { | |
p = (arguments.length === 2) ? [p2.x, p2.y, p.x, p.y] : slice(arguments); | |
return this.addSegment('s', p, this._redrawEnabled); | |
}, | |
// Q x1 y1, x y | |
Q: function (p1, p) { | |
p = (arguments.length === 2) ? [p1.x, p1.y, p.x, p.y] : slice(arguments); | |
return this.addSegment('Q', p, this._redrawEnabled); | |
}, | |
q: function (p1, p) { | |
p = (arguments.length === 2) ? [p1.x, p1.y, p.x, p.y] : slice(arguments); | |
return this.addSegment('q', p, this._redrawEnabled); | |
}, | |
T: function (p) { | |
p = (arguments.length === 1) ? [p.x, p.y] : slice(arguments); | |
return this.addSegment('T', p, this._redrawEnabled); | |
}, | |
t: function (p) { | |
p = (arguments.length === 1) ? [p.x, p.y] : slice(arguments); | |
return this.addSegment('t', p, this._redrawEnabled); | |
}, | |
A: function (rx, ry, xAxisRotation, largeArcFlag, sweepFlag, p) { | |
p = (arguments.length === 6) ? [rx, ry, xAxisRotation, largeArcFlag, sweepFlag, p.x, p.y] : slice(arguments); | |
return this.addSegment('A', p, this._redrawEnabled); | |
}, | |
a: function (rx, ry, xAxisRotation, largeArcFlag, sweepFlag, p) { | |
p = (arguments.length === 6) ? [rx, ry, xAxisRotation, largeArcFlag, sweepFlag, p.x, p.y] : slice(arguments); | |
return this.addSegment('a', p, this._redrawEnabled); | |
}, | |
Z: function () { | |
return this.addSegment('Z', [], this._redrawEnabled); | |
}, | |
// TODO: Add check that first element is moveto | |
addSegment: function (movement, coordinates, redraw) { | |
var segment = { | |
type: movement, | |
coords: coordinates | |
}; | |
if (!this._segments) { | |
this._segments = []; | |
} | |
this._segments.push(segment); | |
if (redraw !== false) { | |
this._drawSegment(segment); | |
} | |
return this; | |
}, | |
clearPath: function () { | |
if (this._segments) { | |
this._segments.length = 0; | |
} | |
this._lastSegment = null; | |
return this.plot(); | |
}, | |
getSegmentCount: function () { | |
return this._segments.length; | |
}, | |
getSegment: function (index) { | |
return this._segments[index]; | |
}, | |
removeSegment: function (index) { | |
this._segments.splice(index, 1); | |
return this.redraw(); | |
}, | |
replaceSegment: function (index, segment) { | |
this._segments.splice(index, 1, segment); | |
return this.redraw(); | |
}, | |
/** | |
* Easing: | |
* <>: ease in and out | |
* >: ease out | |
* <: ease in | |
* -: linear | |
* =: external control | |
* a function | |
*/ | |
drawAnimated: function (options) { | |
options = options || {}; | |
options.duration = options.duration || '1000'; | |
options.easing = options.easing || '<>'; | |
options.delay = options.delay || 0; | |
var length = this.length(); | |
this.stroke({ | |
width: 2, | |
dasharray: length + ' ' + length, | |
dashoffset: length | |
}); | |
var fx = this.animate(options.duration, options.easing, options.delay); | |
fx.stroke({ | |
dashoffset: 0 | |
}); | |
return this; | |
}, | |
update: function (redraw) { | |
if (redraw === true) | |
this._redrawEnabled = false; | |
if (redraw === false) | |
this._redrawEnabled = true; | |
return !!this._redrawEnabled; | |
}, | |
redraw: function () { | |
// reset | |
this._lastSegment = null; | |
this.attr('d', ''); | |
return this._drawSegment(this._segments); | |
}, | |
_drawSegment: function (segment) { | |
var str = '', lastSegment = this._lastSegment; | |
if (!Array.isArray(segment)) { | |
segment = [segment]; | |
} | |
for (var i = 0; i < segment.length; i += 1) { | |
if (lastSegment === segment[i].type) { | |
str += ' ' + segment[i].coords.join(' '); | |
} | |
else { | |
str += ' ' + segment[i].type + segment[i].coords.join(' '); | |
} | |
lastSegment = segment[i].type; | |
} | |
this._lastSegment = lastSegment; | |
return this.attr('d', (this.attr('d') || '') + str); | |
} | |
}); | |
}).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment