123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
- function getOrCreateNode(id, name, nodes, dict) {
- let node = dict[id];
- if (!node) {
- node = {}
- node.id = id;
- node.name = name;
- nodes.push(node);
- dict[id] = node;
- }
- return node;
- }
- function toGraphData(data) {
- let graph = {};
- let nodes = graph.nodes = [];
- let links = graph.links = [];
- let idToNode = [];
- let columns = data.head.vars;
- data.results.bindings.forEach(item => {
- const srcID = item[columns[0]].value;
- const trgtID = item[columns[1]].value;
- const src = getOrCreateNode(srcID, srcID, nodes, idToNode);
- const trgt = getOrCreateNode(trgtID, trgtID, nodes, idToNode);
- let link = {};
- link.source = src.id;
- link.target = trgt.id;
- links.push(link);
- });
- return graph;
- }
- function drawGraph(data, containerID, width = 500, height = 300) {
- let graph = toGraphData(data)
- let container = d3.select(containerID);
- let svg = container.append('svg').attr("width", width).attr("height", height);
- // arrow def
- svg.append('defs').append('marker')
- .attr('id', 'arrowhead')
- .attr('viewBox', '-0 -5 10 10')
- .attr('refX', 13)
- .attr('refY', 0)
- .attr('orient', 'auto')
- .attr('markerWidth', 13)
- .attr('markerHeight', 13)
- .attr('xoverflow', 'visible')
- .append('svg:path')
- .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
- .attr('fill', '#808080')
- .style('stroke', 'none');
- let nodes = graph.nodes;
- let links = graph.links;
- let simulation = d3.forceSimulation()
- .force("link", d3.forceLink().id(function (d) {
- return d.id;
- }).distance(80))
- .force("charge", d3.forceManyBody().strength(-100))
- .force("center", d3.forceCenter(width / 2, height / 2));
- let link = svg.selectAll(".link")
- .data(links)
- .enter()
- .append("line")
- .attr("class", "link")
- .attr('marker-end', 'url(#arrowhead)')
- .style('stroke', '#808080');
- let node = svg.selectAll(".node")
- .data(nodes)
- .enter()
- .append("g")
- .attr("class", "node")
- .call(d3.drag()
- .on("start", dragstarted)
- .on("drag", dragged)
- .on("end", dragended));
- node.append("circle")
- .attr("r", 5)
- .attr("fill", "#006496")
- node.append("title")
- .text(function (d) {
- return d.name;
- });
- node.append("text")
- .attr("dy", -3)
- .text(function (d) {
- return d.id
- });
- simulation.nodes(nodes).on("tick", ticked);
- simulation.force("link").links(links);
- function ticked() {
- link
- .attr("x1", function (d) {
- return getX(d.source.x);
- })
- .attr("y1", function (d) {
- return getY(d.source.y);
- })
- .attr("x2", function (d) {
- return getX(d.target.x);
- })
- .attr("y2", function (d) {
- return getY(d.target.y);
- });
- node.attr("transform",
- function (d) {
- const dx = getX(d.x);
- const dy = getY(d.y);
- return "translate(" + dx + ", " + dy + ")";
- }
- );
- function getX(x) {
- let dx = x;
- if (dx < 20) dx = 20;
- if (dx > width - 20) dx = width - 20;
- return dx;
- }
- function getY(y) {
- let dy = y;
- if (dy < 20) dy = 20;
- if (dy > height - 20) dy = height - 20;
- return dy;
- }
- }
- function dragstarted(event) {
- if (!event.active) simulation.alphaTarget(0.3).restart()
- event.subject.fx = event.subject.x;
- event.subject.fy = event.subject.y;
- }
- function dragged(event) {
- event.subject.fx = event.x;
- event.subject.fy = event.y;
- }
- function dragended(event) {
- if (!event.active) simulation.alphaTarget(0);
- event.subject.fx = null;
- event.subject.fy = null;
- }
- }
- export {drawGraph, toGraphData};
- export default drawGraph;
|