chart = {
const root = d3.hierarchy(rollupData);
const links = root.links();
const nodes = root.descendants();
let MouseOutEvent = null;
const delay = 1000;
const svgR = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.property("value", [1]);
const svg = svgR.append("g");
const link = svg.append("g")
.style("stroke", "#999")
.style("stroke-opacity", 0.6)
.style("stroke-width", 1.5)
.selectAll("line")
.data(links)
.join("line")
.classed("link", true);
const node = svg.append("g")
.selectAll("circle")
.data(nodes)
.join("circle")
.classed("node", true)
.classed("fixed", d => d.fx !== undefined)
.attr("r", showSize)
.attr("fill", showFill)
.attr("stroke", showStroke);
const simulation = d3.forceSimulation()
.nodes(nodes)
.force("charge", d3.forceManyBody().strength(-30).distanceMax(61000 / nodes.length))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("link", d3.forceLink(links).distance(30).strength(2))
.force("collide", d3.forceCollide(10))
.on("tick", () => {
link.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
node.attr("cx", d => d.x)
.attr("cy", d => d.y);
});
// modify the leaf node.
const leaf = svg.selectAll("circle")
.filter(d=>!d.children)
.style("pointer-events", "all")
.style("cursor", "pointer")
.on("click", (event, d)=>{window.open(d.data["主页链接"], "_blank")})
.on("mouseover", function(event, d){
if(MouseOutEvent){
clearTimeout(MouseOutEvent);
d3.select(".mouseOver").attr("fill", showFill).classed("mouseOver", false);
d3.select("#label-group").remove();
d3.select("#school-group").remove();
d3.select("#contri-group").remove();
}
d3.select(this).attr("fill", showColor).style("cursor", "pointer").classed("mouseOver", true);
let sim = d.data["相似推荐"].split(" ").map(d=>+d);
svgR.property("value", d3.select(this).attr("r")).dispatch("input");
svg.selectAll("circle")
.filter(dd=>!dd.children)
.filter(dd=>sim.indexOf(+dd.data["序号"] - 1) >= 0)
.filter(dd=>(+dd.data["序号"] != +d.data["序号"]))
.attr("fill", showColor)
.attr("r", function(dd){
let curR = +d3.select(this).attr("r");
// svgR.property("value", curR).dispatch("input");
return sim.indexOf(+dd.data["序号"] - 1) / 20 * (13 - curR) + curR;
})
.classed("sim", true);
var labelItem = [{x: 10, y: 50, text: `姓名:${d.data["姓名"]}`},
// {x: 10, y: 75, text: `收集负责人:${d.data["收集负责人"]}`},
{x: 10, y: 75, text: `研究兴趣/方向:${d.data["研究兴趣/方向"] || "未知"}`}];
svg.append("g").attr("id", "label-group");
const labelDOM = document.getElementById("label-group")
labelItem.forEach(function(d){
labelDOM.appendChild(createSVGtext(Object.assign(d, {maxCharsPerLine: 20})));
});
svg.select("#label-group")
.selectAll("text")
.attr("id", (d, i)=>`node-${i}`)
.style("font-family", "SemHei")
.style("font-weight", "bold")
.style("font-size", "1em")
.style("text-anchor", "start");
var schoolItem = [{x: width - 250, y: 50, text: `${d.data["学校"]}`},
{x: width - 250, y: 75, text: `- ${d.data["一级单位(学院/系)"]}`},
{x: width - 250, y: 100, text: `-- ${d.data["二级单位(系所/教研室/研究中心/学科/专业/方向)"]}`},
{x: width - 250, y: 125, text: `本科:${d.data["本科毕业学校"] || "未知"},${d.data["本科毕业年份"] || "未知"}`},
{x: width - 250, y: 150, text: `硕士:${d.data["硕士毕业学校"] || "未知"},${d.data["硕士毕业年份"] || "未知"}`},
{x: width - 250, y: 175, text: `博士:${d.data["博士毕业学校"] || "未知"},${d.data["博士毕业年份"] || "未知"}`}];
svg.append("g").attr("id", "school-group");
const schoolDOM = document.getElementById("school-group")
schoolItem.forEach(function(d){
schoolDOM.appendChild(createSVGtext(Object.assign(d, {maxCharsPerLine: 20})));
});
svg.select("#school-group")
.selectAll("text")
.attr("id", (d, i)=>`node-${i}`)
.style("font-family", "SemHei")
.style("font-weight", "bold")
.style("font-size", "1em")
.style("text-anchor", "start");
var contriItem = [{x: width - 250, y: height - 50, text: `收集负责人:${d.data["收集负责人"]}`}];
svg.append("g").attr("id", "contri-group");
const contriDOM = document.getElementById("contri-group")
contriItem.forEach(function(d){
contriDOM.appendChild(createSVGtext(Object.assign(d, {maxCharsPerLine: 20})));
});
svg.select("#contri-group")
.selectAll("text")
.attr("id", (d, i)=>`node-${i}`)
.style("font-family", "SemHei")
.style("font-weight", "bold")
.style("font-size", "1em")
.style("text-anchor", "start");
})
.on("mouseout", function(d, i){
d3.select(this).style("cursor", null);
d3.selectAll(".sim").attr("fill", showFill).attr("r", showSize).style("cursor", "default").classed("sim", false);
MouseOutEvent = setTimeout(()=>{
d3.select(this).attr("fill", showFill).classed("mouseOver", false);
d3.select("#label-group").remove();
d3.select("#school-group").remove();
d3.select("#contri-group").remove();
}, delay);
});
// leaf.append("title")
// .text(d=>`点击查看${d.data["姓名"]}的个人主页`);
// modify the internal nodes.
const internal = svg.selectAll("circle")
.filter(d=>d.children)
// .style("cursor", "zoom-in");
.style("cursor", "move")
.call(d3.drag().on("start", dragstart).on("drag", dragged));
// internal.on("click", click)
internal.append("title")
.text(showText);
// event definitions.
function click(event, d) {
delete d.fx;
delete d.fy;
d3.select(this).classed("fixed", false).attr("fill", showFill);
simulation.alpha(1).restart();
}
function dragstart() {
d3.select(this).classed("fixed", true).attr("fill", "#f00");
}
function dragged(event, d) {
d.fx = clamp(event.x, 0, width);
d.fy = clamp(event.y, 0, height);
simulation.alpha(1).restart();
}
return svgR.node();
}