【问题标题】:Unable to change x position of legend text inside a group element using D3无法使用 D3 更改组元素内图例文本的 x 位置
【发布时间】: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 任何有关如何创建水平图例(不重叠图例)的帮助将不胜感激。克里斯

【问题讨论】:

    标签: d3.js visualization legend


    【解决方案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 属性时使用局部变量di 作为函数参数。本地范围内的参数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>

      【讨论】:

        猜你喜欢
        • 2021-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-10
        相关资源
        最近更新 更多