justNodesAndLabels = {
const radius = 10
const container = d3.select(DOM.svg(width+margin.left+margin.right,
height+margin.top+margin.bottom))
const arcGroup = container
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
const nodes = arcGroup.selectAll("nodes")
.data(graphData.nodes)
.enter().append("circle")
.attr("cx", margin.left+150)
.attr("cy", d => yScale(d.movement_name))
.attr("r", radius)
.attr("fill", d => color(d.location))
.attr("id", d => d.id)
const nodeLabels = arcGroup.selectAll("nodeLabels")
.data(graphData.nodes)
.enter().append("text")
.attr("x",margin.left+120)
.attr("y", d => yScale(d.movement_name))
.attr("fill", d => color(d.location))
.style("font", "16px helvetica neue bold")
.style("text-anchor","end")
.style("alignment-baseline","central")
.text(d => d.movement_name)
const artist = arcGroup.selectAll("key_artist")
.data(graphData.nodes)
.enter().append("text")
.attr("x",margin.left+300)
.attr("y", d => yScale(d.movement_name)+20)
.attr("fill","white")
.style("font", "16px helvetica neue")
.style("text-anchor","start")
.style("alignment-baseline","central")
.text(d => d.key_artist)
const year = arcGroup.selectAll("year")
.data(graphData.nodes)
.enter().append("text")
.attr("x",margin.left-190)
.attr("y", d => yScale(d.movement_name)+20)
.attr("fill","grey")
.style("font", "16px helvetica neue bold")
.style("text-anchor","start")
.style("alignment-baseline","central")
.text(d => d.year)
// This code builds up the SVG path element; see nodesAndArcs for details
function buildArc(d) {
let start = yScale(idToNode[d.source].movement_name);
let end = yScale(idToNode[d.target].movement_name);
const arcPath = ['M', margin.left+150, start, 'A', Math.abs(start - end)/2, ',', Math.abs(start-end)/2, 0,0,",",
start < end ? 1: 0, margin.left+150, end].join(' ');
return arcPath;
}
// create the arcs
const arcs = arcGroup.selectAll("arcs")
.data(graphData.links)
.enter().append("path")
.style("fill", "none")
.attr("stroke", "grey")
.attr("d", d => buildArc(d))
// When the user mouses over a node,
// add interactive highlighting to see connections between nodes
nodes.on('mouseover', function(d, i) {
// add animation on mouseover with expanding bigger nodes
// highlight only the selected node
d3.select(this).style("fill", "grey")
.transition()
.attr("r", radius*1.3);
arcs
// the arc color and thickness stays as the default unless connected to the selected node d
// notice how embedding the reference to arcs within nodes.on() allows the code to connect d to arcd
// this code iterates through all the arcs so we can compare each to the selected node d
.style('stroke', function (arcd) {
return arcd.source === d.id || arcd.target === d.id ? d => color2(d.relationship) : 'none';})
.style('stroke-width', function (arcd) {
return arcd.source === d.id || arcd.target === d.id ? 3 : 1;})
.attr("stroke-dasharray", function () {return this.getTotalLength()})
.attr("stroke-dashoffset", function () {return this.getTotalLength()})
// reveal the arcs
.transition()
// add duration and animation to highlight connection
.duration(1200)
.attr("stroke-dashoffset", 0)
year
.style('fill', function (yeard) {
return yeard.movement_name === d.movement_name ? 'grey' : 'none';});
artist
.style('fill', function (artistd) {
return artistd.movement_name === d.movement_name ? 'grey' : 'none';});
});
// remove highlighting when user mouse moves out of node by restoring default colors and thickness
nodes.on('mouseout', function (d, i) {
nodes.style("fill", d => color(d.location))
// add the animation
.transition()
.attr("r", radius);
arcs.style('stroke', 'grey');
arcs.style('stroke-width', 1);
artist.style("fill", "white");
// have year appear as default timeline for overview
year.style("fill", "grey");
});
return container.node();
}