#javascript #svg #dom #d3.js
Вопрос:
Я пишу вам, потому что я борюсь с D3.js (D3-выделение) для перемещения позиций существующих элементов в SVG.
Я видел много примеров создания новых элементов, но здесь мои элементы уже созданы.
У меня есть эта структура в моем svg :
<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
</g>
<g id='othergroup1' class='othergroup'>
<title>othergroup1</title>
<text id='text1'>textContent1</text>
<ellipse fill="#ac08b6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
<g id='othergroup2' class='othergroup'>
<title>othergroup2</title>
<text id='text2'>textContent2</text>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
Моя цель состоит в том, чтобы переместить все многоточия в основную группу, чтобы получить :
<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
<ellipse fill="#ac08b6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
Мне удалось сделать это благодаря участию в D3.js и часть с манипуляциями с ДОМОМ.
svg = d3.select('svg')
allellipses = svg.selectAll('ellipse').nodes()
for (ell of allellipses) {document.querySelector('.main').append(ell)}
Есть ли способ сделать это только с помощью D3.js ? Я хотел бы заменить document.querySelector
на D3.js функция. По крайней мере, знать и понимать, как работает добавление существующих элементов.
Но, возможно, для этой операции эффективнее использовать только простые манипуляции с DOM.
Ответ №1:
функция selection.remove() удаляет узлы из DOM, возвращая выбранные из них узлы.
selection.append() может быть предоставлена функция, которая добавляет данный узел.
Таким образом, мы можем удалить узлы, использовать узлы в качестве массива данных и ввести/добавить удаляемые эллипсы:
var ellipse = svg.selectAll("ellipse").remove();
svg.select("#maingroup")
.selectAll(null)
.data(ellipse.nodes())
.enter()
.append(d=>d);
var svg = d3.select("svg");
var ellipse = svg.selectAll("ellipse").remove();
svg.select("#maingroup")
.selectAll(null)
.data(ellipse.nodes())
.enter()
.append(d=>d);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
</g>
<g id='othergroup1' class='othergroup'>
<title>othergroup1</title>
<text id='text1'>textContent1</text>
<ellipse fill="#ac08b6" cx="198.5" cy="25" rx="30" ry="20"></ellipse>
</g>
<g id='othergroup2' class='othergroup'>
<title>othergroup2</title>
<text id='text2'>textContent2</text>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
</svg>
Конечно, мы пропускаем привязку данных и используем selection.remove() с selection.each() для добавления удаленных элементов к другому родителю:
var ellipse = svg.selectAll("ellipse")
.remove()
.each(function() {
svg.select("#maingroup").append(()=>this);
})
var svg = d3.select("svg");
var ellipse = svg.selectAll("ellipse")
.remove()
.each(function() {
svg.select("#maingroup").append(()=>this);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
</g>
<g id='othergroup1' class='othergroup'>
<title>othergroup1</title>
<text id='text1'>textContent1</text>
<ellipse fill="#ac08b6" cx="198.5" cy="25" rx="30" ry="20"></ellipse>
</g>
<g id='othergroup2' class='othergroup'>
<title>othergroup2</title>
<text id='text2'>textContent2</text>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
</svg>
Использование selection.insert() вместо selection.append() может обеспечить немного большую гибкость с точки зрения упорядочения добавляемых элементов.
Наконец, адаптируя ваш код с минимальными изменениями, мы можем просто использовать selection.append() с функцией, возвращающей узел в сочетании с циклом for:
var ellipses = svg.selectAll("ellipse").remove();
for(ellipse of ellipses) svg.select("#maingroup").append(()=>ellipse);
var svg = d3.select("svg");
var ellipses = svg.selectAll("ellipse").remove();
for(ellipse of ellipses) svg.select("#maingroup").append(()=>ellipse);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
<svg>
<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
</g>
<g id='othergroup1' class='othergroup'>
<title>othergroup1</title>
<text id='text1'>textContent1</text>
<ellipse fill="#ac08b6" cx="198.5" cy="30" rx="30" ry="20"></ellipse>
</g>
<g id='othergroup2' class='othergroup'>
<title>othergroup2</title>
<text id='text2'>textContent2</text>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
</svg>
Конечно, предварительный выбор основной группы будет более эффективным, чем выбор ее на каждой итерации, и простой javascript должен быть более производительным.