This is a follow on from my previous question d3 rect in one group interfering with rect in another group
Two issues:
Incorrect drag behaviour. When clicking on the second rect to drag it, it jumps to where the third one is.
I added a anonymous function which runs when the svg in clicked on anywhere. This should add a new rect. However that is the working.
I know I should have only one issue per question but these are related and I suspect they will be solved together.
<!DOCTYPE html> <meta charset="utf-8"> <style> /*.active { stroke: #000; stroke-width: 2px; }*/ </style> <svg width="960" height="500"></svg> <script src="//d3js.org/d3.v4.min.js"></script> <script> var margin = { top: 20, right: 20, bottom: 20, left: 20 }, width = 600 - margin.left - margin.right, height = 600 - margin.top - margin.bottom; var svg = d3.select("svg"); var data = [{ x: 200 }, { x: 300 }, { x: 400 }]; var groove = svg.append("g") .attr("class", "groove_group"); groove.append("rect") .attr("x", 100) .attr("y", 150) .attr("rx", 2) .attr("ry", 2) .attr("height", 6) .attr("width", 800) .style("fill", "grey"); groove.append("rect") .attr("x", 102) .attr("y", 152) .attr("rx", 2) .attr("ry", 2) .attr("height", 2) .attr("width", 796) .style("fill", "black"); // create group var group = svg.selectAll(null) .data(data) .enter().append("g") .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)) .on("click", removeElement); group.append("rect") .attr("x", function(d) { return dx; }) .attr("y", 100) .attr("height", 100) .attr("width", 15) .style("fill", "lightblue") .attr('id', function(d, i) { return 'handle_' + i; }) .attr("rx", 6) .attr("ry", 6) .attr("stroke-width", 2) .attr("stroke", "black"); group.append("text") .attr("x", function(d) { return dx }) .attr("y", 100) .attr("text-anchor", "start") .style("fill", "black") .text(function(d) { return "x:" + dx }); // create group var group = svg.selectAll("g") .data(data) .enter().append("g") .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)) .on("click", removeElement); group.append("rect") .attr("x", function(d) { return dx; }) .attr("y", 200) .attr("height", 100) .attr("width", 15) .style("fill", "lightblue") .attr('id', function(d, i) { return 'handle_' + i; }) .attr("rx", 6) .attr("ry", 6) .attr("stroke-width", 2) .attr("stroke", "black"); group.append("text") .attr("x", function(d) { return dx }) .attr("y", 200) .attr("text-anchor", "start") .style("fill", "black") .text(function(d) { return "x:" + dx }); svg.on("click", function() { var coords = d3.mouse(this); var newData = { x: d3.event.x, } data.push(newData); group.selectAll("rect") .data(data) .enter() .append("rect") .attr("x", function(d) { return dx; }) .attr("y", 200) .attr("height", 100) .attr("width", 15) .style("fill", "steelblue") .attr('id', function(d, i) { return 'rect_' + i; }) .attr("rx", 6) .attr("ry", 6) .attr("stroke-width", 2) .attr("stroke", "black"); }); function dragstarted(d) { d3.select(this).raise().classed("active", true); } function dragged(d) { d3.select(this).select("text") .attr("x", dx = d3.event.x); d3.select(this).select("rect") .attr("x", dx = d3.event.x); } function dragended(d) { d3.select(this) .classed("active", false); } function removeElement(d) { d3.event.stopPropagation(); data = data.filter(function(e) { return e != d; }); d3.select(this) .remove(); } </script>
For correctly drag-and-drop behavior, rewrite your code like this:
var margin = { top: 20, right: 20, bottom: 20, left: 20 }, width = 600 - margin.left - margin.right, height = 600 - margin.top - margin.bottom; var svg = d3.select("svg"); var data = [{ x: 200 }, { x: 300 }, { x: 400 }]; var groove = svg.append("g") .attr("class", "groove_group"); groove.append("rect") .attr("x", 100) .attr("y", 150) .attr("rx", 2) .attr("ry", 2) .attr("height", 6) .attr("width", 800) .style("fill", "grey"); groove.append("rect") .attr("x", 102) .attr("y", 152) .attr("rx", 2) .attr("ry", 2) .attr("height", 2) .attr("width", 796) .style("fill", "black"); // create group var group = svg.selectAll(null) .data(data) .enter().append("g") .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)) .on("click", removeElement); group.append("rect") .attr("x", function(d) { return dx; }) .attr("y", 100) .attr("height", 100) .attr("width", 15) .style("fill", "lightblue") .attr('id', function(d, i) { return 'handle_' + i; }) .attr("rx", 6) .attr("ry", 6) .attr("stroke-width", 2) .attr("stroke", "black"); group.append("text") .attr("x", function(d) { return dx }) .attr("y", 100) .attr("text-anchor", "start") .style("fill", "black") .text(function(d) { return "x:" + dx }); svg.on("click", function() { var coords = d3.mouse(this); var newData = { x: d3.event.x, } data.push(newData); group.selectAll("rect") .data(data) .exit() .enter() .append("rect") .attr("x", function(d) { return dx; }) .attr("y", 200) .attr("height", 100) .attr("width", 15) .style("fill", "steelblue") .attr('id', function(d, i) { return 'rect_' + i; }) .attr("rx", 6) .attr("ry", 6) .attr("stroke-width", 2) .attr("stroke", "black"); }); function dragstarted(d) { d3.select(this).raise().classed("active", true); } function dragged(d) { d3.select(this).select("text") .attr("x", dx = d3.event.x); d3.select(this).select("rect") .attr("x", dx = d3.event.x); } function dragended(d) { d3.select(this) .classed("active", false); } function removeElement(d) { d3.event.stopPropagation(); data = data.filter(function(e) { return e != d; }); d3.select(this) .remove(); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.2/d3.min.js"></script> <svg width="960" height="500"></svg>
But, what the problem with adding the new element, I have no idea.
Here are the explanations to your issues:
var groups
, that is, you have two var groups
in your code, the last one overwriting the first one. Just remove the last variable.<g>
) elements, not rectangles.Have a look at the refactored function, it binds the data to a newly created group and appends the rectangle to that group:
var newGroup = svg.selectAll(".group")
.data(data, function(d) {
return d.x
})
.enter()
.append("g")
//etc...
newGroup.append("rect")
//etc...
Also, use a key selection in the data binding, so you know exactly what rectangle is being dragged:
.data(data, function(d){return d.x})
Here is your code with those changes:
<!DOCTYPE html> <meta charset="utf-8"> <style> /*.active { stroke: #000; stroke-width: 2px; }*/ </style> <svg width="960" height="500"></svg> <script src="//d3js.org/d3.v4.min.js"></script> <script> var margin = { top: 20, right: 20, bottom: 20, left: 20 }, width = 600 - margin.left - margin.right, height = 600 - margin.top - margin.bottom; var svg = d3.select("svg"); var data = [{ x: 200 }, { x: 300 }, { x: 400 }]; var groove = svg.append("g") .attr("class", "groove_group"); groove.append("rect") .attr("x", 100) .attr("y", 150) .attr("rx", 2) .attr("ry", 2) .attr("height", 6) .attr("width", 800) .style("fill", "grey"); groove.append("rect") .attr("x", 102) .attr("y", 152) .attr("rx", 2) .attr("ry", 2) .attr("height", 2) .attr("width", 796) .style("fill", "black"); // create group var group = svg.selectAll(null) .data(data, function(d){return dx}) .enter().append("g") .attr("class", "group") .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)) .on("click", removeElement); group.append("rect") .attr("x", function(d) { return dx; }) .attr("y", 100) .attr("height", 100) .attr("width", 15) .style("fill", "lightblue") .attr('id', function(d, i) { return 'handle_' + i; }) .attr("rx", 6) .attr("ry", 6) .attr("stroke-width", 2) .attr("stroke", "black"); group.append("text") .attr("x", function(d) { return dx }) .attr("y", 100) .attr("text-anchor", "start") .style("fill", "black") .text(function(d) { return "x:" + dx }); svg.on("click", function() { var coords = d3.mouse(this); var newData = { x: coords[0], } data.push(newData); var newGroup = svg.selectAll(".group") .data(data, function(d){return dx}) .enter() .append("g") .attr("class", "group") .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)) .on("click", removeElement); newGroup.append("rect") .attr("x", function(d) { return dx; }) .attr("y", 200) .attr("height", 100) .attr("width", 15) .style("fill", "steelblue") .attr('id', function(d, i) { return 'rect_' + i; }) .attr("rx", 6) .attr("ry", 6) .attr("stroke-width", 2) .attr("stroke", "black"); }); function dragstarted(d) { d3.select(this).raise().classed("active", true); } function dragged(d) { d3.select(this).select("text") .attr("x", dx = d3.event.x); d3.select(this).select("rect") .attr("x", dx = d3.event.x); } function dragended(d) { d3.select(this) .classed("active", false); } function removeElement(d) { d3.event.stopPropagation(); data = data.filter(function(e) { return e != d; }); d3.select(this) .remove(); } </script>
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.