AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / user-22403699

LoChab's questions

Martin Hope
LoChab
Asked: 2023-08-17 16:19:46 +0800 CST

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

  • 6

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

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

我尝试重现第一棵树,也是最完整的一棵。第二个是我到目前为止所得到的。 这是我尝试复制的第一棵树。

这是第二棵树,这是我的作品。

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

这是我的完整代码: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
  • 1 个回答
  • 16 Views

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

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

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve