Original question:

我想视觉突出每个 node 的属性.为此,我添加了另一个小圆圈.此外,我想在每个蓝色圆圈中添加一个短字符串.我try 了不同的方法,最常见的似乎是在初始化过程中立即添加.append("Text").不幸的是,我当时还不走运.

我怎样才能做到这一点呢?

MODIFIED, as kikon mentioned:

我按照建议做了,它起作用了.但是如何将文本分配给每个 node 呢?现在,它只出现在第一个子元素的圆圈上.

enter image description here

 var width = window.innerWidth,
            height = window.innerHeight;

        var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height)
            .call(d3.zoom().on("zoom", function(event) {
                svg.attr("transform", event.transform)
            }))
            .append("g")

        ////////////////////////
        // outer force layout

        var data = {
            "nodes":[
                { "id": "A", "shoes": [{"brand": "Nike"}, {"brand": "Adidas"}, {"brand": "Adidas"}]}, 
                { "id": "B", "shoes": [{"brand": "Nike"}, {"brand": "Adidas"}, {"brand": "Adidas"}, {"brand": "Adidas"}]},
                { "id": "C", "shoes": []},
            ],
            "links": [
                { "source": "A", "target": "B"},
                { "source": "B", "target": "C"},
                { "source": "C", "target": "A"}
            ]
        };

        var simulation = d3.forceSimulation()
            .force("size", d3.forceCenter(width / 2, height / 2))
            .force("charge", d3.forceManyBody().strength(-1000))
            .force("link", d3.forceLink().id(function (d) { return d.id }).distance(250))
       
        linksContainer = svg.append("g").attr("class", "linkscontainer")
        nodesContainer = svg.append("g").attr("class", "nodesContainer")
       
        var links = linksContainer.selectAll("g")
            .data(data.links)
            .join("g")
            .attr("fill", "transparent")

        var linkLine = linksContainer.selectAll(".linkPath")
            .data(data.links)
            .join("path")
            .attr("stroke", "red")
            .attr("fill", "transparent")
            .attr("stroke-width", 3)
        
        nodes = nodesContainer.selectAll(".nodes")
            .data(data.nodes, function (d) { return d.id; })
            .join("g")
            .attr("class", "nodes")
            .attr("id", function (d) { return d.id; })
            .call(d3.drag()
                .on("start", dragStarted)
                .on("drag", dragged)
                .on("end", dragEnded)
            )

        nodes.selectAll("circle")
            .data(d => [d])
            .join("circle")
            .style("fill", "lightgrey")
            .style("stroke", "blue")
            .attr("r", 40)

        var eventCircle = nodes.selectAll("g")
            .data(data.nodes)
            .enter()
            .append("g")
            
        eventCircle.append("g")
            .selectAll("circle-small")
            .data(x => x.shoes)
            .enter()
            .append('circle')
            .attr('r', 15)
            .attr("fill", "blue")
            .attr('cx', function (d,i) {
                const factor = (i / 40) * (15 / 2) * 5;
                return 40 * Math.cos(factor - Math.PI * 0.5);
            })
            .attr('cy', function (d,i) { 
                const factor = (i / 40) * (15 / 2) * 5;
                return 40 * Math.sin(factor - Math.PI * 0.5);
            })
            .attr("class", "circle-small")

        eventCircle.append("text")
            .attr("x", function(d) {
                return -4
            })
            .attr("y", function(d) {
                return  -34
            })
            .attr("font-size", 15)
            .attr("fill", "white")
            .attr("pointer-events", "cursor")
            .text(function (d) {
                return "1"
            })

        simulation
            .nodes(data.nodes)
            .on("tick", tick)

        simulation
            .force("link")
            .links(data.links)


            
        function tick() {
            linkLine.attr("d", function(d) {
                var dx = (d.target.x - d.source.x),
                    dy = (d.target.y - d.source.y),
                    dr = Math.sqrt(dx * dx + dy * dy)

                return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
            })
                

            nodes
                .attr("transform", d => `translate(${d.x}, ${d.y})`);
        }

        function dragStarted(event, d) {
            if (!event.active) simulation.alphaTarget(0.3).restart();
            d.fx = d.x;
            d.fy = d.y;
        }

        function dragged(event, d) {
            d.fx = event.x;
            d.fy = event.y;
        }

        function dragEnded(event, d) {
            if (!event.active) simulation.alphaTarget(0);
            d.fx = null;
            d.fy = null;
        }
   body {
        background: whitesmoke,´;
        overflow: hidden;
        margin: 0px;
    }
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>D3v7</title>
    <!-- d3.js framework -->
    <script src="https://d3js.org/d3.v7.js"></script>
</head>



<body>
</body>
</html>

推荐答案

如果您判断您的SVG,您将看到您正在将几个圆圈一个接一个地附加在一起.

只需 for each 品牌添加一个<g>,并相应地进行翻译.

var eventCircle = nodes.selectAll(null)
  .data(d => d.shoes)
  .enter()
  .append("g")
  .attr("transform", function(d, i) {
    const factor = (i / 40) * (15 / 2) * 5;
    return `translate(${40 * Math.cos(factor - Math.PI * 0.5)},${40 * Math.sin(factor - Math.PI * 0.5)})`;
  });

...然后将你的圈子和文本附加到这些群中.

以下是您修改后的演示:

var width = window.innerWidth,
  height = window.innerHeight;

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)
  .call(d3.zoom().on("zoom", function(event) {
    svg.attr("transform", event.transform)
  }))
  .append("g")

////////////////////////
// outer force layout

var data = {
  "nodes": [{
      "id": "A",
      "shoes": [{
        "brand": "Nike"
      }, {
        "brand": "Adidas"
      }, {
        "brand": "Adidas"
      }]
    },
    {
      "id": "B",
      "shoes": [{
        "brand": "Nike"
      }, {
        "brand": "Adidas"
      }, {
        "brand": "Adidas"
      }, {
        "brand": "Adidas"
      }]
    },
    {
      "id": "C",
      "shoes": []
    },
  ],
  "links": [{
      "source": "A",
      "target": "B"
    },
    {
      "source": "B",
      "target": "C"
    },
    {
      "source": "C",
      "target": "A"
    }
  ]
};

var simulation = d3.forceSimulation()
  .force("size", d3.forceCenter(width / 2, height / 2))
  .force("charge", d3.forceManyBody().strength(-1000))
  .force("link", d3.forceLink().id(function(d) {
    return d.id
  }).distance(250))

linksContainer = svg.append("g").attr("class", "linkscontainer")
nodesContainer = svg.append("g").attr("class", "nodesContainer")

var links = linksContainer.selectAll("g")
  .data(data.links)
  .join("g")
  .attr("fill", "transparent")

var linkLine = linksContainer.selectAll(".linkPath")
  .data(data.links)
  .join("path")
  .attr("stroke", "red")
  .attr("fill", "transparent")
  .attr("stroke-width", 3)

nodes = nodesContainer.selectAll(".nodes")
  .data(data.nodes, function(d) {
    return d.id;
  })
  .join("g")
  .attr("class", "nodes")
  .attr("id", function(d) {
    return d.id;
  })
  .call(d3.drag()
    .on("start", dragStarted)
    .on("drag", dragged)
    .on("end", dragEnded)
  )

nodes.selectAll("circle")
  .data(d => [d])
  .join("circle")
  .style("fill", "lightgrey")
  .style("stroke", "blue")
  .attr("r", 40)

var eventCircle = nodes.selectAll(null)
  .data(d => d.shoes)
  .enter()
  .append("g")
  .attr("transform", function(d, i) {
    const factor = (i / 40) * (15 / 2) * 5;
    return `translate(${40 * Math.cos(factor - Math.PI * 0.5)},${40 * Math.sin(factor - Math.PI * 0.5)})`;
  });

eventCircle.append('circle')
  .attr('r', 15)
  .attr("fill", "blue")
  .attr("class", "circle-small")

eventCircle.append("text")
  .attr("font-size", 10)
  .attr("fill", "white")
  .style("text-anchor", "middle")
  .attr("pointer-events", "cursor")
  .text(function(d) {
    return d.brand;
  })

simulation
  .nodes(data.nodes)
  .on("tick", tick)

simulation
  .force("link")
  .links(data.links)



function tick() {
  linkLine.attr("d", function(d) {
    var dx = (d.target.x - d.source.x),
      dy = (d.target.y - d.source.y),
      dr = Math.sqrt(dx * dx + dy * dy)

    return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
  })


  nodes
    .attr("transform", d => `translate(${d.x}, ${d.y})`);
}

function dragStarted(event, d) {
  if (!event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

function dragged(event, d) {
  d.fx = event.x;
  d.fy = event.y;
}

function dragEnded(event, d) {
  if (!event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}
body {
  background: whitesmoke, ´;
  overflow: hidden;
  margin: 0px;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>D3v7</title>
  <!-- d3.js framework -->
  <script src="https://d3js.org/d3.v7.js"></script>
</head>



<body>
</body>

</html>

Javascript相关问答推荐

Javascript,部分重排序数组

为什么我的列表直到下一次提交才更新值/onChange

react—router v6:路由没有路径

数字时钟在JavaScript中不动态更新

我正在建立一个基于文本的游戏在react ,我是从JS转换.我怎样才能使变量变呢?

Next.js服务器端组件请求,如何发送我的cookie token?

Nextjs 13.4 Next-Auth 4.2登录(&Quot;凭据&,{});不工作

如何 for each 输入动态设置输入变更值

未捕获的运行时错误:调度程序为空

为列表中的项目设置动画

如何根据查询结果重新排列日期

JavaScript将字符串数字转换为整数

我们是否可以在reactjs中创建多个同名的路由

我如何才能让p5.js在不使用实例模式的情况下工作?

由于http.get,*ngIf的延迟很大

如何为两条动态路由创建一个页面?

Playwright:ReferenceError:browserContext未定义

使用JavaScript或PHP从div ID值创建锚标记和链接

如何使用JavaScript将动态表上具有相同值的行与某些条件合并

Tinymce CREATE COMMENT函数不读取更新状态