Last active
October 4, 2018 12:32
-
-
Save TVerduyn/4935615ba55a2c0b73b2550e0eb8764d to your computer and use it in GitHub Desktop.
Keypad Code Guessing Visualisation
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> | |
<!--Code Lock Graph--> | |
<meta charset="utf-8"> | |
<style> | |
body { font-family: Helvetica, Arial, sans-serif; } | |
.links line { | |
stroke: #999; | |
stroke-opacity: 0.6; | |
} | |
.nodes circle { | |
stroke: #fff; | |
stroke-width: 1.5px; | |
} | |
</style> | |
<html> | |
<Title>Keypad Code Guessing Visualisation</Title> | |
(Base, #Characters): | |
<select id="BaseCharCount" size="1"> | |
<option value="1,1">(2,2)</option> | |
<option value="1,2">(2,3)</option> | |
<option value="1,3">(2,4)</option> | |
<option value="1,4">(2,5)</option> | |
<option value="1,5">(2,6)</option> | |
<option value="1,6">(2,7)</option> | |
<option value="1,7">(2,8)</option> | |
<option value="2,1">(3,2)</option> | |
<option value="2,2">(3,3)</option> | |
<option selected="selected" value="2,3">(3,4)</option> | |
<option value="2,4">(3,5)</option> | |
<option value="3,1">(4,2)</option> | |
<option value="3,2">(4,3)</option> | |
<option value="3,3">(4,4)</option> | |
<option value="4,1">(5,2)</option> | |
<option value="4,2">(5,3)</option> | |
<option value="5,1">(6,2)</option> | |
<option value="5,2">(6,3)</option> | |
<option value="6,1">(7,2)</option> | |
<option value="7,1">(8,2)</option> | |
<option value="8,1">(9,2)</option> | |
<option value="9,1">(10,2)</option> | |
</select> | |
Speed: | |
<input type="range" min="-1500" max="-100" value="-500" id="Timer" width=90> | |
<input type="button" onclick="draw(+BaseCharCount.value[0]+1,+BaseCharCount.value[2]+1,+-Timer.value);" value="Redraw"> | |
<div id="vis"></div> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script> | |
var svg = d3.select("#vis") | |
.append("svg") | |
draw(3,4,500); | |
function draw(basecount, charcount, timer) { | |
var totalwidth = (window.innerWidth > 0) ? window.innerWidth : screen.width; | |
var totalheight = (window.innerHeight > 0) ? window.innerHeight : screen.height; | |
var width = totalwidth-50 | |
var height = totalheight-50 | |
svg.attr("width", width) | |
.attr("height", height); | |
d3.select("svg").selectAll("text").remove() | |
d3.select("svg").selectAll("g").remove() | |
nodes = []; | |
links = []; | |
currentNode = ''; | |
currentLink = ''; | |
for ( i = 0; i < Math.pow(basecount, charcount); i++) { | |
currentNode = i.toString(basecount).padStart(charcount, '0') | |
nodes.push({"id":currentNode}) | |
for ( j = 0; j < basecount; j++) { | |
currentLink = currentNode.substring(1, charcount) + j.toString() | |
links.push({"source":currentNode,"target":currentLink}); | |
currentLink = ''; | |
} | |
} | |
var color = d3.scaleOrdinal(d3.schemeCategory20); | |
function x_limit_force() { | |
for (var i = 0, n = nodes.length; i < n; ++i) { | |
nodes[i].x = Math.max(10 - nodes[i].vx , Math.min(width - 10 - nodes[i].vx, nodes[i].x)); | |
nodes[i].y = Math.max(25 - nodes[i].vy , Math.min(height - 5 - nodes[i].vy, nodes[i].y)); | |
} | |
} | |
var simulation = d3.forceSimulation() | |
.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(75).strength(0)) | |
.force("charge", d3.forceManyBody().strength(-1)) | |
.force("collide", d3.forceCollide(20).radius(30).strength(0.5)) | |
.force("center", d3.forceCenter(width / 2, height / 2)) | |
.alpha(0.45) | |
; | |
svg.append("svg:defs").selectAll("marker") | |
.data(["end"]) | |
.enter().append("svg:marker") | |
.attr("id", String) | |
.attr("viewBox", "0 -5 10 10") | |
.attr("refX", 15) | |
.attr("refY", -1.5) | |
.attr("markerWidth", 6) | |
.attr("markerHeight", 6) | |
.attr("orient", "auto") | |
.append("svg:path") | |
.attr("d", "M0,-5L10,0L0,5"); | |
var link = svg.append("g") | |
.attr("class", "links") | |
.selectAll("line") | |
.data(links) | |
.enter().append("line") | |
.attr("stroke-width", 1) | |
.attr("opacity", 0.7) | |
.attr("marker-end", "url(#end)"); | |
var node = svg.append("g") | |
.attr("class", "nodes") | |
.selectAll("circle") | |
.data(nodes) | |
.enter() | |
.append("text") | |
.attr("font-family", "Helvetica, Arial, sans-serif") | |
.attr("font-size", 12) | |
.text(function(d) { return d.id}) | |
.attr("x", function(d) { return d.x}) | |
.attr("y", function(d) { return d.y}) | |
.attr("fill", "#2c7bb6") | |
.attr("opacity",0.7) | |
node.append("title") | |
.text(function(d) { return d.id; }); | |
simulation | |
.nodes(nodes) | |
.on("tick", ticked); | |
simulation.force("link") | |
.links(links); | |
var dBsequence = deBruijn (basecount, charcount).join(""); | |
var textstart = svg.append("text") | |
.attr("id","other") | |
.attr("x", 10) | |
.attr("y", 15) | |
.attr("font-size", 12) | |
.text(function() { return "De Bruijn Sequence: " ; }) | |
var textdBprestart = textstart.append("tspan") | |
.attr("fill","red") | |
.attr("font-weight","bold") | |
.text(function() { return dBsequence.substring(0, 0); }) | |
var textdBstart = textstart.append("tspan") | |
.attr("fill","black") | |
.text(function() { return dBsequence.substring(0, 0); }) | |
var textdBmid = textstart.append("tspan") | |
.attr("fill","red") | |
.attr("font-weight","bold") | |
.text(function() { return dBsequence.substring(0, charcount); }) | |
var textdBend = textstart.append("tspan") | |
.attr("fill","black") | |
.text(function() { return dBsequence.substring(charcount); }) | |
for ( i = 0; i < dBsequence.length; i++) { | |
svg.select(".nodes").selectAll('text') | |
.filter(function(d){ return d.id==[dBsequence,dBsequence].join("").substring(i, i+charcount)}) | |
.transition() | |
.duration(timer) | |
.delay(2000+i*timer) | |
.attr("opacity",1) | |
.attr("fill", "red") | |
.transition() | |
.duration(timer) | |
.delay(timer) | |
.attr("opacity", 0.3) | |
svg.selectAll("line") | |
.filter(function(d){ return d.source.id==[dBsequence,dBsequence].join("").substring(i, i+charcount)}) | |
.filter(function(d){ return d.target.id==[dBsequence,dBsequence].join("").substring(i+1, i+charcount+1)}) | |
.transition() | |
.duration(timer) | |
.delay(2000+(i+1)*timer) | |
.attr("opacity", 1) | |
.style("stroke", "#d7191c") | |
.transition() | |
.duration(timer) | |
.delay(timer) | |
.attr("opacity", 0.3) | |
textdBstart | |
.transition() | |
.duration(timer) | |
.delay(2000+(i+0.5)*timer) | |
.text(function() { return dBsequence.substring(0, i); }); | |
textdBmid | |
.transition() | |
.duration(timer) | |
.delay(2000+(i+0.5)*timer) | |
.text(function() { return dBsequence.substring(i, i+charcount); }); | |
textdBend | |
.transition() | |
.duration(timer) | |
.delay(2000+(i+0.5)*timer) | |
.text(function() { return dBsequence.substring(i+charcount); }); | |
if (i>dBsequence.length-charcount){ | |
textdBprestart | |
.transition() | |
.duration(timer) | |
.delay(2000+(i+0.5)*timer) | |
.text(function() { return dBsequence.substring(0, i+charcount-dBsequence.length); }); | |
textdBstart | |
.transition() | |
.duration(timer) | |
.delay(2000+(i+0.5)*timer) | |
.text(function() { return dBsequence.substring(i+charcount-dBsequence.length, i); }); | |
} | |
} | |
function ticked() { | |
link | |
.attr("x1", function(d) { return d.source.x; }) | |
.attr("y1", function(d) { return d.source.y; }) | |
.attr("x2", function(d) { return d.target.x; }) | |
.attr("y2", function(d) { return d.target.y; }); | |
node | |
.attr("x", function(d) { return d.x; }) | |
.attr("y", function(d) { return d.y; }); | |
for (var i = 0, n = nodes.length; i < n; ++i) { | |
if( nodes[i].x + nodes[i].vx <0 || nodes[i].x + nodes[i].vx > width-50 || nodes[i].y + nodes[i].vy < 30 || nodes[i].y + nodes[i].vy > height){ | |
simulation.stop() | |
} | |
} | |
} | |
} | |
function deBruijn (k, n) { | |
var a = []; | |
for (var i = 0; i < k * n; i++) a.push(0); | |
var sequence = []; | |
(function db (t, p) { | |
if (t > n) { | |
if (n % p !== 0) return; | |
for (var j = 1; j <= p; j++) { | |
sequence.push(a[j]); | |
} | |
return; | |
} | |
a[t] = a[t-p]; | |
db(t + 1, p); | |
for (var j = a[t-p] + 1; j < k; j++) { | |
a[t] = j; | |
db(t + 1, t); | |
} | |
})(1,1); | |
return sequence | |
}; | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment