我在使用以下代码时遇到错误。
const div = d3.select('div');
const t = d3.timer((e) => {
const outerOneData = d3.range(0,5);
const outerTwoData = d3.range(0,3);
const outerOne = div.selectAll('div');
outerOne.exit().remove();
outerOne.data(outerOneData)
.join('xhtml:div')
.attr('id',(_,i)=>`outer${i}`);
const outerTwo = outerOne.selectAll('div');
outerTwo.exit().remove();
outerTwo.data(outerTwoData)
.join('xhtml:div')
.attr('id',(_,i)=>`outerTwo${i}`);
if (e > 200) t.stop();
}, 150);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<body>
<div id="viz"></div>
</body>
<script>
</script>
</html>
但不适用于以下内容(当我只做一个级别时)。
const div = d3.select('div');
const t = d3.timer((e) => {
const outerOneData = d3.range(0,5);
const outerTwoData = d3.range(0,3);
const outerOne = div.selectAll('div');
outerOne.exit().remove();
outerOne.data(outerOneData)
.join('xhtml:div')
.attr('id',(_,i)=>`outer${i}`);
/*const outerTwo = outerOne.selectAll('div');
outerTwo.exit().remove();
outerTwo.data(outerTwoData)
.join('xhtml:div')
.attr('id',(_,i)=>`outerTwo${i}`);*/
if (e > 200) t.stop();
}, 150);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<body>
<div id="viz"></div>
</body>
<script>
</script>
</html>
我打算 d3 给我以下 DOM 中的数据绑定结构
└── doc
├── <div id='viz'>
│ └── <div id='outer0'>
│ ├── <div id='inner0'>
│ ├── <div id='inner1'>
│ └── <div id='inner2'>
问题在于您在 D3 中使用的层次结构和选择机制。
在第一个示例中,将数据绑定到outerOne并创建div元素后,您立即尝试选择其中的div元素并将数据绑定到outerTwo。由于 D3 的工作原理,此操作本质上是有缺陷的:
这会导致 D3 尝试将子 div (outerTwo) 附加到其自身或其直接父级 (outerOne),从而导致 DOMException 错误。
修复第一个示例:
这是更正后的版本
const div = d3.select('#viz');
const t = d3.timer((e) => {
const outerOneData = d3.range(0, 5);
const outerTwoData = d3.range(0, 3);
// Bind outerOneData to top-level divs
const outerOne = div.selectAll('.outerOne').data(outerOneData);
// Create/Update/Remove top-level divs
outerOne
.join('div')
.classed('outerOne', true) // Assign a class to distinguish them
.attr('id', (_, i) => `outer${i}`)
.selectAll('.outerTwo') // Now select child divs inside each outerOne div
.data(() => outerTwoData) // Bind outerTwoData to child divs
.join('div')
.classed('outerTwo', true) // Assign a class to distinguish them
.attr('id', (_, i) => `outerTwo${i}`);
// Remove divs no longer in the data
outerOne.exit().remove();
if (e > 200) t.stop();
}, 150);