d3拖动SVG组中的多个文本元素

时间:2019-03-06 21:57:32

标签: javascript d3.js svg text

我是使用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方法,则文本会聚在一起。因此,我想知道是否可以根据我给它的坐标(拖动时)将文本组拖动到适当的位置。无论如何,请让我知道是否需要提供更多信息。谢谢

1 个答案:

答案 0 :(得分:0)

如果您要选择第二个标签,但又不想同时使用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)=>... 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>