chart = {
const svg = d3.select(DOM.svg(width, height));
svg.append("style").text(`
.hover path {
stroke: #ccc;
}
.hover text {
fill: #ccc;
}
.hover g.primary text {
fill: red;
font-weight: bold;
font-size: 14px;
}
.hover g.secondary text {
fill: #333;
}
.hover path.primary {
stroke: #b22222;
stroke-opacity: 1;
}
`);
const label = svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(graph.nodes)
.join("g")
.attr("transform", d => `translate(${margin.left},${d.y = y(d.id)})`)
.call(g => g.append("text")
.attr("x", -6)
.attr("dy", "0.35em")
.attr("fill", d => d3.lab(color(d.group)).darker(2))
.text(d => d.id))
.call(g => g.append("circle")
// .attr("r", 3)
.attr("r", 3)
.attr("fill", d => color(d.group)));
const path = svg.insert("g", "*")
.attr("fill", "none")
.attr("stroke-opacity", 0.6)
// .attr("stroke-width", 1.5)
.selectAll("path")
.data(graph.links)
.join("path")
.attr("stroke", d => d.source.group === d.target.group ? color(d.source.group) : "#aaa")
// .attr("stroke", d => d.source.group === d.target.group ? color(d.source.group) : color(d.target.group))
.attr("stroke-width", d => 1)
// .attr("stroke-width", d => d.value/946*3 + 1)
.attr("d", arc);
let highlight = svg.append("g")
.attr("x", margin.left + 4000)
.attr("y", 2000)
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "#333")
.attr("fill-opacity", 1)
.style("font-size", "3.5vw")
.style("font-weight", 700);
let alias = highlight
.append("text")
.attr("x", margin.left + 120)
.attr("y", 200)
.attr("dy", "-0.3em")
.style('fill', 'red')
.style('fill-opacity', 0.6);
const overlay = svg.append("g")
.attr("fill", "none")
.attr("pointer-events", "all")
.selectAll("rect")
.data(graph.nodes)
.join("rect")
.attr("width", margin.left + 40)
.attr("height", step)
.attr("y", d => y(d.id) - step / 2)
.on("mouseover", d => {
svg.classed("hover", true);
label.classed("primary", n => n === d);
label.classed("secondary", n => n.sourceLinks.some(l => l.target === d) || n.targetLinks.some(l => l.source === d));
path.classed("primary", l => l.source === d || l.target === d).filter(".primary").raise();
// color modification
// path.classed("primary", l => (l.source === d || l.target === d) ? color(d.source.group) : color(d.target.group))
// .attr("stroke", d => d.source.group === d.target.group ? color(d.source.group) : color(d.target.group))
// path.classed("primary", d => d.source === d.target ? color(d.source.group) : color(d.target.group))
alias.text(d.id + " has " + ((d.sourceLinks.length + d.targetLinks.length)/2) + " related tags");
// alias.text(d.id + " has " + (d.sourceLinks.length) + " related tags");
// alias.text(d.id + " has " + (d.popularity) + " related posts");
})
.on("mouseout", d => {
svg.classed("hover", false);
label.classed("primary", false);
label.classed("secondary", false);
path.classed("primary", false).order();
alias.text("")
});
function update() {
y.domain(graph.nodes.sort(viewof order.value).map(d => d.id));
const t = svg.transition()
.duration(750);
label.transition(t)
.delay((d, i) => i * 20)
.attrTween("transform", d => {
const i = d3.interpolateNumber(d.y, y(d.id));
return t => `translate(${margin.left},${d.y = i(t)})`;
});
path.transition(t)
.duration(750 + graph.nodes.length * 20)
.attrTween("d", d => () => arc(d));
overlay.transition(t)
.delay((d, i) => i * 20)
.attr("y", d => y(d.id) - step / 2);
}
viewof order.addEventListener("input", update);
invalidation.then(() => viewof order.removeEventListener("input", update));
return svg.node();
}