我一直在尝试着如何仅更新那些数据已更改但仍不正确的d3
节点。在下面的小测试示例中,我仍然在改变它的所有外观。
我这样做是完全错误还是只是有些错误?
在示例中,单击形状可将形状切换为圆形或正方形,并更新“ clickCnt”属性。然后重新绘制数据。有点工作,但似乎正在重画所有内容。另外,由于某种原因,点击“红色”形状也无法正常工作,但是代码完全相同。
任何见解或技巧都将受到欢迎-我整天都被困在这
var dataArray = [];
dataArray.push({ "label": 'red', "shape": "circle", "clickCnt": 0, x: 30, y: 100 });
dataArray.push({ "label": 'orange', "shape": "square", "clickCnt": 0, x: 110, y: 100 });
dataArray.push({ "label": 'yellow', "shape": "circle", "clickCnt": 0, x: 210, y: 100 });
dataArray.push({ "label": 'green', "shape": "square", "clickCnt": 0, x: 310, y: 100 });
dataArray.push({ "label": 'blue', "shape": "circle", "clickCnt": 0, x: 30, y: 200 });
dataArray.push({ "label": 'indigo', "shape": "square", "clickCnt": 0, x: 110, y: 200 });
dataArray.push({ "label": 'violet', "shape": "circle", "clickCnt": 0, x: 210, y: 200 });
dataArray.push({ "label": 'white', "shape": "square", "clickCnt": 0, x: 310, y: 200 });
var width = 400;
var height = 400;
d3.select("div#svg-container").select("svg").remove();
var svg = d3.select("#svg-container").append("svg")
.attr("width", width)
.attr("height", height);
var content = svg.append("g")
function create(data) {
var groups = content.selectAll("g")
.data(data, function (d) {
return d;
});
groups.exit().remove();
groups.enter()
.append("g")
.attr('transform', function (d, i) {
return 'translate(' + d.x + ',' + d.y + ')'
})
.each(function (d) {
var e = d3.select(this);
e.append("text")
.classed("small-text", true)
.classed("label", true)
.text(function (d) {
return d.label;
})
.style("fill", function (d) {
return d.label;
});
e.append("text")
.classed("small-text", true)
.classed("clickCnt", true)
.attr("y", 20)
.text(function (d) {
return d.clickCnt;
})
.style("fill", function (d) {
return d.label;
})
if (d.shape == "circle") {
e.append("circle")
.attr("class", "circle")
.attr("r", 15)
.attr("cx", 10)
.attr("cy", -40)
.on("click", iconClicked)
.style("cursor", "pointer");
} else if (d.shape == "square") {
e.append("rect")
.attr("class", "square")
.attr("width", 30)
.attr("height", 30)
.attr("x", 0)
.attr("y", -55)
.on("click", iconClicked)
.style("cursor", "pointer");
}
});
}
create(dataArray);
function iconClicked(evt) {
if (evt.shape == "circle") {
evt.shape = "square"
} else if (evt.shape == "square") {
evt.shape = "circle"
}
evt.clickCnt++;
document.getElementById('output').innerHTML = "item clicked: " + evt.label + " " + evt.clickCnt;
create(dataArray);
}
.circle {
stroke: red;
stroke-width: 2px;
}
.square {
stroke: blue;
stroke-width: 2px;
}
#timeline-background {
background: slategray;
}
.label {
fill: blue;
}
.small-text {
font-size: 16px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<body>
<label id="output">out</label>
<div id="timeline-background" style="width: 100%; height: 100%;">
<div id="svg-container"></div>
</div>
</body>
答案 0 :(得分:0)
绑定数据时,这里的问题是key function。
如果您查看文档,将会看到:
可以通过计算每个数据和元素的 string 标识符,指定一个关键功能来控制将哪个数据分配给哪个元素,从而替换默认的按索引联接。 (强调我的)
但是,在您的情况下,不是使用字符串,而是返回了整个对象:
var groups = content.selectAll("g")
.data(data, function (d) {
return d;
// ^--- this is an object
});
当然,这是行不通的。
因此,我们具有您描述的行为:您的exit
选择包含所有组,并且它们都被删除。然后,enter选择包含所有元素,并且它们都被重新绘制。
让我们看一下,单击元素,然后查看控制台:
var dataArray = [];
dataArray.push({ "label": 'red', "shape": "circle", "clickCnt": 0, x: 30, y: 100 });
dataArray.push({ "label": 'orange', "shape": "square", "clickCnt": 0, x: 110, y: 100 });
dataArray.push({ "label": 'yellow', "shape": "circle", "clickCnt": 0, x: 210, y: 100 });
dataArray.push({ "label": 'green', "shape": "square", "clickCnt": 0, x: 310, y: 100 });
dataArray.push({ "label": 'blue', "shape": "circle", "clickCnt": 0, x: 30, y: 200 });
dataArray.push({ "label": 'indigo', "shape": "square", "clickCnt": 0, x: 110, y: 200 });
dataArray.push({ "label": 'violet', "shape": "circle", "clickCnt": 0, x: 210, y: 200 });
dataArray.push({ "label": 'white', "shape": "square", "clickCnt": 0, x: 310, y: 200 });
var width = 400;
var height = 400;
d3.select("div#svg-container").select("svg").remove();
var svg = d3.select("#svg-container").append("svg")
.attr("width", width)
.attr("height", height);
var content = svg.append("g")
function create(data) {
var groups = content.selectAll("g")
.data(data, function (d) {
return d;
});
console.log("The exit selection size is: " + groups.exit().size())
groups.exit().remove();
groups.enter()
.append("g")
.attr('transform', function (d, i) {
return 'translate(' + d.x + ',' + d.y + ')'
})
.each(function (d) {
var e = d3.select(this);
e.append("text")
.classed("small-text", true)
.classed("label", true)
.text(function (d) {
return d.label;
})
.style("fill", function (d) {
return d.label;
});
e.append("text")
.classed("small-text", true)
.classed("clickCnt", true)
.attr("y", 20)
.text(function (d) {
return d.clickCnt;
})
.style("fill", function (d) {
return d.label;
})
if (d.shape == "circle") {
e.append("circle")
.attr("class", "circle")
.attr("r", 15)
.attr("cx", 10)
.attr("cy", -40)
.on("click", iconClicked)
.style("cursor", "pointer");
} else if (d.shape == "square") {
e.append("rect")
.attr("class", "square")
.attr("width", 30)
.attr("height", 30)
.attr("x", 0)
.attr("y", -55)
.on("click", iconClicked)
.style("cursor", "pointer");
}
});
}
create(dataArray);
function iconClicked(evt) {
if (evt.shape == "circle") {
evt.shape = "square"
} else if (evt.shape == "square") {
evt.shape = "circle"
}
evt.clickCnt++;
document.getElementById('output').innerHTML = "item clicked: " + evt.label + " " + evt.clickCnt;
create(dataArray);
}
.as-console-wrapper { max-height: 20% !important;}
.circle {
stroke: red;
stroke-width: 2px;
}
.square {
stroke: blue;
stroke-width: 2px;
}
#timeline-background {
background: slategray;
}
.label {
fill: blue;
}
.small-text {
font-size: 16px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<body>
<label id="output">out</label>
<div id="timeline-background" style="width: 100%; height: 100%;">
<div id="svg-container"></div>
</div>
</body>
(部分)解决方案:使用唯一字符串作为返回值,例如label
属性:
var groups = content.selectAll("g")
.data(data, function (d) {
return d.label;
});
看看:
var dataArray = [];
dataArray.push({ "label": 'red', "shape": "circle", "clickCnt": 0, x: 30, y: 100 });
dataArray.push({ "label": 'orange', "shape": "square", "clickCnt": 0, x: 110, y: 100 });
dataArray.push({ "label": 'yellow', "shape": "circle", "clickCnt": 0, x: 210, y: 100 });
dataArray.push({ "label": 'green', "shape": "square", "clickCnt": 0, x: 310, y: 100 });
dataArray.push({ "label": 'blue', "shape": "circle", "clickCnt": 0, x: 30, y: 200 });
dataArray.push({ "label": 'indigo', "shape": "square", "clickCnt": 0, x: 110, y: 200 });
dataArray.push({ "label": 'violet', "shape": "circle", "clickCnt": 0, x: 210, y: 200 });
dataArray.push({ "label": 'white', "shape": "square", "clickCnt": 0, x: 310, y: 200 });
var width = 400;
var height = 400;
d3.select("div#svg-container").select("svg").remove();
var svg = d3.select("#svg-container").append("svg")
.attr("width", width)
.attr("height", height);
var content = svg.append("g")
function create(data) {
var groups = content.selectAll("g")
.data(data, function (d) {
return d.label;
});
console.log("The exit selection size is: " + groups.exit().size())
groups.exit().remove();
groups.enter()
.append("g")
.attr('transform', function (d, i) {
return 'translate(' + d.x + ',' + d.y + ')'
})
.each(function (d) {
var e = d3.select(this);
e.append("text")
.classed("small-text", true)
.classed("label", true)
.text(function (d) {
return d.label;
})
.style("fill", function (d) {
return d.label;
});
e.append("text")
.classed("small-text", true)
.classed("clickCnt", true)
.attr("y", 20)
.text(function (d) {
return d.clickCnt;
})
.style("fill", function (d) {
return d.label;
})
if (d.shape == "circle") {
e.append("circle")
.attr("class", "circle")
.attr("r", 15)
.attr("cx", 10)
.attr("cy", -40)
.on("click", iconClicked)
.style("cursor", "pointer");
} else if (d.shape == "square") {
e.append("rect")
.attr("class", "square")
.attr("width", 30)
.attr("height", 30)
.attr("x", 0)
.attr("y", -55)
.on("click", iconClicked)
.style("cursor", "pointer");
}
});
}
create(dataArray);
function iconClicked(evt) {
if (evt.shape == "circle") {
evt.shape = "square"
} else if (evt.shape == "square") {
evt.shape = "circle"
}
evt.clickCnt++;
document.getElementById('output').innerHTML = "item clicked: " + evt.label + " " + evt.clickCnt;
create(dataArray);
}
.as-console-wrapper { max-height: 20% !important;}
.circle {
stroke: red;
stroke-width: 2px;
}
.square {
stroke: blue;
stroke-width: 2px;
}
#timeline-background {
background: slategray;
}
.label {
fill: blue;
}
.small-text {
font-size: 16px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<body>
<label id="output">out</label>
<div id="timeline-background" style="width: 100%; height: 100%;">
<div id="svg-container"></div>
</div>
</body>
现在,如您所见,exit
选择的大小始终为零。
但是,我写 partial 的原因是:您不再更改元素了!原因是您没有正确的更新选择。由于退出选择不再具有任何元素,因此进入选择的大小也为零。这里没有任何更新。
创建此类更新选择超出了此答案的范围,我将把这项工作留给您。