D3 удалить круг на dbclick
Я использую Bostock Circle Draging I и Will D3 Mouse Event, чтобы я мог щелкнуть по svg и создать круг, а также они все перетаскиваемые. Это работает, хотя есть побочная проблема, если я дважды щелкаю при создании круга, иногда перетаскивая круги, они заставляют их прыгать.
Но главная проблема заключается в том, что я хотел бы иметь возможность дважды щелкнуть по кругу и заставить его исчезнуть, а также удалить его из данных.
Когда нарисованы круги, я добавил событие dbclick, которое вызывает функцию
function removeElement(d) {
// need to remove this object from data
d3.select(this)
.exit()
.remove();
}
Эта функция также вызывается при создании нового круга.
Эта функция не удаляет круги, как правильно это сделать? И существует ли конфликт между одним щелчком мыши, выполняющим одно, и двойным щелчком, выполняющим что-то другое?
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = 32;
var data = [{
x: 100,
y: 200
},
{
x: 200,
y: 300
},
{
x: 300,
y: 200
},
{
x: 400,
y: 300
}
];
var xScale = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.x_pos
})]).range([0, width]);
svg.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", radius)
.style("fill", "lightblue")
.attr('id', function(d, i) {
return 'rect_' + i;
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("dblclick", removeElement());
svg.on("click", function() {
var coords = d3.mouse(this);
var newData = {
x: d3.event.x,
y: d3.event.y
};
data.push(newData);
svg.selectAll("circle") // For new circle, go through the update process
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", radius)
.style("fill", "red")
.attr('id', function(d, i) {
return 'circle_' + i;
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("dblclick", removeElement());
})
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d) {
d3.select(this)
.attr("cx", d.x = d3.event.x)
.attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this)
.classed("active", false);
}
function removeElement(d) {
// need to remove this object from data
d3.select(this)
.exit()
.remove();
}
.active {
stroke: #000;
stroke-width: 2px;
}
<!DOCTYPE html>
<meta charset="utf-8">
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
1 ответ
Самая большая проблема, с которой вы столкнетесь при написании кода, - это щелчок двойным щелчком. Однако, поскольку вы спрашивали, как удалить кружки, этот ответ будет касаться только этой проблемы.
Ваш код для удаления кругов имеет две проблемы.
Во-первых, это...
.on("dblclick", removeElement())
... позвоню removeElement
немедленно и вернуть его значение (которое, кстати, undefined
). Это не то, что вы хотите.
Вместо этого сделайте это:
.on("dblclick", removeElement)
Что то же самое из:
.on("dbclick", function(d){
removeElement(d);
}
Сюда, removeElement
будет вызываться только тогда, когда пользователь нажимает на круг, а не сразу.
Вторая проблема заключается в следующем:
d3.select(this).exit().remove();
Поскольку с этим кругом все еще связаны данные, ваш выбор "выход" пуст.
Вместо этого должно быть:
d3.select(this).remove();
Вот ваш код с этими изменениями:
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = 32;
var data = [{
x: 100,
y: 200
},
{
x: 200,
y: 300
},
{
x: 300,
y: 200
},
{
x: 400,
y: 300
}
];
var xScale = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.x_pos
})]).range([0, width]);
svg.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", radius)
.style("fill", "lightblue")
.attr('id', function(d, i) {
return 'rect_' + i;
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("dblclick", removeElement);
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d) {
d3.select(this)
.attr("cx", d.x = d3.event.x)
.attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this)
.classed("active", false);
}
function removeElement(d) {
// need to remove this object from data
d3.select(this)
.remove();
}
.active {
stroke: #000;
stroke-width: 2px;
}
<!DOCTYPE html>
<meta charset="utf-8">
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
PS: я убрал клик по SVG для создания кругов. Поскольку этот вопрос (отличающий клик от двойного клика) очень сложен, он может стоить нового отдельного вопроса.