无法使用 D3 更改组元素内图例文本的 x 位置
Posted
技术标签:
【中文标题】无法使用 D3 更改组元素内图例文本的 x 位置【英文标题】:Unable to change x position of legend text inside a group element using D3 【发布时间】:2017-11-30 05:16:59 【问题描述】:我正在尝试在 D3.js 中创建水平图例。我使用组元素 (g) 作为所有图例的容器,并且各个图例 (文本) 也都包含在 "g" 元素中。结果是各个图例堆叠在一起,而不是隔开。 我尝试更改图例上的 x 属性并转换/翻译。虽然 DOM 显示应用了 x 值,但图例不会移动。因此,如果 DOM 显示 legend / g 元素位于 x = 200,它仍位于 0。 我花了两天时间试图解决这个问题,并且可能查看了 50 多个示例,包括我在 StackExchange 上可以找到的任何内容。 下面的代码是我最近的尝试。它不会出现任何错误,并且 x 值会反映在 DOM 中,但元素不会移动。
我已经包含了涵盖相关位的代码(但不是所有代码)。
此处添加图例容器:
/*<note>Add container to hold legends. */
var LegendCanvas = d3.select("svg")
.append("g")
.attr("class", "legend canvas")
.attr("x", 0)
.attr("y", 0)
.attr("width", Width)
.style("fill", "#ffcccc")
.attr("transform", "translate(0,15)");
然后有一个通过 json 对象数组的循环:
var PrevElemLength = 0;
/*<note>Loop through each data series, call the Valueline variable and plot the line. */
Data.forEach(function(Key, i)
/*<note>Add the metric line(s). */
Svg.append("path")
.attr("class", "line")
.attr("data-legend",function() return Key.OriginId )
/*<note>Iterates through the data series objects and applies a different color to each line. */
.style("stroke", function ()
return Key.color = Color(Key.UniqueName); )
.attr("d", Valueline(Key.DataValues));
/*<note>Add a g element to the legend container. */
var Legend = LegendCanvas.append("g")
.attr("class", "legend container")
.attr("transform", function (d, i)
if (i === 0)
return "translate(0,0)"
else
PrevElemLength += this.previousElementSibling.getBBox().width;
return "translate(" + (PrevElemLength) + ",0)"
);
/*<note>Adds a rectangle to pre-fix each legend. */
Legend.append("rect")
.attr("width", 5)
.attr("height", 5)
.style("fill", function ()
return Key.color = Color(Key.UniqueName); );
/*<note>Adds the legend text. */
Legend.append("text")
.attr("x", function()
return this.parentNode.getBBox().width + 5;
)
/*.attr("y", NetHeight + (Margin.bottom/2)+ 10) */
.attr("class", "legend text")
.style("fill", function ()
return Key.color = Color(Key.UniqueName); )
.text(Key.UniqueName);
以下是输出的屏幕截图: enter image description here 任何有关如何创建水平图例(不重叠图例)的帮助将不胜感激。克里斯
【问题讨论】:
【参考方案1】:试试这个:
//Legend
var legend = vis.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) return "translate(0," + i * 20 + ")"; );
legend.append("image")
.attr("x", 890)
.attr("y", 70)
.attr("width", 20)
.attr("height", 18)
.attr("xlink:href",function (d)
return "../assets/images/dev/"+d+".png";
)
legend.append("text")
.attr("x", 910)
.attr("y", 78)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d)
return d;
);
【讨论】:
【参考方案2】:问题是您在设置transform
属性时使用局部变量d
和i
作为函数参数。本地范围内的参数i
会覆盖实际变量。局部变量 i 的值将始终为零,因为没有数据绑定到该元素。
var Legend = LegendCanvas.append("g")
.attr("class", "legend container")
.attr("transform", function (d, i) //Remove i
if (i === 0)
return "translate(0,0)"
else
PrevElemLength += this.previousElementSibling.getBBox().width;
return "translate(" + (PrevElemLength) + ",0)"
);
我还对代码进行了细微更新以进行改进。
var LegendCanvas = d3.select("svg")
.append("g")
.attr("class", "legend canvas")
.attr("x", 0)
.attr("y", 0)
.attr("width", 500)
.style("fill", "#ffcccc")
.attr("transform", "translate(0,15)");
var PrevElemLength = 0;
var Data = [
OriginId: 1,
UniqueName: "Some Long Text 1"
,
OriginId: 2,
UniqueName: "Some Long Text 2"
];
/*<note>Loop through each data series, call the Valueline variable and plot the line. */
var Color = d3.scale.category10();
Data.forEach(function(Key, i)
/*<note>Add a g element to the legend container. */
var Legend = LegendCanvas.append("g")
.attr("class", "legend container")
.attr("transform", function()
if (i === 0)
return "translate(0,0)"
else
var marginLeft = 5;
PrevElemLength += this.previousElementSibling.getBBox().width;
return "translate(" + (PrevElemLength + marginLeft) + ",0)"
);
/*<note>Adds a rectangle to pre-fix each legend. */
Legend.append("rect")
.attr("width", 5)
.attr("height", 5)
.style("fill", function()
return Key.color = Color(Key.UniqueName);
);
/*<note>Adds the legend text. */
Legend.append("text")
.attr("x", function()
return this.parentNode.getBBox().width + 5;
)
.attr("dy", "0.4em")
.attr("class", "legend text")
.style("fill", function()
return Key.color = Color(Key.UniqueName);
)
.text(Key.UniqueName);
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg height=500 width=500></svg>
d3的实现方式(使用数据绑定)如下
var LegendCanvas = d3.select("svg")
.append("g")
.attr("class", "legend canvas")
.attr("x", 0)
.attr("y", 0)
.attr("width", 500)
.style("fill", "#ffcccc")
.attr("transform", "translate(0,15)");
var Data = [
OriginId: 1,
UniqueName: "Some Long Text 1"
,
OriginId: 2,
UniqueName: "Some Long Text 2"
];
var Color = d3.scale.category10();
var Legend = LegendCanvas.selectAll(".legend")
.data(Data)
.enter()
.append("g")
.attr("class", "legend container");
Legend.append("rect")
.attr("width", 5)
.attr("height", 5)
.style("fill", function(Key)
return Key.color = Color(Key.UniqueName);
);
Legend.append("text")
.attr("x", function()
return this.parentNode.getBBox().width + 5;
)
.attr("dy", "0.4em")
.attr("class", "legend text")
.style("fill", function(Key)
return Key.color = Color(Key.UniqueName);
)
.text(function(Key) return Key.UniqueName );
var PrevElemLength = 0;
Legend.attr("transform", function(d, i)
if (i === 0)
return "translate(0,0)"
else
var marginLeft = 5;
PrevElemLength += this.previousElementSibling.getBBox().width;
return "translate(" + (PrevElemLength + marginLeft) + ",0)"
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width=500 height=500></svg>
【讨论】:
以上是关于无法使用 D3 更改组元素内图例文本的 x 位置的主要内容,如果未能解决你的问题,请参考以下文章