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.