Ajout du graphe Secret Santa
This commit is contained in:
parent
7ccd92550b
commit
b09409711d
|
@ -0,0 +1,168 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>D3.js Interactive Cycle Graph with Alternating Curved Arrows</title>
|
||||||
|
<script src="https://d3js.org/d3.v5.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body, html {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend text {
|
||||||
|
font-size: 10px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-anchor: start;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Données du graphe
|
||||||
|
d3.csv("santa.csv").then(function(data) {
|
||||||
|
|
||||||
|
// Dimensions du SVG en plein écran
|
||||||
|
const width = window.innerWidth;
|
||||||
|
const height = window.innerHeight;
|
||||||
|
|
||||||
|
const uniqueNames = data.map(d => d.Source);
|
||||||
|
|
||||||
|
// Création des nœuds avec des positions initiales
|
||||||
|
const nodes = uniqueNames.map((name, index) => ({id: index, label: name}));
|
||||||
|
|
||||||
|
const links = data.map((d, i) => ({
|
||||||
|
source: i,
|
||||||
|
target: uniqueNames.indexOf(d.Cible)
|
||||||
|
}));
|
||||||
|
|
||||||
|
links.push({ source: 0, target: 1 });
|
||||||
|
|
||||||
|
// Création de la force de simulation avec une force de répulsion plus forte
|
||||||
|
const simulation = d3.forceSimulation(nodes)
|
||||||
|
.force("charge", d3.forceManyBody().strength(-300))
|
||||||
|
.force("link", d3.forceLink(links).distance(100))
|
||||||
|
.force("center", d3.forceCenter(width / 2, height / 2))
|
||||||
|
.force("collide", d3.forceCollide().radius(20))
|
||||||
|
.force("x", d3.forceX().strength(0.1).x(width / 2))
|
||||||
|
.force("y", d3.forceY().strength(0.1).y(height / 2));
|
||||||
|
|
||||||
|
// Création du SVG avec zoom
|
||||||
|
const svg = d3.select("body").append("svg")
|
||||||
|
.attr("width", width)
|
||||||
|
.attr("height", height)
|
||||||
|
.call(d3.zoom().on("zoom", function () {
|
||||||
|
svg.attr("transform", d3.event.transform)
|
||||||
|
}))
|
||||||
|
.append("g");
|
||||||
|
|
||||||
|
// Ajout des flèches
|
||||||
|
svg.append("defs").selectAll("marker")
|
||||||
|
.data(["arrow"])
|
||||||
|
.enter().append("marker")
|
||||||
|
.attr("id", function (d) {
|
||||||
|
return d;
|
||||||
|
})
|
||||||
|
.attr("viewBox", "0 -5 10 10")
|
||||||
|
.attr("refX", 18)
|
||||||
|
.attr("refY", 0)
|
||||||
|
.attr("markerWidth", 4)
|
||||||
|
.attr("markerHeight", 4)
|
||||||
|
.attr("orient", "auto")
|
||||||
|
.append("path")
|
||||||
|
.attr("d", "M0,-5L10,0L0,5")
|
||||||
|
.attr("class", "arrow-head");
|
||||||
|
|
||||||
|
// Ajout des liens
|
||||||
|
const link = svg.selectAll("path")
|
||||||
|
.data(links)
|
||||||
|
.enter().append("path")
|
||||||
|
.attr("fill", "none")
|
||||||
|
.attr("stroke", "#ee288b")
|
||||||
|
.attr("stroke-width", "2")
|
||||||
|
.attr("marker-end", "url(#arrow)");
|
||||||
|
|
||||||
|
// Ajout des nœuds
|
||||||
|
const 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", 3) // Taille des points noirs
|
||||||
|
.attr("fill", "#000"); // Couleur des points noirs
|
||||||
|
|
||||||
|
// Ajout des légendes pour les nœuds
|
||||||
|
const legend = svg.selectAll(".legend")
|
||||||
|
.data(nodes)
|
||||||
|
.enter().append("g")
|
||||||
|
.attr("class", "legend")
|
||||||
|
.attr("transform", function (d) {
|
||||||
|
return "translate(" + (d.x + 10) + "," + (d.y) + ")";
|
||||||
|
});
|
||||||
|
|
||||||
|
legend.append("text")
|
||||||
|
.text(function (d) {
|
||||||
|
return d.label;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Met à jour la position des éléments à chaque itération de la simulation
|
||||||
|
simulation.on("tick", function () {
|
||||||
|
link.attr("d", function (d) {
|
||||||
|
const dx = d.target.x - d.source.x,
|
||||||
|
dy = d.target.y - d.source.y,
|
||||||
|
dr = Math.sqrt(dx * dx + dy * dy),
|
||||||
|
sweep = 1;
|
||||||
|
return "M" + d.source.x + "," + d.source.y +
|
||||||
|
"A" + dr + "," + dr + " 0 0," + sweep + " " + d.target.x + "," + d.target.y;
|
||||||
|
});
|
||||||
|
|
||||||
|
node.attr("transform", function (d) {
|
||||||
|
return "translate(" + d.x + "," + d.y + ")";
|
||||||
|
});
|
||||||
|
|
||||||
|
legend.attr("transform", function (d) {
|
||||||
|
return "translate(" + (d.x + 10) + "," + (d.y) + ")";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fonctions de gestion du glisser-déposer
|
||||||
|
function dragstarted(d) {
|
||||||
|
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
|
||||||
|
d.fx = d.x;
|
||||||
|
d.fy = d.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragged(d) {
|
||||||
|
d.fx = d3.event.x;
|
||||||
|
d.fy = d3.event.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragended(d) {
|
||||||
|
if (!d3.event.active) simulation.alphaTarget(0);
|
||||||
|
d.fx = null;
|
||||||
|
d.fy = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue