javascript - 进入-更新-退出模式后节点的 x 和 y 属性丢失

标签 javascript d3.js force-layout

我正在尝试在 D3v4 中转换力模拟的节点。原始力是用鲨鱼家族聚合的节点正确绘制的,我想点击“格陵兰鲨鱼”按钮,这样只有名为“格陵兰鲨鱼”的节点可见(这是有效的),我会就像这样,如果用户单击“按家庭划分的鲨鱼”按钮,力就会回到原来的位置。但是,如果我在点击“格陵兰鲨鱼”后点击“鲨鱼家族”,只有两个节点可见,因为除了直接从格陵兰鲨鱼节点更新的节点外,其余节点没有 cx 和 cy 所以它们都堆叠在彼此之上,默认位置为 0,0。我不确定为什么 cx 和 cy 属性丢失,这可能是我的输入、更新、退出模式中的错误吗?

下面是相关代码,这里是可视化 + 代码的 Plunker 链接 https://plnkr.co/edit/rvbOJT2fIgxBlsqOtXR4 仅可视化 https://run.plnkr.co/plunks/rvbOJT2fIgxBlsqOtXR4/

      // Original force simulation by family

      var simulation = d3.forceSimulation();

      simulation.force('x', d3.forceX(function(d) {
              var i = mapIndex(d.family);
              return xposition(i)
          }).strength(0.03))
          .force('y', d3.forceY(function(d) {
              var i = mapIndex(d.family);
              return yposition(i)
          }).strength((0.03)))
          .force('collide', d3.forceCollide(function(d) {
              return radiusScale(+d.size)
          })).velocityDecay(0.1).alphaDecay(0.001);


      var circles = g.selectAll(".sharks")
          .data(nodes)
          .enter().append("circle")
          .attr("class", "sharks")
          .attr("r", function(d) {
              return radiusScale(+d.size)
          })
          .attr("fill", function(d) {
              return colorScale(d.family)
          })
          .attr('stroke', '')


      simulation.nodes(nodes)
          .on('tick', ticked);


      nodes.forEach(function(d) {
          d.x = familyXScale(d.family)
          d.y = yPositionScale(sharks.indexOf(d.name))
      })


      function ticked() {
          circles
              .attr("cx", function(d) {
                  return d.x
              })
              .attr("cy", function(d) {
                  return d.y
              })
      }

      function charge(d) {
          return -Math.pow(d.radius, 2.0) * forceStrength;
      }



       // function for only showing one node (greenland shark)
      function greenlandShark() {
          console.log('greenlandShark');
          console.log(nodes);

          var newNodes = filterNodes('common_name', 'Greenland shark');

          circles = g.selectAll(".sharks").data(newNodes);

          circles.exit()
              .transition()
              .duration(1000)
              .attr("r", 0)
              .remove();

          circles
              .attr('r', function(d) {
                  return radiusScale(+d.size)
              })
              .attr('fill', function(d) {
                  return colorScale(d.family)
              });

          simulation.nodes(newNodes)
              .on('tick', ticked);

          simulation.force('x', d3.forceX().strength(0.03).x(center.x))
              .force('y', d3.forceY(function(d) {
                  return height / 2
              }).strength((0.03)));

          simulation.alpha(1).restart();

      }

      function filterNodes(key, group) {
          var newnodes = nodes.filter(function(d) {
              return d[key] == group;
          });
          return newnodes;;
      }

      // function for visualizing all nodes again organized by family     
      function sharksByFamily() {

          circles = g.selectAll(".sharks").data(nodes);

          circles.exit().transition().duration(750)
              .attr("r", 0)
              .remove();

          circles.transition().duration(750)
              .attr("fill", function(d) {
                  return colorScale(d.family)
              }).attr("r", function(d) {
                  return radiusScale(+d.size);
              })

          circles.enter().append("circle").attr("class", "sharks")
              .attr("fill", function(d) {
                  return colorScale(d.family)
              }).attr("r", function(d) {
                  return radiusScale(+d.size);
              })
              .attr('stroke', '')

          simulation.force('x', d3.forceX(function(d) {
                  var i = mapIndex(d.family);
                  return xposition(i)
              }).strength(0.03))
              .force('y', d3.forceY(function(d) {
                  var i = mapIndex(d.family);
                  return yposition(i)
              }).strength((0.03)))
              .force('collide', d3.forceCollide(function(d) {
                  return radiusScale(+d.size)
              })).velocityDecay(0.1).alphaDecay(0.001);


          // cx cy not showing up for nodes
          simulation.nodes(nodes)
              .on('tick', ticked);

          simulation.alpha(1).restart();

      }

最佳答案

属性在那里,那不是问题。问题只是 ticked 函数中 circles 的定义。

例如,如果您这样做:

function ticked() {
    g.selectAll("circle").attr("cx", function(d) {
            return d.x
        })
        .attr("cy", function(d) {
            return d.y
        })
};

它会起作用的。这是你的 fork 插件:https://plnkr.co/edit/szhg8eUYQUMxHcLmBF8N?p=preview

但是,这里惯用​​的解决方案是合并 sharksByFamilyRev 函数内的选择:

circles = circles.enter().append("circle").attr("class", "sharks")
    .attr("fill", function(d) {
        return colorScale(d.family)
    }).attr("r", function(d) {
        return radiusScale(+d.size);
    })
    .attr('stroke', '')
    .merge(circles);

这是进行了更改的插件:https://plnkr.co/edit/pBPJUhEKQIPnB0ammGDd?p=preview

PS:您在该代码中还有其他问题,这些问题与当前问题无关(例如混合 jQuery 和 D3、重复代码等...)。

关于javascript - 进入-更新-退出模式后节点的 x 和 y 属性丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54210667/

相关文章:

javascript - 'this' 上下文在赋值过程中丢失,但也不完全丢失?

javascript - 圆环图 : how to flip upside down numbers?

javascript - D3 : Sunburst chart with root node on the outside ring

javascript - 如何在扩展组件(Material-UI + ReactJS)时保留组件(Card 组件)的位置?

javascript - jquery onclick 运行两次

php - POST 数据发送并将 URL 更改为相同

javascript - d3 对立图表 Axis 对齐问题

d3.js - 迭代 D3js 中已经创建的节点

javascript - 无法在 d3 中选择 SVG foreignObject 元素

javascript - 带有对象条目的 d3.js forceSimulation()