import React, { useState, useEffect } from "react"; import * as d3 from "d3"; export function drawChart(height, width) { d3.select("#chart") .append("svg") .attr("width", width) .attr("height", height) .style("border", "1px solid black") .append("text") .attr("fill", "green") .attr("x", 50) .attr("y", 50) .text("Hello D3"); } export function drawCircles() { var svg = d3 .select("#circles") .append("svg") .attr("width", 960) .attr("height", 500) .attr("bgcolor", "blue"); var background = svg .append("rect") .attr("width", "100%") .attr("height", "100%") .attr("fill", "blue"); var ball = svg .append("circle") .attr("r", 73) .attr("cx", 480) .attr("cy", 250) .style("fill", "#ffe41e"); } export function drawGraph() { let margin = { top: 20, right: 30, bottom: 20, left: 30 }; let width = 900 - margin.left - margin.right; let height = 600 - margin.top - margin.bottom; var svg = d3 .select("#graph") .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); let data = { nodes: [ { id: 1, name: "A", }, { id: 2, name: "B", }, { id: 3, name: "C", }, { id: 4, name: "D", }, { id: 5, name: "E", }, { id: 6, name: "F", }, { id: 7, name: "G", }, { id: 8, name: "H", }, { id: 9, name: "I", }, { id: 10, name: "J", }, ], links: [ { source: 1, target: 2, }, { source: 1, target: 5, }, { source: 1, target: 6, }, { source: 2, target: 3, }, { source: 2, target: 7, }, { source: 3, target: 4, }, { source: 8, target: 3, }, { source: 4, target: 5, }, { source: 4, target: 9, }, { source: 5, target: 10, }, ], }; console.log(data); // List of node names var allNodes = data.nodes.map(function (d) { return d.name; }); // A linear scale to position the nodes on the X axis var x = d3.scalePoint().range([0, width]).domain(allNodes); // Add the circle for the nodes svg .selectAll("mynodes") .data(data.nodes) .enter() .append("circle") .attr("cx", function (d) { return x(d.name); }) .attr("cy", height - 30) .attr("r", 8) .style("fill", "#69b3a2"); // And give them a label svg .selectAll("mylabels") .data(data.nodes) .enter() .append("text") .attr("x", function (d) { return x(d.name); }) .attr("y", height - 10) .text(function (d) { return d.name; }) .style("text-anchor", "middle"); // Add links between nodes. Here is the tricky part. // In my input data, links are provided between nodes -id-, NOT between node names. // So I have to do a link between this id and the name var idToNode = {}; data.nodes.forEach(function (n) { idToNode[n.id] = n; }); // Cool, now if I do idToNode["2"].name I've got the name of the node with id 2 // Add the links svg .selectAll("mylinks") .data(data.links) .enter() .append("path") .attr("d", function (d) { let start = x(idToNode[d.source].name); // X position of start node on the X axis let end = x(idToNode[d.target].name); // X position of end node return ( [ "M", start, height - 30, // the arc starts at the coordinate x=start, y=height-30 (where the starting node is) "A", // This means we're gonna build an elliptical arc (start - end) / 2, ",", // Next 2 lines are the coordinates of the inflexion point. Height of this point is proportional with start - end distance (start - end) / 2, 0, 0, ",", start < end ? 1 : 0, end, ",", height - 30, ] // We always want the arc on top. So if end is before start, putting 0 here turn the arc upside down. .join(" ") ); }) .style("fill", "none") .attr("stroke", "black"); // labels for links svg .selectAll("mylinks") .data(data.links) .enter() .append("text") .attr("x", function (d) { let start = x(idToNode[d.source].name); // X position of start node on the X axis let end = x(idToNode[d.target].name); // X position of end node return start + (end - start) / 2; }) .attr("y", function (d) { let start = x(idToNode[d.source].name); // X position of start node on the X axis let end = x(idToNode[d.target].name); // X position of end node return height - 30 - Math.abs(start - end) / 2; //height-30 }) .text(function (d) { return `${idToNode[d.source].name}-${idToNode[d.target].name}`; }) .style("text-anchor", "top"); svg .selectAll("text") .data(data.links) .enter() .append("text") .attr("x", function (d) { return d.source.x + (d.target.x - d.source.x) / 2; }) .attr("y", function (d) { return d.source.y + (d.target.y - d.source.y) / 2; }) .text(function (d) { return d.something; }); } export function D3Experiment() { useEffect(() => { drawGraph(); }, []); return (
); } export default D3Experiment;