D3 v4 forcelayout example with dropdown filters.
forked from mbostock's block: Force Dragging I
forked from almsuarez's block: Force Layout v4 with Filters
xxxxxxxxxx
<meta charset="utf-8">
<style>
.links line {
stroke: #c1c1c1;
stroke-width: 2px;
pointer-events: all;
}
.node circle {
pointer-events: all;
stroke: #777;
stroke-width: 1px;
}
div.tooltip {
position: absolute;
background-color: white;
max-width; 200px;
height: auto;
padding: 1px;
border-style: solid;
border-radius: 4px;
border-width: 1px;
box-shadow: 3px 3px 10px rgba(0, 0, 0, .5);
pointer-events: none;
}
</style>
<body>
</body>
<svg width="960" height="700"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var color = d3.scaleOrdinal(d3.schemeSet3);
color(0);
color(1);
color(2);
color(3);
color(4);
color(5);
color(6);
color(7);
color(8);
color(9);
color(10);
var tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
d3.json("miserables.json", function(error, graph) {
if (error) throw error;
var currNodes = graph.nodes
var currLinks = graph.links
var nodesByGroup = d3.nest()
.key(function(d) { return d.group; })
.entries(graph.nodes);
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
//.data(graph.links)
.data(currLinks)
.enter().append("line")
.on('mouseover', function(d) {
tooltip.transition()
.duration(300)
.style("opacity", .8);
tooltip.html("Source:"+ d.source.id +
"<p/>Target:" + d.target.id +
"<p/>Strength:" + d.value)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY + 10) + "px");
})
.on("mouseout", function() {
tooltip.transition()
.duration(100)
.style("opacity", 0);
})
.on("mousemove", function() {
tooltip.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY + 10) + "px");
});
let node = svg.append('g').attr('class','node')
.selectAll("circle")
//.data(graph.nodes)
.data(currNodes).enter().append('circle').attr("r", 6)
.attr("fill", function(d) { return color(d.group);})
.on('mouseover', function(d) {
tooltip.transition()
.duration(300)
.style("opacity", .8);
tooltip.html("Name:" + d.id + "<p/>group:" + d.group)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY + 10) + "px");
})
.on('mouseover', fade(0.1))
.on("mouseout", function() {
fade(1);
tooltip.transition()
.duration(100)
.style("opacity", 0);
})
.on("mousemove", function() {
tooltip.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY + 10) + "px");
})
.on("dblclick", releasenode) // thank you to https://stackoverflow.com/questions/39168274/d3-js-version-4-make-nodes-sticky
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
node.append("text")
.attr("dx", 5)
.attr("dy", ".35em")
.text(d => d.name)
simulation
//.nodes(graph.nodes)
.nodes(currNodes)
.on("tick", ticked);
simulation.force("link")
.links(currLinks);
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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
const linkedByIndex = {};
currLinks.forEach(d => {
linkedByIndex[`${d.source.index},${d.target.index}`] = 1;
});
console.log("Linkarray:", linkedByIndex);
function isConnected(a, b) {
console.log("Item a:",a)
console.log("Item b:",b)
return linkedByIndex[`${a.source.index},${b.target.index}`] ||
linkedByIndex[`${b.source.index},${a.target.index}`] ||
a.index === b.index;
}
function fade(opacity) {
return d => {
node.style('stroke-opacity', function (o) {
linkedByIndex[d.index, o.index]
console.log(isConnected(d,o))
const thisOpacity = isConnected(d, o) ? 1 : opacity;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.style('stroke-opacity',
o => (o.source === d || o.target === d ? 1 : opacity));
};
}
});
var sequentialScale = d3.scaleOrdinal(d3.schemeSet3)
.domain([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
var svg = d3.select("svg");
svg.append("g")
.attr("class", "legendSequential")
.attr("transform", "translate("+(width-140)+","+(height-300)+")");
var legendSequential = d3.legendColor()
.shapeWidth(30)
.cells(11)
.orient("vertical")
.title("Group number by color:")
.titleWidth(100)
.scale(sequentialScale)
svg.select(".legendSequential")
.call(legendSequential);
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
//d.fx = null;
//d.fy = null;
}
function releasenode(d) {
d.fx = null;
d.fy = null;
}
</script>
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js
https://d3js.org/d3-scale-chromatic.v1.min.js