mirror of
https://github.com/KrisKennaway/bigapple.git
synced 2025-01-13 12:31:28 +00:00
6a4706d6b0
sectors and visualize it as a D3 force-directed graph. This is pretty cool There are two thresholds to control the graph size and connectivity - limit to boot1 images that are represented in at least 10 disks - only render links for distances < 200 bits Needs improvements, e.g. - use human-readable names for the boot1 images - potentially add controls for dynamically changing those thresholds and other D3 params - display list of associated disks to each image
120 lines
2.9 KiB
HTML
120 lines
2.9 KiB
HTML
<!DOCTYPE html>
|
|
<meta charset="utf-8">
|
|
<canvas width="2000" height="2000"></canvas>
|
|
<script src="https://d3js.org/d3.v4.js"></script>
|
|
<script>
|
|
|
|
var canvas = document.querySelector("canvas"),
|
|
context = canvas.getContext("2d"),
|
|
width = canvas.width,
|
|
height = canvas.height;
|
|
|
|
|
|
// TODO
|
|
// - hover text
|
|
// - distance on links
|
|
// - full file name on nodes
|
|
// - list of all disks on nodes
|
|
// - size nodes by number of matching disks
|
|
// Double-click on a node and sort it in relation to all of its links
|
|
|
|
d3.json("levenshtein.json", function(error, graph) {
|
|
if (error) throw error;
|
|
|
|
var nodes = graph.nodes;
|
|
|
|
console.log(graph.links);
|
|
var links = [];
|
|
graph.links.forEach(function(link) {
|
|
if (link.distance < 200 && link.distance > 0) {
|
|
links.push(link);
|
|
}
|
|
});
|
|
console.log(links);
|
|
|
|
var simulation = d3.forceSimulation(nodes)
|
|
.force("charge", d3.forceManyBody().strength(-500))
|
|
.force("link", d3.forceLink(links)
|
|
.strength(1)
|
|
// TODO: Also add source and target radius so circles don't overlap
|
|
.distance(function(d) {return d.distance;}))
|
|
.force("x", d3.forceX())
|
|
.force("y", d3.forceY())
|
|
.on("tick", ticked);
|
|
|
|
d3.select(canvas)
|
|
.call(d3.drag()
|
|
.container(canvas)
|
|
.subject(dragsubject)
|
|
.on("start", dragstarted)
|
|
.on("drag", dragged)
|
|
.on("end", dragended)
|
|
);
|
|
|
|
function ticked() {
|
|
context.clearRect(0, 0, width, height);
|
|
context.save();
|
|
context.translate(width / 2, height / 2);
|
|
|
|
context.beginPath();
|
|
links.forEach(drawLink);
|
|
context.strokeStyle = "#aaa";
|
|
context.stroke();
|
|
|
|
nodes.forEach(drawNode);
|
|
context.strokeStyle = "#fff";
|
|
context.stroke();
|
|
|
|
context.restore();
|
|
}
|
|
|
|
function dragsubject() {
|
|
return simulation.find(d3.event.x - width / 2, d3.event.y - height / 2);
|
|
}
|
|
|
|
function dragstarted() {
|
|
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
|
|
d3.event.subject.fx = d3.event.subject.x;
|
|
d3.event.subject.fy = d3.event.subject.y;
|
|
}
|
|
|
|
function dragged() {
|
|
d3.event.subject.fx = d3.event.x;
|
|
d3.event.subject.fy = d3.event.y;
|
|
}
|
|
|
|
function dragended() {
|
|
if (!d3.event.active) simulation.alphaTarget(0);
|
|
d3.event.subject.fx = null;
|
|
d3.event.subject.fy = null;
|
|
}
|
|
|
|
function drawLink(d) {
|
|
context.moveTo(d.source.x, d.source.y);
|
|
context.lineTo(d.target.x, d.target.y);
|
|
}
|
|
|
|
function drawNode(d) {
|
|
context.beginPath();
|
|
context.moveTo(d.x, d.y); // was d.x+3 for some reason
|
|
var radius = (Math.log10(d.radius)+1)*5
|
|
context.arc(d.x, d.y, radius, 0, 2 * Math.PI);
|
|
context.strokeStyle = "#000000"
|
|
context.strokeText(d.sha1, d.x+radius+5, d.y);
|
|
context.fillStyle = '#' + d.sha1.substr(0,6).toUpperCase();
|
|
context.fill();
|
|
}
|
|
|
|
function mouseOver(d, i) {
|
|
d3.select(this).append("text")
|
|
.text( d.x)
|
|
.attr("x", x(d.x))
|
|
.attr("y", y(d.y));
|
|
}
|
|
|
|
function mouseOut(d) {
|
|
}
|
|
});
|
|
|
|
</script>
|