【问题标题】:Spread D3.js legend on two columns在两列上传播 D3.js 图例
【发布时间】:2018-07-25 13:49:26
【问题描述】:

嗨,我有一个非常基本的 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

【问题讨论】:

  • 你用的是什么版本?
  • 我使用的是 4.7.4
  • 我添加了一个答案。请检查:)
  • 任何更新......?

标签: javascript html css d3.js


【解决方案1】:

使用单列图例,您可以轻松地定位每个条目,例如:

.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 是图例条目的高度,@ 987654327@ 是所有图例条目垂直翻译的基础数量。

您可以通过以下功能实现上述目标:

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>

这种方法可能导致最后一列只有一个条目,而上面的第一个方法可能只有一行只有一个条目。视情况而定,其中一种可能更可取

【讨论】:

    【解决方案2】:

    您可以使用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/

    检查上面小提琴中的最后一个代码块来看看这个。

    希望对你有帮助!!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-19
      • 2014-08-14
      • 1970-01-01
      • 1970-01-01
      • 2013-01-24
      • 2014-11-14
      相关资源
      最近更新 更多