如何编辑D3.js RadialTree的第一个节点半径?

问题描述 投票:0回答:1

你好(我的英语不太好,所以剩下的都是用GoogleTrad翻译的,我是法语=D)

对于一个项目,我正在使用 html、js 代码和 D3js 库创建一个 RadialTree。

我尝试重现第一棵树,最完整的一棵。第二个是我到目前为止所得到的。 Here is the first tree that i'm trying te reproduce.

Here the 2nd tree, which is my work.

如果你看圆的中心,在第一个径向树中,分支从中心开始呈“直线”。在第二个径向树中,分支从一开始形成一条曲线,然后到达子节点。我无法阻止这个开始的转弯,你能帮我吗?

这是我的完整代码:https://jsfiddle.net/LoChab/jetmryhb/2/

<!DOCTYPE html>
<html>
<head>
    <title>D3.js Radial Tree Example</title>
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
    <style>
        svg {
            border: solid 1px rgb(255, 51, 0);
            display: block;
            margin: 0 auto;
        }
        .link {
            fill: none;
            stroke: #194353;
            stroke-width: 5.5px;
        }
        .node {
            fill: white;
            stroke: black;
        }
        .node-text {
            font-family: 'Roboto', sans-serif;
            font-size: 12px;
            fill: black;
            stroke: none;
            white-space: pre-line;
        }
        .background-circle {
            fill: #f0f0f000;
            stroke: rgba(255, 255, 255, 0);
            stroke-width: 0px;
        }
        .center-circle {
            fill: #194353;
        }
    </style>
</head>
<body>



    <svg id="combinedSvg" width="1500" height="1500">
        <g id="radialTreeGroup">
            <!-- Contenu de l'arbre radial -->
        </g>
        <g id="pieChartGroup">
            <!-- Contenu du graphique à secteurs -->
        </g>
    </svg>

    <div id="exportButtonContainer">
        <button id="exportButton">Exporter le graphe en PNG</button>
    </div>

    <script>

// radial tree
        let root = {
            "name": "Point 1", "info":"FirstNode", "weight": 117, "children": [
            {"name":"CULTIVER", "weight": 21,
"children":[{"name":"LA QUALITE DES RELATIONS (n=13)", "weight": 13},
{"name":"ENTRAIDE ET COLLABORATION (n=3)", "weight": 3},
{"name":"L'ARTICULATION DE TEMPS COLLECTIFS ET INDIVIDUEL (n=3)", "weight": 3},
{"name":"LA CONVIVIALITE (n=2)", "weight": 2}]},
{"name":"LE CADRE ET L'ANIMATION", "weight": 12,
"children":[{"name":"UN CADRE STRUCTURE ET BIENVEILLANT QUI PERMET L'ECOUTE (n=3)", "weight": 3},
{"name":"LE RESPECT DE L'AUTONOMIE (n=2)", "weight": 2},
{"name":"LE RESPECT DU RYTHME DE CHACUN (n=2)", "weight": 2},
{"name":"LE PROFESSIONNALISME DE L'EQUIPE (n=5)", "weight": 5}]},
{"name":"LE COLLECTIF", "weight": 14,
"children":[{"name":"LE TRAVAIL (n=6)", "weight": 6},
{"name":"PRECISER (n=5)", "weight": 5},
{"name":"LA REPRISE (n=2)", "weight": 2},
{"name":"LA REGLE (n=1)", "weight": 1}]},
{"name":"RESTITUTION", "weight": 2,
"children":[{"name":"CREATION (n=1)", "weight": 1},
            ]
        }]};

        let maxDistance; // Déclaration de la variable maxDistance en dehors de la fonction

        let createRadialTree = function (input) {
            let height = 1500;
            let width = 1500;

            let svg = d3.select('#radialTreeGroup')
                .append('svg')
                .attr('width', width)
                .attr('height', height);

            let diameter = height * 8.1;
            let radius = diameter / 30.1;

            let tree = d3.tree()
                .size([2 * Math.PI, radius])
                .separation(function (a, b) {
                    if (a.parent === b.parent) {
                        return 1;
                    } else if (a.depth === b.depth) {
                        return 1.2;
                    } else {
                        return 2;
                    }
                });

            let data = d3.hierarchy(input);

            let treeData = tree(data);

            let nodes = treeData.descendants();
            let links = treeData.links();

            nodes.forEach(function (node) {
                let totalChildren = node.descendants().length - 1;
                node.totalChildren = totalChildren;
            });

            let linkWidthScale = d3.scaleLinear()
                .domain([0, d3.max(nodes, function (d) { return d.totalChildren; })])
                .range([0, 15]);

            let graphGroup = svg.append('g')
                .attr('transform', "translate(" + (width / 2) + "," + (height / 2) + ")");

            maxDistance = calculateMaxDistance(nodes);
            
            graphGroup.append("circle")
                .attr("class", "background-circle")
                .attr("r", maxDistance)
                .style("fill", "#f0f0f000");
            
            // Ajouter un cercle fixe au centre du graphe
            graphGroup.append("circle")
                .attr("class", "center-circle")
                .attr("r", 10) // rayon du cercle au centre
                .style("fill", "#194353");
                
            graphGroup.selectAll(".link")
                .data(links)
                .join("path")
                .attr("class", "link")
                .style("stroke-width", function (d) {
                    return linkWidthScale(d.target.data.weight || 1);
                })
                .attr("stroke-linecap", "round")
                .attr("d", d3.linkRadial()
                    .angle(function (d) {
                        if (d.depth === 0) { // Vérifie si c'est le nœud parent (racine)
                            return 0; // Angle fixe pour le nœud parent au centre
                        } else {
                            return d.x;
                        }
                    })
                    .radius(function (d) { return d.y; })
                );

            let nodeSizeScale = d3.scaleLinear()
                .domain([0, d3.max(nodes, function(d) { return d.depth; })])
                .range([15, 4]);

            let node = graphGroup
                .selectAll(".node")
                .data(nodes)
                .enter()
                .append("g")
                .attr("class", function(d) { return "node node-level-" + d.depth; })
                .attr("transform", function (d) {
                    let angle = (d.x - Math.PI / 2) * 180 / Math.PI; // Ajustement de l'angle de rotation
                    let radius = d.y; // Rayon du cercle
                    return `rotate(${angle}) translate(${radius}, 0)`;
                });

            node.append("circle")
                .attr("r", function(d) { return nodeSizeScale(d.depth); });

            node.filter(function (d) { return d.depth === 2; })
                .append("text")
                .attr("class", "node-text")
                .attr("dx", function (d) { return d.x < Math.PI ? 14 : -14; })
                .attr("dy", ".31em")
                .attr("text-anchor", function (d) { return d.x < Math.PI ? "start" : "end"; })
                .attr("transform", function (d) { return d.x < Math.PI ? null : "rotate(180)"; })
                .selectAll("tspan")
                .data(function (d) {
                    return d.data.name.split("\n");
                })
                .enter()
                .append("tspan")
                .attr("x", 0)
                .attr("dy", function (d, i) { return i ? "1.2em" : 0; })
                .text(function (d) { return d; })
                .call(wrapText, 300); // Appel à la fonction wrapText avec une largeur de 20 pixels

        };

        function calculateMaxDistance(nodes) {
            let maxDistance = 0;
            for (let i = 0; i < nodes.length; i++) {
                if (nodes[i].depth === 2) {
                    maxDistance = Math.max(maxDistance, nodes[i].y);
                }
            }
            return maxDistance;
        }

        function wrapText(text, width) {
            text.each(function (d) {
                if (d.depth < 1) {
                    return;
                }

                let text = d3.select(this);
                let words = text.text().split(/\s+/).reverse();
                let lineHeight = 1.2; // Ajustez la valeur ici pour définir l'interligne souhaité
                let y = text.attr("y");
                let x = text.attr("x");
                let dy = parseFloat(text.attr("dy")) || 0;
                let tspan = text.text(null).append("tspan").attr("x", x).attr("y", y).attr("dy", dy + "em");

                let line = [];
                let lineNumber = 0;
                let word;
                let wordCount = words.length;
                while ((word = words.pop())) {
                    line.push(word);
                    tspan.text(line.join(" "));
                    if (tspan.node().getComputedTextLength() > width) {
                        line.pop();
                        tspan.text(line.join(" "));
                        line = [word];
                        tspan = text
                            .append("tspan")
                            .attr("x", x)
                            .attr("y", y)
                            .attr("dx", x) // Ajout de l'attribut dx conditionnellement
                            .attr("dy", lineHeight + "em") // Utilisez une valeur fixe pour l'interligne
                            .text(word);
                    }
                }
            });
        }

// code svg
        const svgWidth = 1500;
        const svgHeight = 1500;

        const pieChartGroup = d3.select("#pieChartGroup")
            .attr("transform", `"translate(" + (width / 2) + "," + (height / 2) + "`);

        const radialTreeGroup = d3.select("#radialTreeGroup")
            .attr("transform", `translate()`);

// code création radial tree
        createRadialTree(root);

// Opération à appliquer à toutes les datas ayant le label "Bout"
function applyOperation(data) {
  const updatedData = data.map(d => {
    if (d.label === "Bout") {
      // Effectuer l'opération souhaitée sur la valeur ici
      d.value = ((2.3 / 2) + (((d.value)-1)*1.1) + (1.4/2));
    }
    else if (d.label === "") {
      // Effectuer l'opération souhaitée sur la valeur ici
      d.value = ((((d.value) - 1) * 1.1) + (1.4));
    }
    return d;
  });

  return updatedData;
}

// Données pour les secteurs du graphique
  const data = [ 
    { label: "Bout", value: 4}, 
    { label: "", value: 4}, 
    { label: "", value: 4},
    { label: "", value: 3},
    { label: "", value: 2}, 
    { label: "", value: 3}, 
    { label: "", value: 3}, 
    { label: "", value: 2}, 
    { label: "", value: 3}, 
    { label: "", value: 2}, 
    { label: "", value: 1}, 
    { label: "", value: 3}, 
    { label: "", value: 2}, 
    { label: "Bout", value: 1},  
    // Ajoutez autant de secteurs que vous le souhaitez avec leurs angles respectifs
    // Value = degré, valeur
  ];

// Appliquer l'opération aux données ayant le label "Bout"
const updatedData = applyOperation(data);

console.log(updatedData);

  // Dimensions du graphique
  const width = 1500;
  const height = 1500;
  const radius = maxDistance;

  // Deux jeux de couleurs alternées
  const colors = ["#98d9ff", "#d4efff"];

  // Création d'un générateur d'angles
  const pie = d3.pie()
    .value(d => d.value)
    .sort(null);

  // Sélection de la zone du graphique
  const svg = d3.select("#pieChartGroup")
    .append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", `translate(${width / 2}, ${height / 2})`);

  // Création des arcs pour les secteurs
  const arc = d3.arc()
    .innerRadius(0)
    .outerRadius(radius);

  // Génération du graphique
  const arcs = svg.selectAll("arc")
    .data(pie(data))
    .enter()
    .append("g");

  arcs.append("path")
    .attr("d", arc)
    .attr("fill", (d, i) => colors[i % colors.length]); // Alterne entre les deux jeux de couleurs

  // Ajout d'étiquettes à chaque secteur (optionnel)
  // arcs.append("text")
  //  .attr("transform", d => `translate(${arc.centroid(d)})`)
  //  .attr("text-anchor", "middle")
  //  .text(d => d.data.label);

    pieChartGroup.lower(0); // pour mettre les secteurs en arrière-plan

    // EXPORT
// Fonction pour exporter le graphe en PNG
function exportGraphToPng() {
    const combinedSvg = document.getElementById("combinedSvg");

    html2canvas(combinedSvg).then(function(canvas) {
        // Convertir le canvas en image
        const imgData = canvas.toDataURL("image/png");

        // Convertir l'image en un objet Blob
        const blob = dataURLtoBlob(imgData);

        // Utiliser la librairie FileSaver.js pour déclencher le téléchargement
        saveAs(blob, "graph.png");
    });
}

// Attendez que le contenu de la page soit chargé
document.addEventListener('DOMContentLoaded', function() {
    // Associer l'événement de clic au bouton pour déclencher l'export
    const exportButton = document.getElementById("exportButton");
    exportButton.addEventListener("click", exportGraphToPng);
    
    // ... Le reste de votre code JavaScript existant ...
});

    </script>
</body>
</html>

感谢您的帮助!

如果你看圆的中心,在第一个径向树中,分支从中心开始呈“直线”。在第二个径向树中,分支从一开始形成一条曲线,然后到达子节点。我无法阻止这个开始的转弯,你能帮我吗?

javascript d3.js tree radius radial
1个回答
0
投票

您可以以不同的方式处理第一个链接,例如绘制链接时的路径:

    .attr("d",(d)=>{
        if (d.source.depth === 0) {
            // strait line for first link
            return d3.linkRadial()
                .angle(0)
                .radius(function (d) {
                    return d.y;
                })(d)

        } else {
            return d3.linkRadial()
                .angle(function (d, i) {
                    return d.x;
                })
                .radius(function (d) {
                    return d.y;
                })(d)
        }
        }
    )
    .attr('transform',(d)=>{
         if(d.target.depth<= 1 && d.source.depth===0) {
             // rotate first line only
             return`rotate(${d.target.x*(180/Math.PI)})`;
         }
         return ''
    });

// radial tree
let root = {
  "name": "Point 1",
  "info": "FirstNode",
  "weight": 117,
  "children": [{
      "name": "CULTIVER",
      "weight": 21,
      "children": [{
          "name": "LA QUALITE DES RELATIONS (n=13)",
          "weight": 13
        },
        {
          "name": "ENTRAIDE ET COLLABORATION (n=3)",
          "weight": 3
        },
        {
          "name": "L'ARTICULATION DE TEMPS COLLECTIFS ET INDIVIDUEL (n=3)",
          "weight": 3
        },
        {
          "name": "LA CONVIVIALITE (n=2)",
          "weight": 2
        }
      ]
    },
    {
      "name": "LE CADRE ET L'ANIMATION",
      "weight": 12,
      "children": [{
          "name": "UN CADRE STRUCTURE ET BIENVEILLANT QUI PERMET L'ECOUTE (n=3)",
          "weight": 3
        },
        {
          "name": "LE RESPECT DE L'AUTONOMIE (n=2)",
          "weight": 2
        },
        {
          "name": "LE RESPECT DU RYTHME DE CHACUN (n=2)",
          "weight": 2
        },
        {
          "name": "LE PROFESSIONNALISME DE L'EQUIPE (n=5)",
          "weight": 5
        }
      ]
    },
    {
      "name": "LE COLLECTIF",
      "weight": 14,
      "children": [{
          "name": "LE TRAVAIL (n=6)",
          "weight": 6
        },
        {
          "name": "PRECISER (n=5)",
          "weight": 5
        },
        {
          "name": "LA REPRISE (n=2)",
          "weight": 2
        },
        {
          "name": "LA REGLE (n=1)",
          "weight": 1
        }
      ]
    },
    {
      "name": "RESTITUTION",
      "weight": 2,
      "children": [{
        "name": "CREATION (n=1)",
        "weight": 1
      }, ]
    }
  ]
};

let maxDistance; // Déclaration de la variable maxDistance en dehors de la fonction

let createRadialTree = function(input) {
  let height = 1500;
  let width = 1500;

  let svg = d3.select('#radialTreeGroup')
    .append('svg')
    .attr('width', width)
    .attr('height', height);

  let diameter = height * 8.1;
  let radius = diameter / 30.1;

  let tree = d3.tree()
    .size([2 * Math.PI, radius])
    .separation(function(a, b) {
      if (a.parent === b.parent) {
        return 1;
      } else if (a.depth === b.depth) {
        return 1.2;
      } else {
        return 2;
      }
    });

  let data = d3.hierarchy(input);

  let treeData = tree(data);

  let nodes = treeData.descendants();
  let links = treeData.links();

  nodes.forEach(function(node) {
    let totalChildren = node.descendants().length - 1;
    node.totalChildren = totalChildren;
  });

  let linkWidthScale = d3.scaleLinear()
    .domain([0, d3.max(nodes, function(d) {
      return d.totalChildren;
    })])
    .range([0, 15]);

  let graphGroup = svg.append('g')
    .attr('transform', "translate(" + (width / 2) + "," + (height / 2) + ")");

  maxDistance = calculateMaxDistance(nodes);

  graphGroup.append("circle")
    .attr("class", "background-circle")
    .attr("r", maxDistance)
    .style("fill", "#f0f0f000");

  // Ajouter un cercle fixe au centre du graphe
  graphGroup.append("circle")
    .attr("class", "center-circle")
    .attr("r", 10) // rayon du cercle au centre
    .style("fill", "#194353");

  graphGroup.selectAll(".link")
    .data(links)
    .join("path")
    .attr("class", "link")
    .style("stroke-width", function(d) {
      return linkWidthScale(d.target.data.weight || 1);
    })
    .attr("stroke-linecap", "round")
    .attr("d", (d) => {
      if (d.source.depth === 0) {
        // strait line for first link
        return d3.linkRadial()
          .angle(0)
          .radius(function(d) {
            return d.y;
          })(d)

      } else {
        return d3.linkRadial()
          .angle(function(d, i) {
            return d.x;
          })
          .radius(function(d) {
            return d.y;
          })(d)
      }
    })
    .attr('transform', (d) => {
      if (d.target.depth <= 1 && d.source.depth === 0) {
        // rotate first line only
        return `rotate(${d.target.x*(180/Math.PI)})`;
      }
      return ''
    });

  let nodeSizeScale = d3.scaleLinear()
    .domain([0, d3.max(nodes, function(d) {
      return d.depth;
    })])
    .range([15, 4]);

  let node = graphGroup
    .selectAll(".node")
    .data(nodes)
    .enter()
    .append("g")
    .attr("class", function(d) {
      return "node node-level-" + d.depth;
    })
    .attr("transform", function(d) {
      let angle = (d.x - Math.PI / 2) * 180 / Math.PI; // Ajustement de l'angle de rotation
      let radius = d.y; // Rayon du cercle
      return `rotate(${angle}) translate(${radius}, 0)`;
    });

  node.append("circle")
    .attr("r", function(d) {
      return nodeSizeScale(d.depth);
    });

  node.filter(function(d) {
      return d.depth === 2;
    })
    .append("text")
    .attr("class", "node-text")
    .attr("dx", function(d) {
      return d.x < Math.PI ? 14 : -14;
    })
    .attr("dy", ".31em")
    .attr("text-anchor", function(d) {
      return d.x < Math.PI ? "start" : "end";
    })
    .attr("transform", function(d) {
      return d.x < Math.PI ? null : "rotate(180)";
    })
    .selectAll("tspan")
    .data(function(d) {
      return d.data.name.split("\n");
    })
    .enter()
    .append("tspan")
    .attr("x", 0)
    .attr("dy", function(d, i) {
      return i ? "1.2em" : 0;
    })
    .text(function(d) {
      return d;
    })
    .call(wrapText, 300); // Appel à la fonction wrapText avec une largeur de 20 pixels

};

function calculateMaxDistance(nodes) {
  let maxDistance = 0;
  for (let i = 0; i < nodes.length; i++) {
    if (nodes[i].depth === 2) {
      maxDistance = Math.max(maxDistance, nodes[i].y);
    }
  }
  return maxDistance;
}

function wrapText(text, width) {
  text.each(function(d) {
    if (d.depth < 1) {
      return;
    }

    let text = d3.select(this);
    let words = text.text().split(/\s+/).reverse();
    let lineHeight = 1.2; // Ajustez la valeur ici pour définir l'interligne souhaité
    let y = text.attr("y");
    let x = text.attr("x");
    let dy = parseFloat(text.attr("dy")) || 0;
    let tspan = text.text(null).append("tspan").attr("x", x).attr("y", y).attr("dy", dy + "em");

    let line = [];
    let lineNumber = 0;
    let word;
    let wordCount = words.length;
    while ((word = words.pop())) {
      line.push(word);
      tspan.text(line.join(" "));
      if (tspan.node().getComputedTextLength() > width) {
        line.pop();
        tspan.text(line.join(" "));
        line = [word];
        tspan = text
          .append("tspan")
          .attr("x", x)
          .attr("y", y)
          .attr("dx", x) // Ajout de l'attribut dx conditionnellement
          .attr("dy", lineHeight + "em") // Utilisez une valeur fixe pour l'interligne
          .text(word);
      }
    }
  });
}

// code svg
const svgWidth = 1500;
const svgHeight = 1500;

const pieChartGroup = d3.select("#pieChartGroup")
  .attr("transform", `"translate(" + (width / 2) + "," + (height / 2) + "`);

const radialTreeGroup = d3.select("#radialTreeGroup")
  .attr("transform", `translate()`);

// code création radial tree
createRadialTree(root);

// Opération à appliquer à toutes les datas ayant le label "Bout"
function applyOperation(data) {
  const updatedData = data.map(d => {
    if (d.label === "Bout") {
      // Effectuer l'opération souhaitée sur la valeur ici
      d.value = ((2.3 / 2) + (((d.value) - 1) * 1.1) + (1.4 / 2));
    } else if (d.label === "") {
      // Effectuer l'opération souhaitée sur la valeur ici
      d.value = ((((d.value) - 1) * 1.1) + (1.4));
    }
    return d;
  });

  return updatedData;
}

// Données pour les secteurs du graphique
const data = [{
    label: "Bout",
    value: 4
  },
  {
    label: "",
    value: 4
  },
  {
    label: "",
    value: 4
  },
  {
    label: "",
    value: 3
  },
  {
    label: "",
    value: 2
  },
  {
    label: "",
    value: 3
  },
  {
    label: "",
    value: 3
  },
  {
    label: "",
    value: 2
  },
  {
    label: "",
    value: 3
  },
  {
    label: "",
    value: 2
  },
  {
    label: "",
    value: 1
  },
  {
    label: "",
    value: 3
  },
  {
    label: "",
    value: 2
  },
  {
    label: "Bout",
    value: 1
  },
  // Ajoutez autant de secteurs que vous le souhaitez avec leurs angles respectifs
  // Value = degré, valeur
];

// Appliquer l'opération aux données ayant le label "Bout"
const updatedData = applyOperation(data);

console.log(updatedData);

// Dimensions du graphique
const width = 1500;
const height = 1500;
const radius = maxDistance;

// Deux jeux de couleurs alternées
const colors = ["#98d9ff", "#d4efff"];

// Création d'un générateur d'angles
const pie = d3.pie()
  .value(d => d.value)
  .sort(null);

// Sélection de la zone du graphique
const svg = d3.select("#pieChartGroup")
  .append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
  .attr("transform", `translate(${width / 2}, ${height / 2})`);

// Création des arcs pour les secteurs
const arc = d3.arc()
  .innerRadius(0)
  .outerRadius(radius);

// Génération du graphique
const arcs = svg.selectAll("arc")
  .data(pie(data))
  .enter()
  .append("g");

arcs.append("path")
  .attr("d", arc)
  .attr("fill", (d, i) => colors[i % colors.length]); // Alterne entre les deux jeux de couleurs

// Ajout d'étiquettes à chaque secteur (optionnel)
// arcs.append("text")
//  .attr("transform", d => `translate(${arc.centroid(d)})`)
//  .attr("text-anchor", "middle")
//  .text(d => d.data.label);

pieChartGroup.lower(0); // pour mettre les secteurs en arrière-plan

// EXPORT
// Fonction pour exporter le graphe en PNG
function exportGraphToPng() {
  const combinedSvg = document.getElementById("combinedSvg");

  html2canvas(combinedSvg).then(function(canvas) {
    // Convertir le canvas en image
    const imgData = canvas.toDataURL("image/png");

    // Convertir l'image en un objet Blob
    const blob = dataURLtoBlob(imgData);

    // Utiliser la librairie FileSaver.js pour déclencher le téléchargement
    saveAs(blob, "graph.png");
  });
}

// Attendez que le contenu de la page soit chargé
document.addEventListener('DOMContentLoaded', function() {
  // Associer l'événement de clic au bouton pour déclencher l'export
  const exportButton = document.getElementById("exportButton");
  exportButton.addEventListener("click", exportGraphToPng);

  // ... Le reste de votre code JavaScript existant ...
});
svg {
  border: solid 1px rgb(255, 51, 0);
  display: block;
  margin: 0 auto;
}

.link {
  fill: none;
  stroke: #194353;
  stroke-width: 5.5px;
}

.node {
  fill: white;
  stroke: black;
}

.node-text {
  font-family: 'Roboto', sans-serif;
  font-size: 12px;
  fill: black;
  stroke: none;
  white-space: pre-line;
}

.background-circle {
  fill: #f0f0f000;
  stroke: rgba(255, 255, 255, 0);
  stroke-width: 0px;
}

.center-circle {
  fill: #194353;
}
<!DOCTYPE html>
<html>

<head>
  <title>D3.js Radial Tree Example</title>
  <script src="https://d3js.org/d3.v6.min.js"></script>
  <script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
  <style>

  </style>
</head>

<body>



  <svg id="combinedSvg" width="1500" height="1500">
        <g id="radialTreeGroup">
            <!-- Contenu de l'arbre radial -->
        </g>
        <g id="pieChartGroup">
            <!-- Contenu du graphique à secteurs -->
        </g>
    </svg>

  <div id="exportButtonContainer">
    <button id="exportButton">Exporter le graphe en PNG</button>
  </div>

  <script>
  </script>
</body>

</html>

© www.soinside.com 2019 - 2024. All rights reserved.