AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 76919648
Accepted
LoChab
LoChab
Asked: 2023-08-17 16:19:46 +0800 CST2023-08-17 16:19:46 +0800 CST 2023-08-17 16:19:46 +0800 CST

Como editar o raio do primeiro nó de um RadialTree D3.js?

  • 772

Olá (meu inglês não é tão bom, então o resto é traduzido com o GoogleTrad, sou francês =D)

Para um projeto, estou criando um radialtree com html, código js e a biblioteca D3js.

Tento reproduzir a primeira árvore, a mais completa. O 2º é o que estou conseguindo até agora. Aqui está a primeira árvore que estou tentando reproduzir.

Aqui a 2ª árvore, que é um trabalho meu.

Se você olhar para o centro do círculo, na primeira árvore radial os galhos vão em uma "linha reta" a partir do centro. Na segunda árvore radial, as ramificações formam uma curva no início e depois vão para os nós filhos. Não consigo impedir esta curva inicial, você pode me ajudar?

Aqui está o meu código completo: 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>

Obrigado pela ajuda !

Se você olhar para o centro do círculo, na primeira árvore radial os galhos vão em uma "linha reta" a partir do centro. Na segunda árvore radial, as ramificações formam uma curva no início e depois vão para os nós filhos. Não consigo impedir esta curva inicial, você pode me ajudar?

javascript
  • 1 1 respostas
  • 16 Views

1 respostas

  • Voted
  1. Best Answer
    pernifloss
    2023-08-17T17:27:16+08:002023-08-17T17:27:16+08:00

    You can handle first links differently for example for your paths when you draw links:

        .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>

    • 0

relate perguntas

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    destaque o código em HTML usando <font color="#xxx">

    • 2 respostas
  • Marko Smith

    Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}?

    • 1 respostas
  • Marko Smith

    Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)?

    • 2 respostas
  • Marko Smith

    Por que as compreensões de lista criam uma função internamente?

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 respostas
  • Marko Smith

    Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)?

    • 4 respostas
  • Marko Smith

    Por que o construtor de uma variável global não é chamado em uma biblioteca?

    • 1 respostas
  • Marko Smith

    Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto?

    • 1 respostas
  • Marko Smith

    Somente operações bit a bit para std::byte em C++ 17?

    • 1 respostas
  • Martin Hope
    fbrereto Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi Por que as compreensões de lista criam uma função internamente? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A formato fmt %H:%M:%S sem decimais 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python std::views::filter do C++20 não filtrando a visualização corretamente 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa Por que o construtor de uma variável global não é chamado em uma biblioteca? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev Por que os compiladores perdem a vetorização aqui? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan Somente operações bit a bit para std::byte em C++ 17? 2023-08-17 17:13:58 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve