148 lines
3.6 KiB
JavaScript
148 lines
3.6 KiB
JavaScript
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm"
|
|
import {
|
|
forceSimulation,
|
|
forceLink,
|
|
forceCollide,
|
|
} from "https://cdn.jsdelivr.net/npm/d3@7/+esm"
|
|
|
|
const data = {
|
|
nodes: [
|
|
{ id: "A", group: 1 },
|
|
{ id: "B", group: 1 },
|
|
{ id: "C", group: 1 },
|
|
{ id: "D", group: 1 },
|
|
{ id: "E", group: 1 },
|
|
{ id: "F", group: 1 },
|
|
{ id: "G", group: 1 },
|
|
{ id: "H", group: 1 },
|
|
{ id: "I", group: 1 },
|
|
{ id: "J", group: 1 },
|
|
{ id: "K", group: 1 },
|
|
{ id: "L", group: 1 },
|
|
{ id: "M", group: 1 },
|
|
{ id: "N", group: 1 },
|
|
{ id: "O", group: 1 },
|
|
{ id: "P", group: 1 },
|
|
{ id: "Q", group: 1 },
|
|
{ id: "R", group: 1 },
|
|
{ id: "S", group: 1 },
|
|
{ id: "T", group: 1 },
|
|
{ id: "U", group: 1 },
|
|
{ id: "V", group: 1 },
|
|
{ id: "W", group: 1 },
|
|
{ id: "X", group: 1 },
|
|
{ id: "Y", group: 1 },
|
|
{ id: "Z", group: 1 },
|
|
],
|
|
links: [
|
|
{ source: "A", target: "B", value: 1 },
|
|
{ source: "A", target: "C", value: 1 },
|
|
{ source: "A", target: "D", value: 1 },
|
|
{ source: "A", target: "E", value: 1 },
|
|
{ source: "A", target: "F", value: 1 },
|
|
{ source: "A", target: "G", value: 1 },
|
|
{ source: "A", target: "H", value: 1 },
|
|
{ source: "A", target: "I", value: 1 },
|
|
{ source: "A", target: "J", value: 1 },
|
|
{ source: "A", target: "K", value: 1 },
|
|
{ source: "A", target: "L", value: 1 },
|
|
{ source: "A", target: "M", value: 1 },
|
|
{ source: "A", target: "N", value: 1 },
|
|
{ source: "A", target: "O", value: 1 },
|
|
{ source: "A", target: "P", value: 1 },
|
|
{ source: "A", target: "Q", value: 1 },
|
|
{ source: "A", target: "R", value: 1 },
|
|
{ source: "A", target: "S", value: 1 },
|
|
{ source: "A", target: "T", value: 1 },
|
|
{ source: "A", target: "U", value: 1 },
|
|
{ source: "A", target: "V", value: 1 },
|
|
{ source: "A", target: "W", value: 1 },
|
|
{ source: "A", target: "X", value: 1 },
|
|
{ source: "A", target: "Y", value: 1 },
|
|
{ source: "A", target: "Z", value: 1 },
|
|
],
|
|
}
|
|
|
|
const width = window.innerWidth
|
|
const height = window.innerHeight
|
|
|
|
const svg = d3
|
|
.select("body")
|
|
.append("svg")
|
|
.attr("width", width)
|
|
.attr("height", height)
|
|
|
|
const simulation = forceSimulation(data.nodes)
|
|
.force(
|
|
"link",
|
|
forceLink(data.links).id((d) => d.id)
|
|
)
|
|
.force("collide", forceCollide(30))
|
|
|
|
const link = svg
|
|
.selectAll("line")
|
|
.data(data.links)
|
|
.enter()
|
|
.append("line")
|
|
.attr("stroke", "black")
|
|
.attr("stroke-width", 1)
|
|
|
|
const node = svg
|
|
.selectAll("circle")
|
|
.data(data.nodes)
|
|
.enter()
|
|
.append("circle")
|
|
.attr("r", 10)
|
|
.attr("fill", "red")
|
|
.call(
|
|
d3.drag().on("start", dragStarted).on("drag", dragged).on("end", dragEnded)
|
|
)
|
|
|
|
node.append("title").text((d) => d.id)
|
|
|
|
const text = svg
|
|
.selectAll("text")
|
|
.data(data.nodes)
|
|
.enter()
|
|
.append("text")
|
|
.attr("x", (d) => d.x)
|
|
.attr("y", (d) => d.y + 20)
|
|
.text((d) => d.id)
|
|
.attr("text-anchor", "middle")
|
|
.attr("fill", "black")
|
|
|
|
simulation.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)
|
|
text.attr("x", (d) => d.x).attr("y", (d) => d.y + 20)
|
|
})
|
|
|
|
node.on("click", function (event, d) {
|
|
d.fx = null
|
|
d.fy = null
|
|
})
|
|
|
|
function dragStarted(event, d) {
|
|
if (!event.active) simulation.alphaTarget(0.3).restart()
|
|
d.fx = d.x
|
|
d.fy = d.y
|
|
}
|
|
|
|
function dragged(event, d) {
|
|
d.fx = event.x
|
|
d.fy = event.y
|
|
}
|
|
|
|
function dragEnded(event, d) {
|
|
if (!event.active) simulation.alphaTarget(0)
|
|
if (!d3.event.active) {
|
|
d.fx = d.x
|
|
d.fy = d.y
|
|
}
|
|
}
|