简体   繁体   中英

d3 drag multiple text elements inside a group SVG

I am new to using d3.js. I am trying to append multiple text elements in a svg group. With that, I want to be able to drag the group of multiple text.
So for an example:

    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);
}

If I use the selectAll method, the text gets clumped together. Therefore, I was wondering if I can drag the text group in their proper position based on the coordinate I give it (while being dragged). Anyways please let me know if I need to provide any further information. Thank you

If you want to select the second label, but don't want to use selectAll as it selects both, you can give the labels classes when appending and select those when dragging:

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);

Though of course this will set the same coordinate for both labels unless you specify an offset, as below:

 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 dx;}) .attr("y", function(d) { return dy;}) .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 dx = x; }) .attr("y", function(d) { return dy = 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> 

I won't dive into the alternative in too much depth, but it applies the drag to the g , positioning both text labels at the same time. This can handle irregular spacing between sibling labels easier than the above:

 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("+[dx,dy]+")"; }) .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("+[dx=d3.event.x,dy=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> 

Also, there is no need to use append("text").data(data) , this is not doing anything - your datum is already bound to the newly appended element

Lastly, you can make this work with selectAll() if you set attributes using the second parameter of any provided function when setting attributes: (d,i)=>... i is the index of the element, so if your sibling labels are regularly spaced, you can use something like:

 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 dx;}) .attr("y", function(d) { return dy;}) .text(function(d) { return d.label; }) labels.append("text") .attr("font-size", ".75em") .attr("x", function(d) { return dx;}) .attr("y", function(d) { return dy + 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 dx = x; }) .attr("y", function(d,i) { dy = y; return dy + 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> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM