Reputation: 3337
I have an initial array of object which is my data. A function called render()
is called which should first display rectangles bound to this data. But I am not seeing any rectangles.
Then if any of these rectangles is clicked a function removeElement
is called, which removes that rectangle's data from the array and then calls render()
and executes it using the new data.
If the svg is clicked on anywhere a new data element is added to the data, and again render is called which should display the rectangles again according to the new data.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
/*.active {
stroke: #000;
stroke-width: 2px;
}*/
svg {
border: 1px solid black;
}
</style>
<svg width="800" height="300"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var margin = {
top: 20,
right: 20,
bottom: 20,
left: 20
},
width = 840 - margin.left - margin.right,
height = 640 - margin.top - margin.bottom;
var svg = d3.select("svg");
var data = [{
x: 100
}, {
x: 300
}, {
x: 400
}, {
x: 600
}];
var ind = 0;
var groove = svg.append("g")
.attr("class", "groove_group");
groove.append("rect")
.attr("x", 0)
.attr("y", 150)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 6)
.attr("width", width)
.style("fill", "grey");
groove.append("rect")
.attr("x", 2)
.attr("y", 152)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 2)
.attr("width", 796)
.style("fill", "black");
render();
function render() {
// create group
var group = svg.selectAll(null)
.data(data, function(d) {
return d.x
});
group.exit().remove();
group.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 d.x;
})
.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, i) {
if (i == 0) { // first element
return ((data[i].x / 2));
} else {
return (data[i].x - (data[i].x - data[i - 1].x) / 2);
}
})
.attr("y", 100)
.attr("text-anchor", "middle")
.style("fill", "black")
.attr('id', function(d, i) {
return 'text_' + i;
})
.text(function(d, i) {
if (i == 0) { // first set
return i + ": " + (data[i].x) + "m";
} else {
return i + ": " + ((data[i].x - data[i - 1].x)) + "m";
}
});
}
svg.on("click", function() {
var coords = d3.mouse(this);
getPosition(ind, coords[0]);
render();
});
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d, i) {
if (i == 0) {
d3.select("#text_" + i)
.attr("x", d.x = (d3.event.x / 2))
.text(function(d) {
return i + " " + d3.event.x
});
d3.select("#text_" + (i + 1))
.attr("x", d.x = d3.event.x + ((data[i + 1].x - d3.event.x) / 2))
.text(function(d) {
return (i + 1) + " " + (data[i + 1].x - d3.event.x) + "m"
});
d3.select(this).select("rect")
.attr("x", d.x = d3.event.x);
} else if (i == data.length - 1) {
d3.select("#text_" + i)
.attr("x", d.x = (d3.event.x - data[i - 1].x) / 2 + data[i - 1].x)
.text(function(d) {
return i + ": " + (d3.event.x - data[i - 1].x) + "m"
});
d3.select("#text_" + (i + 1))
.attr("x", d.x = d3.event.x + (width - d3.event.x) / 2)
.text(function(d) {
return (i + 1) + ": " + (width - d3.event.x) + "m"
});
d3.select(this).select("rect")
.attr("x", d.x = d3.event.x);
} else {
d3.select("#text_" + i)
.attr("x", d.x = d3.event.x - ((d3.event.x - data[i - 1].x) / 2))
.text(function(d) {
return i + ": " + (d3.event.x - data[i - 1].x) + "m"
});
d3.select("#text_" + (i + 1))
.attr("x", d.x = d3.event.x + ((data[i + 1].x - d3.event.x) / 2))
.text(function(d) {
return (i + 1) + ": " + (data[i + 1].x - d3.event.x) + "m"
});
d3.select(this).select("rect")
.attr("x", d.x = d3.event.x);
}
}
function dragended(d) {
d3.select(this)
.classed("active", false);
}
function removeElement(d, i) {
d3.event.stopPropagation();
data = data.filter(function(e) {
return e != d;
});
d3.select(this)
.remove();
render();
}
function getPosition(ind, coords) {
if (coords[0] > data[ind].x) {
getPosition(++ind);
} else {
data.splice(1, 0, {
x: coords
});
}
}
</script>
Any help would be greatly appreciated,
Upvotes: 1
Views: 41
Reputation: 102174
If you look at group
...
var group = svg.selectAll(null)
.data(data, function(d) {
return d.x
});
... you'll see that it is just an "update" selection. There is no SVG <g>
element being appended here. Thus, this...
group.append("rect")
//etc...
Has no effect.
Solution: Use a merge()
function or a proper enter selection:
var groupEnter = group.enter()
.append("g")
.attr("class", "group");
groupEnter.append("rect")
//etc...
Here is the updated code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
/*.active {
stroke: #000;
stroke-width: 2px;
}*/
svg {
border: 1px solid black;
}
</style>
<svg width="800" height="300"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var margin = {
top: 20,
right: 20,
bottom: 20,
left: 20
},
width = 840 - margin.left - margin.right,
height = 640 - margin.top - margin.bottom;
var svg = d3.select("svg");
var data = [{
x: 100
}, {
x: 300
}, {
x: 400
}, {
x: 600
}];
var ind = 0;
var groove = svg.append("g")
.attr("class", "groove_group");
groove.append("rect")
.attr("x", 0)
.attr("y", 150)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 6)
.attr("width", width)
.style("fill", "grey");
groove.append("rect")
.attr("x", 2)
.attr("y", 152)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 2)
.attr("width", 796)
.style("fill", "black");
render();
function render() {
// create group
var group = svg.selectAll(null)
.data(data, function(d) {
return d.x
});
group.exit().remove();
var groupEnter = group.enter().append("g")
.attr("class", "group");
groupEnter.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("click", removeElement);
groupEnter.append("rect")
.attr("x", function(d) {
return d.x;
})
.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");
groupEnter.append("text")
.attr("x", function(d, i) {
if (i == 0) { // first element
return ((data[i].x / 2));
} else {
return (data[i].x - (data[i].x - data[i - 1].x) / 2);
}
})
.attr("y", 100)
.attr("text-anchor", "middle")
.style("fill", "black")
.attr('id', function(d, i) {
return 'text_' + i;
})
.text(function(d, i) {
if (i == 0) { // first set
return i + ": " + (data[i].x) + "m";
} else {
return i + ": " + ((data[i].x - data[i - 1].x)) + "m";
}
});
}
svg.on("click", function() {
var coords = d3.mouse(this);
getPosition(ind, coords[0]);
render();
});
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d, i) {
if (i == 0) {
d3.select("#text_" + i)
.attr("x", d.x = (d3.event.x / 2))
.text(function(d) {
return i + " " + d3.event.x
});
d3.select("#text_" + (i + 1))
.attr("x", d.x = d3.event.x + ((data[i + 1].x - d3.event.x) / 2))
.text(function(d) {
return (i + 1) + " " + (data[i + 1].x - d3.event.x) + "m"
});
d3.select(this).select("rect")
.attr("x", d.x = d3.event.x);
} else if (i == data.length - 1) {
d3.select("#text_" + i)
.attr("x", d.x = (d3.event.x - data[i - 1].x) / 2 + data[i - 1].x)
.text(function(d) {
return i + ": " + (d3.event.x - data[i - 1].x) + "m"
});
d3.select("#text_" + (i + 1))
.attr("x", d.x = d3.event.x + (width - d3.event.x) / 2)
.text(function(d) {
return (i + 1) + ": " + (width - d3.event.x) + "m"
});
d3.select(this).select("rect")
.attr("x", d.x = d3.event.x);
} else {
d3.select("#text_" + i)
.attr("x", d.x = d3.event.x - ((d3.event.x - data[i - 1].x) / 2))
.text(function(d) {
return i + ": " + (d3.event.x - data[i - 1].x) + "m"
});
d3.select("#text_" + (i + 1))
.attr("x", d.x = d3.event.x + ((data[i + 1].x - d3.event.x) / 2))
.text(function(d) {
return (i + 1) + ": " + (data[i + 1].x - d3.event.x) + "m"
});
d3.select(this).select("rect")
.attr("x", d.x = d3.event.x);
}
}
function dragended(d) {
d3.select(this)
.classed("active", false);
}
function removeElement(d, i) {
d3.event.stopPropagation();
data = data.filter(function(e) {
return e != d;
});
d3.select(this)
.remove();
render();
}
function getPosition(ind, coords) {
if (coords[0] > data[ind].x) {
getPosition(++ind);
} else {
data.splice(1, 0, {
x: coords
});
}
}
</script>
PS: Your code still have a lot of problems (and I can foresee future questions here)... This answer is dealing only with the main issue regarding the "enter" selection.
Upvotes: 1