d3js输入().在exit().remove()后追加
d3js enter().append after exit().remove()
我有一个可以按日期范围和情感过滤的词云。有时数据会更多,有时会更少。当我删除数据,更新dom,然后添加数据时,被删除的元素将不会回来。使用d3js版本3.4.13
var width = 600, height = 200;
var words = ["Hello", "world", "Wonderful"];
//inserting text
var wcwords = d3.select("#wordcloud")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.selectAll("text")
.data(words)
.enter()
.append("text");
wcwords
.attr("transform", function(d,i) {
return "translate(" + [5, 20*i] + ")";
})
.text(function(d) { return d; });
//changing data and updating dom (in this change there are less items)
wcwords.data(words.slice(0,2)).exit().remove();
//changing data and updating dom (in this change there are more items)
wcwords.data(words.concat(["No"])).enter().append('text')
.attr("transform", function(d,i) {
return "translate(" + [5, 20*i] + ")";
})
.text(function(d) { return d; });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg id='wordcloud'></svg>
编辑
原始代码不工作,更新了我的帖子与代码,做我需要的。新建,删除和更新的项目动画不同。我可以更改现有项目,删除项目,并再次返回项目。
技巧是使用正确的选择parent.selectAll(children)
并传递更新对象(由.data(newData)
返回的对象)
这里是"工作"的代码,希望我做对了:
var width = 600;
var height = 200;
var words = ["Hello", "world", "Wonderful"];
var when=1000;
var step=1;
//this function sets the data and passes the update object
// to exit, update and enter
function change(data){
var update = d3.select('#wccontainer')
.selectAll('text')
.data(data);
exitWords(update);
updateWords(update);
enterWords(update);
}
//existing items move to the right
function updateWords(update){
update
//this is an existing item, no need for append
.text(function(d) { return d; })
.transition()
.duration(when-100)
.attr("transform", function(d,i) {
this.left=this.left+25;
return "translate(" + [this.left, 20*i] + ")";
})
.style('opacity',1);
}
//new items fade in
function enterWords(update){
update
.enter()
.append("text")
.attr("transform", function(d,i) {
this.left=0;
return "translate(" + [5, 20*i] + ")";
})
.text(function(d) { return d; })
.style('opacity',0)
.transition()
.duration(when-100)
.attr("transform", function(d,i) {
return "translate(" + [5, 20*i] + ")";
})
.style('opacity',1);
}
//removed words fade out
function exitWords(update){
var removeItems = update
.exit()
removeItems
.transition()
.duration(when-800)
.style('opacity',0)
.each('end',function(){
removeItems.remove();
});
}
function later(when,fn,parms){
setTimeout(function(){
fn.apply(null,parms);
},when);
}
//create the g container and set svg width/height
d3.select("#wordcloud")
.attr("width", width)
.attr("height", height)
.append("g")
.attr('id','wccontainer')
.attr("transform", "translate(" + width / 2
+ "," + height / 2 + ")")
//set the text labels
change(words);
//in 1000ms (value of when) set the text lables with changed data
later(when,change,[words.slice(0,2)]);
//in 2000ms set the text lables with changed data
later(when*++step,change,[["CHANGED"]
.concat(words.slice(1,2))
.concat(["ONE","TWO","THREE","FOUR"])]);
//in 3000ms set the text lables with the original values
later(when*++step,change,[words]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg id='wordcloud'></svg>
我先解释一下发生了什么…
var width = 600, height = 200;
var words = ["Hello", "world", "Wonderful"];
var wcwords = d3.select("#wordcloud")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.selectAll("text")
.data(words);
.enter()
.append("text");
wcwords现在是一个enter选择,恰好与update集合具有相同的结构,因为所有元素都是新的。因为使用了selectAll
,所以选择被嵌套在g
节点下:这是选择的父对象。
wcwords
.attr("transform", function(d,i) {
return "translate(" + [5, 20*i] + ")";
})
.text(function(d) { return d; });
wcwords.data(words.slice(0,2)).exit().remove();
所有这些都是使用data
方法作为选择器来删除一个DOM元素。新的选择(只有两个元素)没有在作用域中引用,wcwords
不变,所以实际上DOM现在与选择不同步了。
wcwords.data(words.concat(["No"])).enter().append('text')
.attr("transform", function(d,i) {
return "translate(" + [5, 20*i] + ")";
})
.text(function(d) { return d; });
创建了一个新的选区,同样,wcwords
对象保持不变。将wcwords
的节点结构(不是DOM结构)与新的数据结构进行比较,因为前者有3个节点,后者有4个节点,而且因为data
保留了索引,所以enter选择将由一组4个元素组成,前三个元素null
和最后一个元素是新节点的数据对象。然后通过append
语句将一个新的文本节点添加到wcwords
的父节点(g
)的末尾。由于第三个元素不在enter选项中,因此不会重新插入它。
基本原则是
-
data
不会改变调用它的对象,它返回一个对新选择的引用(这里忽略) -
data
语句在构造进入、更新和退出选择时比较选择结构和数据结构。它不与DOM结构比较。
我猜你期望的顺序,因为你还没有分享,但也许你想要的是下面的东西。
var width = 70, height = 100;
var words = ["Hello", "world", "Wonderful"];
var outputLog = OutputLog("#output-log");
var transitionLog = OutputLog("#transition-log");
var wcwords = d3.select("#wordcloud").style("display", "inline-block")
.attr("width", width)
.attr("height", height)
.append("g")
.style("font-size", "10px")
.attr("transform", "translate(" + 10 + "," + 20 + ")")
.selectAll("text")
.data(words)
.enter()
.append("text")
.style("opacity", 0);
wcwords
.text(function(d) { return d; })
.attr("transform", function(d,i) {
return "translate(" + [5, 20*i] + ")";
})
.call(step, 0, "in")
.call(log, "wcwords.data(words) enter");
// bind a new data set to the selection and return the update selection
var wcwords = wcwords.data(words.slice(0,2))
.call(log, "wcwords.data(words.slice(0,2)) update");
// merge the enter selection into the update selection and update the DOM
wcwords.enter()
.append("text")
.style("opacity", 0);
wcwords.exit().transition().call(step, 1, "out").remove()
.call(log, "exit");
// modify the selection by rebinding the original data
// but with an extra element concatenated
// and return the update selection
var wcwords = wcwords.data(words.concat(["No"]))
.call(log, "wcwords.data(words.concat(['No'])) update");
// update the DOM and merge the exit selection into the update selection
wcwords.enter().append('text')
.attr("transform", function(d,i) {
return "translate(" + [5, 20*i] + ")";
})
.text(function(d) { return d; })
.style("opacity", 0)
.call(step, 2, "in")
.call(log, "enter");
function datum(n){
return n ? d3.select(n).datum() : "";
}
function step (selection, s, type) {
var id = Date.now(),
opacity = {in: 1, out: 0},
t = 1000,
w = 0, b = "";
selection.each(function(d){w = Math.max(w, d.length) });
b = new Array(w+4).join('_')
this.transition(Date.now()).delay(s * t).duration(t)
.each("start." + id, function(d, i, j){
var n = this, node = d3.select(n),
DOM_node = d3.select(selection[0].parentNode)
.selectAll(this.nodeName).filter(function(d){return node.datum() === d});
DOM_node = DOM_node.length ? DOM_node[0][0] : null;
transitionLog.writeLine(["start ", (""+id).slice(-4), s, type, (d+b).slice(0,w), style(this, "opacity") || "null", DOM_node === n].join("'t"))
})
.each("interrupt." + id, function(d){
console.log(["'tinterrupt ", id, type, style(this, "opacity"), s].join("'t"))
})
.each("end." + id, function(d){
var n = this, node = d3.select(n),
DOM_node = d3.select(selection[0].parentNode)
.selectAll(this.nodeName).filter(function(d){return node.datum() === d});
DOM_node = DOM_node.length ? DOM_node[0][0] : null;
transitionLog.writeLine(["end", (""+id).slice(-4), s, type, (d+b).slice(0,w), style(this, "opacity") || "null", DOM_node === n].join("'t"))
})
.style("opacity", opacity[type]);
function style(n, a){return d3.select(n).style(a)}
}
function log(selection, title){
outputLog.writeLine(title);
outputLog.writeLine(this[0].map(datum), 1);
}
function OutputLog(selector) {
var outputLog = d3.select(selector)
.style({
"display" : "inline-block",
"font-size" : "10px",
"margin-left": "10px",
padding : "1em",
"white-space": "pre",
"background" : "#fd9801",
});
outputLog.writeLine = (function() {
var s = "";
return function(l, indent) {
this.text((s += ((indent ? " " : "") + l + "'n")));
}
})();
return outputLog
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="UTF-8"></script>
<svg id='wordcloud'></svg>
<div id="output-log"></div>
<div id="transition-log"></div>
相关文章:
- 表追加而不附加最后一个元素
- chart.series[id].remove()无法刷新高位图表/高位股票中其他系列的图例属性
- jQuery.remove(Selector)没有'不起作用
- 如何在jquery中停止在更改时追加值
- JQuery.on(“keydown”)追加到页面时不工作
- 使用rows().eevery().remove()时未更新行索引
- jQuery[button.class]未检测到用按钮追加行
- 使用jQuery'生成输入字段;s追加
- js”;在“;不按特定顺序追加键/值
- 如何在 ReactJs 中追加到表
- 文本框仅接受十进制值,并且应在十进制后追加2个零
- 为什么DocumentFragment在追加后被清除
- Sails.js/Waterline.add()和.remove()仅适用于第二次调用
- jQuery detach() v/s remove() v/s hide()
- 正在从JQuery追加Laravel Blade
- 有什么方法可以在下一个元素上进行追加吗
- jQuery-根据值在输入字段后追加图像
- jQuery动态使用.append()添加输入,但发布表单不是追加数据
- d3js输入().在exit().remove()后追加
- 调用remove()后如何重新追加元素