Commit b896eef3 authored by Juan Batiz-Benet's avatar Juan Batiz-Benet

Moved out d3view

d3view is now in its own repo:
https://github.com/jbenet/ipfs-diag-net-d3-vis

This is so we can iterate on it quickly without having to
needlessly waste CI resources.

The repo also installs it for you:

```sh
git clone github.com/jbenet/ipfs-diag-net-d3-vis d3view
cd d3view
sudo make install
```
parent cff596d4
# ipfs diagnostics
Usage:
```sh
ipfs diag net [--vis=<vis>]
```
## view in d3
Install https://github.com/jbenet/ipfs-diag-net-d3-vis then:
```
> ipfs diag net --vis=d3 | d3view
http://ipfs.benet.ai:8080/ipfs/QmX8PuUyhSet8fppZHuRNxG7vk949z7XDxnsAz3zN77MGx#QmdhRqGea2QEzyKHG9Zhkc12d2994iah1h47tfHJifuzhT
```
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
font: 11px "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.node:hover circle {
stroke: red;
stroke-width: 4px;
}
.node .link {
stroke-width: 0;
}
.node:hover .link {
stroke-width: 4px;
}
.link {
stroke: steelblue;
stroke-opacity: .4;
fill: none;
}
#legend {
position: fixed;
top: 10px;
left: 10px;
font-size: 14px;
background: rgba(255, 255, 255, 0.7);
}
#legend h1 {
font-weight: 200;
margin: 0px;
padding: 0px;
}
</style>
<body>
<div id="legend">
<h1>IPFS TestNet</h1>
<a href="http://ipfs.io">ipfs.io</a> - <span id="node-count"></span> nodes
</div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var hash = window.location.hash.substring(1)
var diameter = 1400,
radius = diameter / 2,
innerRadius = radius - 200
rotate = 145;
var color = d3.scale.category10()
var diagonal = d3.svg.diagonal.radial()
.projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
var svg = d3.select("body").append("svg")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", "0 0 " + diameter + " " + diameter )
.attr("preserveAspectRatio", "xMidYMid meet")
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
d3.json(hash, function(error, data) {
graph = parseGraph(data)
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
var p = projection
node.append("svg:circle")
.attr("r", function(d) { return d.conns + 2; })
.style("fill", function(d, i) { return color(i % 20); })
.attr("transform", function(d) { return "rotate(" + (d.x - 90 + rotate) + ")translate(" + d.y + ")"; })
var link = svg.selectAll(".link")
.data(graph.paths)
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + p(d[0])[0] + "," + p(d[0])[1]
+ "S" + p(d[1])[0] + "," + p(d[1])[1]
+ " " + p(d[2])[0] + "," + p(d[2])[1];
})
node.selectAll('.link')
.data(function(d) { return d.links })
.enter().append('path')
.attr('class', 'link')
.style("stroke", function(d) { return color(d.source.index % 20); })
.attr("d", function(d) {
return "M" + p(d.path[0])[0] + "," + p(d.path[0])[1]
+ "S" + p(d.path[1])[0] + "," + p(d.path[1])[1]
+ " " + p(d.path[2])[0] + "," + p(d.path[2])[1];
})
node.append("text")
.attr("class", "label")
.attr("dx", -4)
.attr("dy", 3)
// .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
// .attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; })
.text(function(d) { return d.conns + " - " + (d.rtkey || d.name); })
.attr("transform", function(d) { return "rotate(" + (d.x - 90 + rotate) + ")translate(" + d.y + ")"; })
node.append("svg:title")
.text(function(d) { return d.name; });
// var mid = svg.selectAll(".node-mid")
// .data(graph.mids)
// .enter().append("g")
// .attr("class", "node-mid")
// .attr("transform", function(d) { return "rotate(" + (d.x + rotate) + ")translate(" + d.y + ")"; })
// mid.append("svg:circle")
// .attr("r", function(d) { return 4; })
// .style("fill", function(d, i) { return color(i % 3); })
console.log(graph.paths)
});
function parseGraph(graph2) {
graph = {}
graph.nodes = []
graph.links = []
graph.paths = []
graph.byName = {}
graph.mids = []
graph2.nodes.sort(function(a, b) {
var aname = a.rtkey || a.name
var bname = b.rtkey || b.name
if (aname > bname) return 1;
if (aname < bname) return -1;
return 0;
})
graph2.nodes.forEach(function(data, i) {
data.y = innerRadius
data.x = ((360 / graph2.nodes.length) * i)
data.conns = 0
graph.nodes.push(data)
graph.byName[data.name] = data
data.index = i
data.links = []
})
graph2.links.forEach(function(link) {
var source = graph2.nodes[link.source]
var target = graph2.nodes[link.target]
source.conns++
target.conns++
var mid = curveNode(source, target)
graph.mids.push(mid)
var link1 = {source: source, target: mid, value: link.value || 3}
var link2 = {source: mid, target: target, value: link.value || 3}
graph.links.push(link1)
graph.links.push(link2)
var path = [source, mid, target]
graph.paths.push(path)
source.links.push({path: path, source: source})
target.links.push({path: path, source: target})
})
document.getElementById("node-count").innerText = graph.nodes.length
return graph
}
function curveNode(source, target) {
var d = circleDistance(source.x, target.x)
var h = ((1-(d/180)) * innerRadius) * 0.7
var x = circleMidpoint(source.x, target.x)
return {x: x, y: h}
}
function circleMidpoint(x, y) {
var x2 = x > y ? x : y
var y2 = x > y ? y : x
var a = (x2-y2)
if (a > 180) {
a = 360 - a
return (x2 + a/2) % 360
} else {
return (y2 + a/2) % 360
}
}
function circleDistance(x, y) {
var a = abs(x-y)
return (a > 180) ? 360 - a : a
}
function abs(x) {
return x < 0 ? -x : x
}
function projection(d) {
var r = d.y, a = (d.x - 90 + rotate) / 180 * Math.PI;
return [r * Math.cos(a), r * Math.sin(a)];
}
function truncate(name, limit) {
return name.substring(0, limit)
}
d3.select(self.frameElement).style("height", "100%");
d3.select(self.frameElement).style("width", "100%");
</script>
#!/bin/sh
# put stdin in temp file
file=`mktemp -t d3view`
cat >"$file"
# add file to ipfs
hash=$(ipfs add -q "$file" </dev/null | tail -n1)
# this viewer is the hash of go-ipfs/diagnostics/d3/viewer.html
force="QmaY6Lq9MEhDfWUc1VfHcu9aLWSyvi4VDLvWQXLoVZ4Mau"
chord="QmYWjPa736Bk7FhNEEtWLjaEdioSxXkYMhRT9tLi45ccm7"
viewer="$chord"
# the ipfs gateway to use
gatewayHTTP="http://ipfs.benet.ai:8080"
gatewayIPFS="/ip4/104.236.32.22/tcp/4001/Qme7peMbkRH8qzb9TMXSoRwVmVDZz3Z4dseRXAyBwBmxA7"
# make sure you're reachable (no NAT yet)
ipfs swarm connect "$gatewayIPFS" </dev/null >/dev/null
# output the url at the gateway
url="$gatewayHTTP/ipfs/$viewer#$hash"
echo "$url"
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
<body>
<h1>Ipfs Visualization</h1>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var hash = window.location.hash.substring(1)
var width = 960,
height = 800;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-50)
.linkDistance(90)
.gravity(0.01)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json(hash, function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) {return 1.0 + Math.log(d.value)})
.style("fill", function(d) { return color(d.group); })
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
force.on("tick", function() {
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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
</script>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment