Home > Enterprise >  Old links not cleaned before new links created
Old links not cleaned before new links created

Time:11-23

When drag one node, the links should be updated with new coordinates. current code do not clear the old path. I use join method with the group element but group element not clean up sub-elements appended.

svg_arc()

function svg_arc() {
        var svg = d3.select('body')
                .append('svg')
                .attr('width',410)
                .attr('height',500)
                //.style('border','10px solid red')
                .style('background','#ececec')
        
        var g = svg.append('g')
                .attr('stroke','black')
                .attr('stroke-width',1)
                .attr('fill','black')       
        
        var data = [
                {
                        id:"pointA",
                        x:100,
                        y:350,
                        r:6,
                        text:'A'
                },{
                        id:"pointB",
                        x:250,
                        y:50,
                        r:6,
                        text:'B'
                },{
                        id:"pointC",
                        x:400,
                        y:350,
                        r:6,
                        text:'C'
                }
        ]
        var node = g.selectAll('.node')
                .data(data)
                .join('g')
                .attr('class','node')
                .attr('transform',d => `translate(${d.x},${d.y})`)
                .attr("pointer-events", "all")
        
        var circle = node.append('circle')
                .attr('id',d => d.id)
                .attr('cx',0)
                .attr('cy',0)
                .attr('r',d => d.r)
                .attr("pointer-events", "all")

        var text = node.append('text')
                .attr('class','text')
                .text(d => d.text)
                .attr('x',0)
                .attr('y',0)
                .attr('dx',-15)
                .attr('dy',-15)

        node.call(
                d3.drag()
                        .on("start",function(event,d) {
                                d3.select(this).raise().classed("active", true);
                        })                          
                        .on("drag",function(event,d) {
                                
                                d.x  = event.dx
                                d.y  = event.dy
                                update_links(g,data)
                                d3.select(this).attr('transform',`translate(${d.x},${d.y})`)
                        })
                        .on("end", function dragEnd(event,d) {
                                d3.select(this).classed("active", false);
                        })
        )

        update_links(g,data)
}

function update_links(g,n) {
        var data = [0]//dummy data
        var line = g.selectAll('.lines')
                .data(data)
                .join('g')
                .attr('class','lines')
        
        line.append('path')
                .attr('class','AB')
                .attr('d',['M',n[0].x,n[0].y,'L',n[1].x,n[1].y].join(' '))
                .attr('stroke','black')

        line.append('path')
                .attr('class','BC')
                .attr('d',['M',n[1].x,n[1].y,'L',n[2].x,n[2].y].join(' '))
                .attr('stroke','black')

        line.append('path')
                .attr('class','AC')     
                .attr('d',['M',n[0].x,n[0].y,'Q',n[1].x,n[1].y,n[2].x,n[2].y].join(' '))
                .attr('stroke','black')
                .attr('fill','none')

        line.append('path')
                .attr('class','MID')
                .attr('d',['M',(n[0].x n[1].x)/2,(n[0].y n[1].y)/2,'L',(n[1].x n[2].x)/2,(n[1].y n[2].y)/2].join(' '))
                .attr('fill','none')
        
}
<script src="https://unpkg.com/[email protected]/dist/d3.min.js"></script>

CodePudding user response:

You're using join for the group, that's correct, but then you are just appending the paths to the group. In other words, you need an enter/update/exit selection for the paths themselves.

Here's the code with that change:

svg_arc()

function svg_arc() {
  var svg = d3.select('body')
    .append('svg')
    .attr('width', 410)
    .attr('height', 500)
    //.style('border','10px solid red')
    .style('background', '#ececec')

  var g = svg.append('g')
    .attr('stroke', 'black')
    .attr('stroke-width', 3)
    .attr('fill', 'black')

  var data = [{
    id: "pointA",
    x: 100,
    y: 350,
    r: 6,
    text: 'A'
  }, {
    id: "pointB",
    x: 250,
    y: 50,
    r: 6,
    text: 'B'
  }, {
    id: "pointC",
    x: 400,
    y: 350,
    r: 6,
    text: 'C'
  }]
  var node = g.selectAll('.node')
    .data(data)
    .join('g')
    .attr('class', 'node')
    .attr('transform', d => `translate(${d.x},${d.y})`)
    .attr("pointer-events", "all")

  var circle = node.append('circle')
    .attr('id', d => d.id)
    .attr('cx', 0)
    .attr('cy', 0)
    .attr('r', d => d.r)
    .attr("pointer-events", "all")

  var text = node.append('text')
    .attr('class', 'text')
    .text(d => d.text)
    .attr('x', 0)
    .attr('y', 0)
    .attr('dx', -15)
    .attr('dy', -15)

  node.call(
    d3.drag()
    .on("start", function(event, d) {
      d3.select(this).raise().classed("active", true);
    })
    .on("drag", function(event, d) {

      d.x  = event.dx
      d.y  = event.dy
      update_links(g, data)
      d3.select(this).attr('transform', `translate(${d.x},${d.y})`)
    })
    .on("end", function dragEnd(event, d) {
      d3.select(this).classed("active", false);
    })
  )

  update_links(g, data)
}

function update_links(g, n) {
  var data = [0] //dummy data
  var group = g.selectAll('.lines')
    .data(data)
    .join('g')
    .attr('class', 'lines');

  const line = group.selectAll(".line")
    .data([0, 1, 2, 3])
    .join("path")
    .attr("class", "line")
    .attr("d", d => d === 0 ? ['M', n[0].x, n[0].y, 'L', n[1].x, n[1].y].join(' ') :
      d === 1 ? ['M', n[1].x, n[1].y, 'L', n[2].x, n[2].y].join(' ') :
      d === 2 ? ['M', n[0].x, n[0].y, 'Q', n[1].x, n[1].y, n[2].x, n[2].y].join(' ') : ['M', (n[0].x   n[1].x) / 2, (n[0].y   n[1].y) / 2, 'L', (n[1].x   n[2].x) / 2, (n[1].y   n[2].y) / 2].join(' '))
    .attr('stroke', 'black')
    .attr('fill', d => d > 1 ? 'none' : null)


}
<script src="https://unpkg.com/[email protected]/dist/d3.min.js"></script>

Have in mind that this is just to show you why your code was behaving the way it was. There are still lots and lots of problems to fix here, from just unnecessary bits to patterns that effectively worsen performance (for instance, the very use of join inside the drag callback is a big no) , but that's out of the scope of this answer.

  • Related