将D3.js图例分散在两列中

时间:2018-07-25 13:49:27

标签: javascript html css d3.js

嗨,我有一个非常基本的D3.js图例

    svg.append('g')
        .classed('legend-color', true)
        .attr('text-anchor', 'start')
        .attr('transform', 'translate(20,30)')
        .style('font-size', '11px')
        .style('fill', 'rgb(0,0,0)')
        .call(legendOrdinal);

我想把它分成两半,因为否则,底部的图例单元会干扰我的节点。

所以基本上它将来自

Category A
Category B
Category C
Category D
Category E
Category F
Category G
Category H

    Category A     Category E
    Category B     Category F
    Category C     Category G
    Category D     Category H

2 个答案:

答案 0 :(得分:3)

使用一栏图例,您可以使用以下内容轻松定位每个条目:

.attr("transform", function(d,i) {  "translate(10," + (i * 20) +")" });

要放置多个列(以及同时放置行),我们需要调整转换的x值并根据列调整y值。最简单的方法可能是对x和y使用以下代码:

x = Math.floor(i/c) * w + tx
y = i % c * h + ty

其中c是列数,w是每个图例条目的宽度,tx是所有图例条目水平转换的基本量,h是图例条目的高度,ty是所有图例条目垂直转换的基本量。

您可以使用以下功能来实现上述目标:

function position(d,i) {
  var c = 2;   // number of columns
  var h = 20;  // legend entry height
  var w = 150; // legend entry width (so we can position the next column) 
  var tx = 10; // tx/ty are essentially margin values
  var ty = 10;
  var x = i % c * w + tx;
  var y = Math.floor(i / c) * h + ty;
  return "translate(" + x + "," + y + ")";
}

var entries = "ABCDEFGHIJ".split("");
var color = d3.schemeCategory10;

var n = Math.round(entries.length/2);
var w = 100;
var h = 20;

var svg = d3.select("body")
  .append("svg")
  .attr("width", 400)
  .attr("height",200);
  
var legend = svg.selectAll("g")
  .data(entries)
  .enter()
  .append("g")
  .attr("transform", position)
  
legend.append("text")
  .attr("x", 18)
  .attr("y", 12)
  .text(function(d) { return "Category " + d; });

legend.append("rect")
  .attr("width",10)
  .attr("height",10)
  .attr("fill",function(d,i) { return color[i]; })
  
  
function position(d,i) {
  var c = 2;   // number of columns
  var h = 20;  // height of each entry
  var w = 150; // width of each entry (so you can position the next column)
  var tx = 10; // tx/ty are essentially margin values
  var ty = 10;
  var x = i % c * w + tx;
  var y = Math.floor(i / c) * h + ty;
  return "translate(" + x + "," + y + ")";
}
  
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

或者,您可以通过压缩将其缩短:

var entries = "ABCDEFGHIJ".split("");
var color = d3.schemeCategory10;

var svg = d3.select("body")
  .append("svg")
  .attr("width", 400)
  .attr("height",200);
  
var legend = svg.selectAll("g")
  .data(entries)
  .enter()
  .append("g")
  .attr("transform", function(d,i) {
    return "translate(" + (i % 2 * 150 + 10) + "," + (Math.floor(i / 2) * 20 + 10) + ")";
  })
  
legend.append("text")
  .attr("x", 18)
  .attr("y", 12)
  .text(function(d) { return "Category " + d; });

legend.append("rect")
  .attr("width",10)
  .attr("height",10)
  .attr("fill",function(d,i) { return color[i]; })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>


如果您希望每列中的条目是连续的,而不是每行中的条目,我们可以对其进行一些修改以指定行数(由所需的列数和图例决定)您拥有的项目:Math.ceil(numberEntries/numberColumns)。看起来可能像这样:

var entries = "ABCDEFGHIJ".split("");
var color = d3.schemeCategory10;

var n = Math.round(entries.length/2);
var w = 100;
var h = 20;

var svg = d3.select("body")
  .append("svg")
  .attr("width", 400)
  .attr("height",200);
  
var legend = svg.selectAll("g")
  .data(entries)
  .enter()
  .append("g")
  .attr("transform", position)
  
legend.append("text")
  .attr("x", 18)
  .attr("y", 12)
  .text(function(d) { return "Category " + d; });

legend.append("rect")
  .attr("width",10)
  .attr("height",10)
  .attr("fill",function(d,i) { return color[i]; })
  
  
function position(d,i) {
  var c = 3
  var r = Math.ceil(entries.length / c);
  var h = 20;  // height of each entry
  var w = 100; // width of each entry (so you can position the next column)
  var tx = 10; // tx/ty are essentially margin values
  var ty = 10;
  var x = Math.floor(i / r) * w + tx;
  var y = i % r * h + ty;
  return "translate(" + x + "," + y + ")";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

此方法可能导致最后一列只有一个条目,而上面的第一个方法可能只有一行只有一个行。视情况而定,可能更优选

答案 1 :(得分:0)

您可以对transform属性使用函数,并根据逻辑更改布局。

这是一个简单的例子:

而不是.attr('transform', 'translate(20,30)'),请输入以下内容:

.attr('transform', function(data, index){

      var sections = Math.round((Object.keys(slices).length - 1) / 2);

      if(index < sections)
        return 'translate(0,0)'; 
      else
        return 'translate(80,-40)'; 
    });

这是我写的一个非常简单的逻辑,只是为了向您展示这个想法。我计算一列中会有多少个元素,然后根据其索引更改其每个translate属性。

这是小提琴:https://jsfiddle.net/nimeshka/wbejmg30/35/

检查上述小提琴中的最后一个代码块以查看此内容。

希望有帮助!