D3 节点标签的彩色文本和换行符

Colored text and line-breaks for D3 node labels

我正在处理 D3 图表,但无法正确标记节点(我想将 "size" 放在第二行,并将所有文本更改为白色。例如, "Toyota" 节点会说 "Toyota Motor" 并在下面的新行上显示“61.84”)。

这是我的起点。我试图用 CSV 数据添加一个 pre 块,这样它就可以在 JSfiddle 上 运行,但我卡住了。

我知道我需要更改此代码以便从 pre 块而不是外部 CSV 获取数据:

d3.text("./car_companies.csv", function(error, text) {

在那之后,我需要添加一个新的 "node append",像这样:

  node.append("revenue")
  .style("text-anchor", "middle")
  .attr("dy", "1.5em")
  .text(function(d) { return d.revenue.substring(0, d.radius / 3); });

http://jsfiddle.net/nick2ny/pqo1x670/4/

感谢您的任何想法。

与问题没有直接关系,但要使用 <pre> 元素来保存数据,您必须使用:

var text = d3.select("pre").text();

而不是 d3.text()

回到问题:

要打印这些值,您只需要:

node.append("text")
    .attr("dy", "1.3em")
    .style("text-anchor", "middle")
    .style("fill", "white")
    .text(function(d) {
        return d.size;
    });

按您想要的方式调整dy。但是,还有一个问题:您没有在数据数组中填充 size 。因此,在 create_nodes 函数中添加:

size: data[node_counter].size,

下面是修改后的代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style type="text/css">
  text {
    font: 10px sans-serif;
  }
  
  pre {
    display: none;
  }
  
  circle {
    stroke: #565352;
    stroke-width: 1;
  }
</style>

<body>
  <pre id="data">
Toyota Motor,61.84,Asia,239
Volkswagen,44.54,Europe,124
Daimler,40.79,Europe,104
BMW,35.78,Europe,80
Ford Motor,31.75,America,63
General Motors,30.98,America,60
</pre>

  <script src="https://d3js.org/d3.v3.min.js"></script>
  <script>
    Array.prototype.contains = function(v) {
      for (var i = 0; i < this.length; i++) {
        if (this[i] === v) return true;
      }
      return false;
    };


    var width = 500,
      height = 500,
      padding = 1.5, // separation between same-color nodes
      clusterPadding = 6, // separation between different-color nodes
      maxRadius = 12;

    var color = d3.scale.ordinal()
      .range(["#0033cc", "#33cc66", "#990033"]);



    var text = d3.select("pre").text();
    var colNames = "text,size,group,revenue\n" + text;
    var data = d3.csv.parse(colNames);

    data.forEach(function(d) {
      d.size = +d.size;
    });


    //unique cluster/group id's
    var cs = [];
    data.forEach(function(d) {
      if (!cs.contains(d.group)) {
        cs.push(d.group);
      }
    });

    var n = data.length, // total number of nodes
      m = cs.length; // number of distinct clusters

    //create clusters and nodes
    var clusters = new Array(m);
    var nodes = [];
    for (var i = 0; i < n; i++) {
      nodes.push(create_nodes(data, i));
    }

    var force = d3.layout.force()
      .nodes(nodes)
      .size([width, height])
      .gravity(.02)
      .charge(0)
      .on("tick", tick)
      .start();

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


    var node = svg.selectAll("circle")
      .data(nodes)
      .enter().append("g").call(force.drag);


    node.append("circle")
      .style("fill", function(d) {
        return color(d.cluster);
      })
      .attr("r", function(d) {
        return d.radius
      })


    node.append("text")
      .attr("dy", ".3em")
      .style("text-anchor", "middle")
      .style("fill", "white")
      .text(function(d) {
        return d.text;
      });

    node.append("text")
      .attr("dy", "1.3em")
      .style("text-anchor", "middle")
      .style("fill", "white")
      .text(function(d) {
        return d.size;
      });

    function create_nodes(data, node_counter) {
      var i = cs.indexOf(data[node_counter].group),
        r = Math.sqrt((i + 1) / m * -Math.log(Math.random())) * maxRadius,
        d = {
          cluster: i,
          radius: data[node_counter].size * 1.5,
          text: data[node_counter].text,
          size: data[node_counter].size,
          revenue: data[node_counter].revenue,
          x: Math.cos(i / m * 2 * Math.PI) * 200 + width / 2 + Math.random(),
          y: Math.sin(i / m * 2 * Math.PI) * 200 + height / 2 + Math.random()
        };
      if (!clusters[i] || (r > clusters[i].radius)) clusters[i] = d;
      return d;
    };



    function tick(e) {
      node.each(cluster(10 * e.alpha * e.alpha))
        .each(collide(.5))
        .attr("transform", function(d) {
          var k = "translate(" + d.x + "," + d.y + ")";
          return k;
        })

    }

    // Move d to be adjacent to the cluster node.
    function cluster(alpha) {
      return function(d) {
        var cluster = clusters[d.cluster];
        if (cluster === d) return;
        var x = d.x - cluster.x,
          y = d.y - cluster.y,
          l = Math.sqrt(x * x + y * y),
          r = d.radius + cluster.radius;
        if (l != r) {
          l = (l - r) / l * alpha;
          d.x -= x *= l;
          d.y -= y *= l;
          cluster.x += x;
          cluster.y += y;
        }
      };
    }

    // Resolves collisions between d and all other circles.
    function collide(alpha) {
      var quadtree = d3.geom.quadtree(nodes);
      return function(d) {
        var r = d.radius + maxRadius + Math.max(padding, clusterPadding),
          nx1 = d.x - r,
          nx2 = d.x + r,
          ny1 = d.y - r,
          ny2 = d.y + r;
        quadtree.visit(function(quad, x1, y1, x2, y2) {
          if (quad.point && (quad.point !== d)) {
            var x = d.x - quad.point.x,
              y = d.y - quad.point.y,
              l = Math.sqrt(x * x + y * y),
              r = d.radius + quad.point.radius + (d.cluster === quad.point.cluster ? padding : clusterPadding);
            if (l < r) {
              l = (l - r) / l * alpha;
              d.x -= x *= l;
              d.y -= y *= l;
              quad.point.x += x;
              quad.point.y += y;
            }
          }
          return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
        });
      };
    }
  </script>