首页 > 解决方案 > d3.js 想在 dragend 上更改节点样式

问题描述

我有一个 d3.js 图表,允许用户单击并拖动节点。一旦他们拖动一个节点,我就认为它是“固定的”。一旦它得到修复,我想通过将节点的笔划更改为不同的颜色来直观地显示固定节点和非固定节点之间的差异。

但是,我不知道将更改笔画宽度的逻辑放在哪里。现在,我在最初绘制圆圈时放置了逻辑,但在拖动节点后它不会更新。我应该在哪里进行逻辑检查和样式更改?

这是我的代码。注意最后的.style变化node.append("circle")

d3.dsv(",", "board_games.csv", function(d) {
  return {
    source: d.source,
    target: d.target,
    value: +d.value
  }
}).then(function(data) {

  var links = data;

  var nodes = {};

  // compute the distinct nodes from the links.
  links.forEach(function(link) {
      link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
      link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
  });

  var width = 1200,
      height = 700;

  var force = d3.forceSimulation()
      .nodes(d3.values(nodes))
      .force("link", d3.forceLink(links).distance(100))
      .force('center', d3.forceCenter(width / 2, height / 2))
      .force("x", d3.forceX())
      .force("y", d3.forceY())
      .force("charge", d3.forceManyBody().strength(-250))
      .alphaTarget(1)
      .on("tick", tick);

  var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);

  // add the links
  var path = svg.append("g")
      .selectAll("path")
      .data(links)
      .enter()
      .append("path")
      .attr("class", function(d) { return "link " + d.type; });

  // define the nodes
  var node = svg.selectAll(".node")
      .data(force.nodes())
      .enter().append("g")
      .attr("class", "node")
      .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended));

  node.append("circle")
      .attr("r", function(d) {
         d.weight = 5;
         var minRadius = 10;
         return minRadius + (d.weight * 2);
       })
       .style("stroke", function(d){ if(d.fixed == true) {return 'gray'} else {return 'green'} });

    // add the curvy lines
  function tick() {
      path.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;
      });

      node.attr("transform", function(d) {
          return "translate(" + d.x + "," + d.y + ")";
      });
  };

  function dragstarted(d) {
      if (!d3.event.active) force.alphaTarget(0.3).restart();
      d.fx = d.x;
      d.fy = d.y;
  };

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

  function dragended(d) {
      if (!d3.event.active) force.alphaTarget(0);
      d.fixed = true;
      if (d.fixed == true) {
          d.fx = d.x;
          d.fy = d.y;
      }
      else {
          d.fx = null;
          d.fy = null;
      }
  };

}).catch(function(error) {
  console.log(error);
});

我的 csv 看起来像这样:

source,target,value
Dork Tower,Nur Peanuts!,0
Dork Tower,Hepta,1
Snake Pit,Lucky Captain,0
Snake Pit,Alien Wars,0
Snake Pit,Full Moon Jacket,1
Dork Tower,Crystal Faire,1
Buffy the Vampire Slayer,Twixt,1
Buffy the Vampire Slayer,Hepta,1
Abduction,Leipzig,0
Dork Tower,Astro Drive,0
Abduction,Snake Pit,0

标签: javascriptd3.js

解决方案


当您在 之后立即设置stroke属性时append("circle"),所做的事情就完成了。笔触颜色将是您在那一刻设置的颜色,即d.fixed !== true笔触为绿色。

拖动后更改笔触颜色的正确方法,

  function dragended(d) {
        if (!d3.event.active) force.alphaTarget(0);
        d.fixed = true;
        if (d.fixed == true) {
              d.fx = d.x;
              d.fy = d.y;
        }
        else {
              d.fx = null;
              d.fy = null;
        }
        d3.select(this) // `this` is the node where drag happend
          .select("circle")
          .style("stroke", "grey");
    };

一个工作示例


推荐阅读