【问题标题】:d3 drag multiple text elements inside a group SVGd3在组SVG中拖动多个文本元素
【发布时间】:2019-03-06 21:57:32
【问题描述】:

我是使用 d3.js 的新手。我正在尝试在 svg 组中附加多个文本元素。有了这个,我希望能够拖动多个文本组。
举个例子:

    export function testNode (config = {}) {
    let { svg, rectX, rectY, text1, text2 } = config
    var data = [{ x: rectX, y:rectY, label: text1, label2: text2, labelX: rectX + 100, labelY: rectY + 200, labelX2: rectX + 300, labelY2: rectY + 300 }]
        var group = svg.append("g")
                .selectAll("g")
        .data(data)
        .enter()
                .append("g")
                .attr("transform",
                    "translate(" + 0 + "," + 0 + ")")
                .call(d3.drag()
                    .on("start", dragstarted)
                    .on("drag", dragged)
                    .on("end", dragended));

        group.append("text")
                .data(data)
                .attr("x", (d) => { return d.labelX })
                .attr("y", (d) => { return d.labelY })
                .attr("font-size", "1em")
                .attr("color", "black")
                .text((d) => { return d.label });

            group.append("text")
                .data(data)
                .attr("x", (d) => { return d.labelX2 })
                .attr("y", (d) => { return d.labelY2 })
                .attr("font-size", ".75em")
                .attr("color", "black")
                .attr("class", "label")
                .text((d) => { return d.metricValue_01 });

function dragStarted() { 
 d3.select(this).raise().classed("active", true);
}

function dragged(d) {
d3.select(this).select("text")
 .attr("x", d.labelX = d3.event.x + 10)
 .attr("y", d.labelY = d3.event.y + 20);

d3.select(this).select("text")
 .attr("x", d.labelX2 = d3.event.x + 10)
 .attr("y", d.labelY2 = d3.event.y + 20);

function dragended() {
    d3.select(this).classed("active", false);
}

如果我使用 selectAll 方法,文本会聚集在一起。因此,我想知道是否可以根据我给它的坐标(在被拖动时)将文本组拖动到正确的位置。无论如何,如果我需要提供任何进一步的信息,请告诉我。谢谢

【问题讨论】:

    标签: javascript d3.js svg text


    【解决方案1】:

    如果您想选择第二个标签,但又不想使用selectAll,因为它同时选择了两个标签,您可以在附加时指定标签类,并在拖动时选择它们:

    d3.select(this).select(".bigLabel")
     .attr("x", d.labelX = d3.event.x + 10)
     .attr("y", d.labelY = d3.event.y + 20);
    
    d3.select(this).select(".smallLabel")
     .attr("x", d.labelX2 = d3.event.x + 10)
     .attr("y", d.labelY2 = d3.event.y + 20);
    

    当然,除非您指定偏移量,否则这将为两个标签设置相同的坐标,如下所示:

    var data = [
     { x: 100, x2: 100, y: 100, y2: 120, label: "label1", value: "17%" },
     { x: 300, x2: 300, y: 200, y2: 220, label: "label2", value: "83%" },
     { x: 100, x2: 100, y: 200, y2: 220, label: "label3", value: "11%" },
     { x: 300, x2: 300, y: 100, y2: 120, label: "label4", value: "96%" }
    ];
    
    var svg = d3.select("svg");
    
    var labels = svg.selectAll("g")
      .data(data)
      .enter()
      .append("g")
      .call(d3.drag()
      .on("drag",drag));
        
    labels.append("text")
      .attr("font-size", "1em")
      .attr("x", function(d) { return d.x;})
      .attr("y", function(d) { return d.y;})
      .text(function(d) { return d.label; })
      .attr("class","label1");
         
    labels.append("text")
      .attr("font-size", ".75em")
      .attr("x", function(d) { return d.x2;})
      .attr("y", function(d) { return d.y2;})  
      .text(function(d) { return d.value; })
      .attr("class","label2");
    
    function drag(d) {
      var x = d3.event.x;
      var y = d3.event.y;
      d3.select(this)
        .select(".label1")
        .attr("x", function(d) { return d.x = x; })
        .attr("y", function(d) { return d.y = y; })
      d3.select(this)
        .select(".label2")
        .attr("x", function(d) { return d.x2 = x; })
        .attr("y", function(d) { return d.y2 = y + 20; })    
        
    }
    text {
      text-anchor:middle;
      cursor:pointer;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <svg width="500" height="400"></svg>

    我不会深入探讨替代方案,但它会将拖动应用到g,同时定位两个文本标签。这可以比上面更容易地处理兄弟标签之间的不规则间距:

    var data = [
     { x: 100, y: 100, label: "label1", value: "17%" },
     { x: 300, y: 200, label: "label2", value: "83%" },
     { x: 100, y: 200, label: "label3", value: "11%" },
     { x: 300, y: 100, label: "label4", value: "96%" }
    ];
    
    var svg = d3.select("svg");
    
    var labels = svg.selectAll("g")
      .data(data)
      .enter()
      .append("g")
      .attr("transform",function(d) { 
        return "translate("+[d.x,d.y]+")"; 
      })
      .call(d3.drag().on("drag", drag));
        
    labels.append("text")
      .attr("font-size", "1em")
      .text(function(d) { return d.label; });
         
    labels.append("text")
      .attr("font-size", ".75em")
      .text(function(d) { return d.value; })
      .attr("dy", "1em")
      
    function drag(d) {
      d3.select(this)
        .attr("transform","translate("+[d.x=d3.event.x,d.y=d3.event.y]+")"); 
    }
    text {
      text-anchor: middle;
      cursor: pointer;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <svg width="500" height="400"></svg>

    另外,没有必要使用append("text").data(data),这并没有做任何事情——你的数据已经绑定到新添加的元素上

    最后,如果您在设置属性时使用任何提供的函数的第二个参数设置属性,则可以使用 selectAll() 来实现这一点:(d,i)=&gt;... i 是元素的索引,所以如果您的兄弟标签是定期间隔,你可以使用类似的东西:

    var data = [
     { x: 100, y: 100, label: "label1", value: "17%" },
     { x: 300, y: 200, label: "label2", value: "83%" },
     { x: 100, y: 200, label: "label3", value: "11%" },
     { x: 300, y: 100, label: "label4", value: "96%" }
    ];
    
    var svg = d3.select("svg");
    
    var labels = svg.selectAll("g")
      .data(data)
      .enter()
      .append("g")
      .call(d3.drag()
      .on("drag",drag));
        
    labels.append("text")
      .attr("font-size", "1em")
      .attr("x", function(d) { return d.x;})
      .attr("y", function(d) { return d.y;})
      .text(function(d) { return d.label; })
         
    labels.append("text")
      .attr("font-size", ".75em")
      .attr("x", function(d) { return d.x;})
      .attr("y", function(d) { return d.y + 20;})  
      .text(function(d) { return d.value; })
    
    function drag(d) {
      var x = d3.event.x;
      var y = d3.event.y;
      d3.select(this)
        .selectAll("text")
        .attr("x", function(d) { return d.x = x; })
        .attr("y", function(d,i) { d.y = y;
          return d.y + i * 20;
        })
    }
    text {
      text-anchor:middle;
      cursor:pointer;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <svg width="500" height="400"></svg>

    【讨论】:

    • 非常感谢!我刚刚将类属性添加到组中。我需要将它拖到一起,因为实际上这两个元素都在 svg 组的矩形内。真的很感激!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-22
    • 1970-01-01
    • 2013-04-03
    相关资源
    最近更新 更多