chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("stroke-width", 2);
const bounds = [0, 0, width, height];
const simulation = d3.forceSimulation(graph.nodes)
.force('link', d3.forceLink(graph.links)
.id(function(d) { return d.id; })
.strength(0)
)
.force("charge", d3.forceManyBody())
.force('center', d3.forceCenter(width/2, height/2))
.force('collision', d3.forceCollide(d => d.rBounding))
.force("walls", wallForce)
.on('tick', update)
.on("end", moveToCentroid)
let cells = graph.nodes.map(function(s){ return []; });
let voronoi = d3.weightedVoronoi()
.clip([[0,0], [0,height], [width, height], [width,0]]);
const cellLiner = d3.line()
computeAllCells();
redrawAllCells();
var boundingCircle;
boundingCircle = svg.append("g")
.selectAll('circle')
.data(graph.nodes)
.join("circle")
.attr("class", 'boundingCircle')
.attr("id", (d, i) => 'boundingCircle-' + i.toString())
.attr("r", d => d.rBounding)
.attr('fill', 'rgba(255,0,0,0.5)')
const link = svg
.selectAll(".link")
.data(graph.links)
.join("line")
.classed("link", true)
const circle = svg.append("g")
.selectAll("circle")
.data(graph.nodes)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", radius)
.attr("fill", (d, i) => {
if(d.draggable){
return d3.schemeCategory10[i % 10]
} else {
return "rgba(0,0,0,0.3)";
}
})
.call(d3.drag()
.on("start", dragstarted )
.on("drag", dragged)
.on("end", dragended)
.on("start.update drag.update end.update", update))
.on("click", click);
function click(event, d) {
d.isSelected = !d.isSelected
if (d.isSelected) {
d.weight = openWeight;
d.rBounding = 200;
circle.filter((p) => p === d).attr("stroke", "black");
} else {
d.weight = 0;
d.rBounding = 40;
circle.filter((p) => p === d).attr("stroke", "");
}
update();
}
function update() {
circle.attr("cx", d => d.x).attr("cy", d => d.y);
boundingCircle
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', d => d.rBounding)
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)
simulation.force('collision', d3.forceCollide(d => d.rBounding))
computeAllCells();
redrawAllCells();
}
function dragstarted(event, d){
if (!event.active) simulation.alphaTarget(0.3).restart();
circle.filter(p => p === d).attr("stroke", "black")
}
function dragged(event, d){
d.x = event.x, d.y = event.y
}
function dragended(event, d){
if (!event.active) simulation.alphaTarget(0);
d.weight = 0;
circle.filter(p => p === d).attr("stroke", null)
}
function computeAllCells() {
cells = voronoi(graph.nodes);
}
function redrawAllCells() {
var cellSelection = svg.selectAll(".cell")
.data(cells, function(c){ return c.site.originalObject.index; });
cellSelection.enter()
.append("path")
.attr("fill", "none")
.attr("pointer-events", "all")
.attr("stroke", "#ccc")
.attr("stroke-width", 3)
.classed("cell", true)
.attr("id", function(d,i){ return "cell-"+d.site.originalObject.index; })
.attr("weight", function(d,i){ return d.site.originalObject.weight; })
.merge(cellSelection)
.attr("d", function(d){ return cellLiner(d)+"z"; });
cellSelection.exit().remove();
}
// 在初次渲染完成之后将点至于区域的中心
function moveToCentroid(){
console.log("渲染完成")
var points = graph.nodes.map((d) => { return [d.x, d.y] })
var polygons = [...d3.Delaunay.from(points).voronoi([0, 0, width, height]).cellPolygons()]
polygons.forEach((d, i) => {
console.log("JINLAILE", d3.select(circle._groups[0][i]), circle._groups[0][i])
let centroid = d3.polygonCentroid(d)
// circle.attr("transform", "translate(" + centroid[0] + "," + centroid[1] + ")")
d3.select(circle._groups[0][i]).attr('cx', centroid[0]).attr('cy', centroid[1])
d3.select( boundingCircle._groups[0][i]).attr('cx', centroid[0]).attr('cy', centroid[1])
});
}
return svg.node();
}