d3.js:具有动态元素宽度的图例

时间:2016-06-08 10:23:32

标签: d3.js

我正在尝试更换d3图例绘制功能,该功能使用.data()手动创建和将图例元素放置到一个。

我能够让一切正常工作,除了一件事:通过手动循环数据数组,我能够通过使用currentX跟踪变量确保图例元素之间的间距相等。然而,对于.data(),我无法引用其他元素,并且必须使用设计师讨厌的固定宽度框(我也是)。

鉴于下面的代码,我如何使新代码(顶行)的行为与旧代码(底行)完全相同?

(请不要建议我使用图例库,在提取此测试用例的"真实"代码中有很多事件处理和更多内容)



var config = {
  circleYCenter: 170,
  circleXCenter: 150,
  legendMarginTop: 52,
  legendMarginInner: 18,
  legendDotHeight: 8,
  legendDotWidth: 16,
};
var colors = {
  'lightyellow': '#FEE284',
  'darkblue': '#2872A3',
  'dirtyorange': '#E68406',
};

function drawLegend(container, map) {
  var legendGroup = container.append("g").attr({
    "transform": "translate(0,50)",
    "class": "legendGroup"
  });

  //New code
  var elGroup = legendGroup.selectAll("g").data(map).enter().append("g").attr({
    transform: function(d, i) {
      return "translate(" + (i * 100) + ",0)"
    }
  });

  elGroup.append("text").text(function(d) {
    return d.label;
  }).attr({
    x: config.legendDotWidth + config.legendMarginInner
  });
  elGroup.append("rect").attr({
    x: 0,
    width: config.legendDotWidth,
    y: -5,
    height: config.legendDotHeight,
    "fill": function(d) {
      return d.color;
    }
  });


  //Old code
  var currentX = 0;
  map.forEach(function(el, key) {
    var elGroup = legendGroup.append("g").attr("transform", "translate(" + currentX + ",100)");
    elGroup.append("rect").attr({
      x: 0,
      width: config.legendDotWidth,
      y: -5,
      height: config.legendDotHeight,
      "fill": el.color
    });
    elGroup.append("text").attr({
      "x": (config.legendDotWidth + 10),
      "y": 0,
      "alignment-baseline": "middle"
    }).text(el.label);
    currentX += elGroup.node().getBBox().width + config.legendMarginInner;
  });
}

drawLegend(d3.select("svg"), [{
  label: "foo",
  color: colors.dirtyorange
}, {
  label: "Banana",
  color: colors.darkblue
}, {
  label: "baz",
  color: colors.lightyellow
}]);

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<svg width=600 height=300></svg>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

首先组成小组:

 var elGroup = legendGroup.selectAll("g").data(map).enter().append("g");

正如您所做的那样附加textrect DOM:

  elGroup.append("text").text(function(d) {
    return d.label;
  }).attr({
    x: config.legendDotWidth + config.legendMarginInner
  });

  elGroup.append("rect").attr({
    x: 0,
    width: config.legendDotWidth,
    y: -5,
    height: config.legendDotHeight,
    "fill": function(d) {
      return d.color;
    }
  });

现在使用组的bbox将翻译添加到组中。

var currentX = 0;   
elGroup.attr({
    transform: function(d, i) {
            var ret = "translate(" + currentX + ",0)"
            currentX += this.getBBox().width + config.legendMarginInner;
      return ret;
    }
  });

工作代码here