D3.js 如何更改d3图例条目间距/对齐方式

D3.js 如何更改d3图例条目间距/对齐方式,d3.js,svg,D3.js,Svg,我有一个传说: 如您所见,每个图例条目的宽度相同。相反,我希望每个图例条目的宽度根据条目符号和文本的宽度而变化。最后,我希望前导项文本的端点和下一个项符号的起点之间的距离相同。换句话说,我希望“OA”和加号之间的距离与“OI”和钻石、“RARC”和正方形之间的距离相同。我需要这是基于像素(字符串长度将不够)。我一直在尝试各种各样的东西,但都没有成功 这是我的密码: var legendData = [["OA", "yellow", "circle"], ["OI", "blu

我有一个传说:

如您所见,每个图例条目的宽度相同。相反,我希望每个图例条目的宽度根据条目符号和文本的宽度而变化。最后,我希望前导项文本的端点和下一个项符号的起点之间的距离相同。换句话说,我希望“OA”和加号之间的距离与“OI”和钻石、“RARC”和正方形之间的距离相同。我需要这是基于像素(字符串长度将不够)。我一直在尝试各种各样的东西,但都没有成功

这是我的密码:

        var legendData = [["OA", "yellow", "circle"], ["OI", "blue", "cross"], ["RARC", "green", "diamond"], ["CAPE", "red", "square"], ["Other", "black", "triangle-down"]];

        this.svg.selectAll('.legend').remove() //remove remnants of previous legend so new legend has clean slate...eliminates overlays during resizing

        var legend = this.svg.append('g')
            .attr("class", "legend")
            .attr("height", 0)
            .attr("width", 0)
            .attr('transform', 'translate(' + (ScatterChart.Config.margins.left + (width * .008)) + ',' + (height += .40 * ScatterChart.Config.margins.bottom) + ')');

        var legendRect = legend
            .selectAll('g')
            .data(legendData)
            ;

        var labelLength = 0
        var labelLengthPrevious = 0

        var legendRectE = legendRect.enter()
            .append("g")
            .attr("transform", function (d, i) {
                //labelLength = labelLengthPrevious //Need to figure out pixel lengths
                //labelLengthPrevious += (d[0].length) + 50
                //return 'translate(' + labelLength + ', ' + 0 + ' )';  // y is constant and x growing
                return 'translate(' + (i * (.15 * width)) + ', ' + 0 + ' )';  // y is constant and x growing
            })
            ;

        legendRectE
            .append('path')
            .attr("d", d3.svg.symbol().type((d) => {
                return d[2]
            }
            ).size((d3.min([height, width]) * ScatterChart.Config.axisFontMultiplier) * (d3.min([height, width]) * ScatterChart.Config.symbolSizeMultiplier)))
            .style("fill", function (d) {
                return d[1];
            })
            .attr('stroke', 'black')
            ;

        //This asserts legendRectE as a node...I think. I do this so I can use the width and height measurements of legendRectE.
        var node: SVGElement = <SVGElement>legendRectE.node()

        legendRectE
            .append("text")
            .attr("x", function (d) {
                return node.getBoundingClientRect().width
            })
            .attr("y", function (d) {
                return node.getBoundingClientRect().height / 2.25
            })
            .text(function (d) {
                return d[0];
            })
            .style('font-size', function () { return d3.min([height, width]) * ScatterChart.Config.axisFontMultiplier + "px" })
            ;
显然,我错了。有什么想法/建议吗


p、 我使用的是D3V3.5。

挑战在于(据我所知)在最初添加元素时很难确定转换,因为宽度未知。但是,您可以在添加所有图例条目后返回并计算每个图例条目的宽度,然后相应地重新定位图例条目

下面的代码段将所有内容放置在彼此的上方以开始,然后使用
getBBox
计算每个图例的
svg
宽度
g
。然后,使用d3.sum计算附加在它前面的每个元素的宽度(因此应该在它的左边),并相应地将translate值设置为这些宽度的总和

它可能会被清理一点可能,有点快。如果在元素正确定位之前存在延迟,则透明地附加它们,然后在它们定位后淡入可能是一个优雅的(视觉上,编程上较少)解决方案(或者最初将它们附加到视图框之外)

d3v4:
var data=[‘短文本’、‘长文本’、‘最长文本段’、‘短文本’];
var svg=d3.select('body')
.append('svg')
.attr('width',800)
.attr('height',200);
var groups=svg.selectAll('g')
.数据(数据)
.输入()
.append('g');
var rect=groups.append('rect')
.attr('fill',函数(d,i){return d3.schemeCategory10[i];})
.attr('height',30)
.attr('宽度',30);
var text=groups.append('text')
.attr('y',20)
.attr('x',35)
.text(函数(d){return d;});
//现在,在添加组后将其隔开:
var=10;
groups.attr('transform',function(d,i){
返回“translate”(“+(d3.sum)(数据,函数(e,j)){
如果(j

谢谢您的帮助。除了最后一部分,您建议的编码对我有效。它会阻塞
节点()
。我收到一个错误:
[ts]属性“节点”在“类型”选择中不存在。
知道为什么以及如何使其工作吗?我想这是因为我使用的是TypeScript,但我不确定。我的错,忘记了v3和v4在这方面有一些不同。现在更新答案-参见第二段。谢谢@Andrew。通过一个小小的调整:
return(groups)[0][j].getBBox().width
,我可以让它与您最近的更改一起工作。
    var legendRectE = legendRect.enter()
        .append("g")
        .attr("transform", function (d, i) {
             var node: SVGElement = <SVGElement>legendRectE.node()
             return 'translate(' + node.getBoundingClientRect().width + ', ' + 0 + ' )';  // y is constant and x growing
        })
        ;