Hi Bruce,
The behavior you describe is possible using D3, without any extra plugins. The key to achieving the outcome you describe is the "general update pattern", which is described quite well in the
documentation for selection.merge.
In the code you shared, the logic that defines how circles should render is duplicated. It occurs once for the first render, adding the event listeners, and again for when the button is pressed, without adding the event listeners. The reason why the new circle doesn't have the event listener is because you are not invoking on() in second copy of the rendering logic.
Using the general update pattern, the rendering logic can be unified into a single render() function. This function can be called any number of times, with data that is different on each invocation. Here's one way your code can be refactored to work with the general update pattern, and also use selection.on to add event listeners to the circles:
function render(data){
var svg = d3.select("svg");
var circles = svg.selectAll("circle")
.data(data);
circles.exit().remove();
circles
.enter()
.append("circle")
.merge(circles)
.attr("cx",function(d){
return d.x;
})
.attr("cy",function(d){
return d.y;
})
.attr("r",function(d){
return d.r
})
.style("fill", function(d){
return d.color;
})
.on("click", test);
}
function test(d){
alert(d.x);
}
function main(){
var data = [
{x:100,y:100,r:30, color:"red"},
{x:200,y:200,r:30, color:"red"},
{x:300,y:300,r:30, color:"red"},
];
render(data);
var cx=400, cy=400, index=0;
d3.select(".btn1")
.on("click",function(){
data.push({
x:cx+index*100,
y:cy,
r:30,
color: "yellow"
});
index++;
render(data);
});
}
main();
Best regards,
Curran