Как обновить SVG-путь с помощью d3.js
Я хотел бы применить общий шаблон обновления от официальной документации, чтобы обновить SVG-путь в событии мыши (но может быть кнопкой или что-то еще).
Но путь добавляется и не обновляется. Я думаю, почему я не правильно использую свойства enter
и exit
, но после некоторого различного пробного периода я не могу позволить ему работать.
Вот jsfiddle.
Мой код js находится здесь:
var shapeCoords = [
[10, 10], [100, 10], [100, 100], [10, 100]
];
$(function() {
var container = $('#container');
// D3
console.log("D3: ", d3);
var svg = d3.select('#container')
.append('svg:svg')
.attr('height', 600)
.attr('width', 800);
var line = d3.svg.line()
.x(function(d) { return d[0]; })
.y(function(d) { return d[1]; })
.interpolate('linear');
function render() {
svg.data(shapeCoords)
.append('svg:path')
.attr('d', line(shapeCoords) + 'Z')
.style('stroke-width', 1)
.style('stroke', 'steelblue');
}
render();
var mouseIsDown = false;
container.on('mousedown mouseup mousemove', function(e) {
if (e.type == 'mousedown') {
mouseIsDown = true;
shapeCoords[3] = [e.offsetX, e.offsetY];
} else if (e.type == 'mouseup' ){
mouseIsDown = false;
shapeCoords[3] = [e.offsetX, e.offsetY];
} else if (e.type == 'mousemove') {
if (mouseIsDown) {
shapeCoords[3] = [e.offsetX, e.offsetY];
render();
}
}
});
});
И html:
<!DOCTYPE html>
<html>
<head>
<title>D3 mousemove</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js">
</script>
<script type="text/javascript"
src="http://mbostock.github.com/d3/d3.js">
</script>
<script type="text/javascript" src="script.js"></script>
<style>
#container {
width: 800px;
height: 600px;
border: 1px solid silver; }
path, line {
stroke: steelblue;
stroke-width: 1;
fill: none;
}
</style>
</head>
<body>
<div id="container"></div>
</body>
</html>
Ответы
Ответ 1
Ваш код не выбирает существующий элемент, поэтому вместо обновления атрибута "d" существующего пути с помощью выбора update
он добавляет новый путь каждый раз. Эта версия render()
вызвала ожидаемое поведение. Подробнее о выборе здесь.
function render() {
path = svg.selectAll('path').data([shapeCoords])
path.attr('d', function(d){return line(d) + 'Z'})
.style('stroke-width', 1)
.style('stroke', 'steelblue');
path.enter().append('svg:path').attr('d', function(d){return line(d) + 'Z'})
.style('stroke-width', 1)
.style('stroke', 'steelblue');
path.exit().remove()
Как только вы запустите соединение данных на path
с помощью .data()
, операции, выполняемые в path
, применимы только к выбору обновления. Это означает, что только те существующие элементы, которые по-прежнему имеют соответствующие элементы данных в новом соединении. Когда вы вызываете enter().append()
, он добавляет новый элемент для каждого элемента данных без ранее существовавшего элемента, а затем применяет следующие операции только к этим элементам.
В приведенном выше примере первое path.attr()
работает только на существующих элементах; те, которые применяются после path.enter()
, применяются только к новым элементам. Он не показан в приведенном выше фрагменте, но enter()
добавляет выбор ввода к выбору обновления: любые операции над path
после вызова enter()
будут применяться как к существующим, так и к новым элементам.
Ответ 2
Пожалуйста, попробуйте следующий код, я думаю, это то, что вы хотите. Проблема вызвана тем, что вы должны различать ввод, обновление и завершение, когда хотите обновлять элементы, иначе он будет добавлять данные снова и снова.
$(function() {
var container = $('#container');
// D3
console.log("D3: ", d3);
var svg = d3.select('#container')
.append('svg:svg')
.attr('height', 600)
.attr('width', 800);
var line = d3.svg.line()
.x(function(d) { return d[0]; })
.y(function(d) { return d[1]; })
.interpolate('linear');
svg.data(shapeCoords)
.append('svg:path')
.attr('d', line(shapeCoords) + 'Z')
.style('stroke-width', 1)
.style('stroke', 'steelblue');
function render() {
var svg = d3.select('#container').select("svg").selectAll('path').data(shapeCoords);
svg.enter().append('svg:path')
.attr('d', line(shapeCoords) + 'Z')
.style('stroke-width', 1)
.style('stroke', 'steelblue');
svg.attr('d', line(shapeCoords) + 'Z')
.style('stroke-width', 1)
.style('stroke', 'steelblue');
svg.exit().remove();
}
render();