我正在使用d3为一堆数据创建线图可视化。该行的数据来自一个对象数组,我使用此函数将该数据转换为可显示的svg路径:
this.line = d3.svg.line()
.interpolate('linear')
// .x(function(d,i) {return x(d['date']);})
.x(function (d,i) {return x(i);})
.y(function (d,i) {return y(d[this.key]) - this.yOffset;});
但是,如果我将所有数据保留为单个对象数组(并将其设置为路径的唯一数据点),那么我将无法使用进入和退出转换来添加/删除某些段如果我的数据集改变了大小,则构成该行。因此,为了解决这个问题,我使用这个函数将我的点数组分成一个2D数组:一个长度为2的数组,每个数组包含我的一行特定段的起点和终点,然后我用它array作为我路径的数据,屏幕上的每个段都分别绑定到它自己的2元素数组。
当我调用setData并输入时,路径完全按照预期绘制。但是,当我使用更新功能更新数据时(在这种情况下我转换为更长的数据集),路径将经历相应的更新和退出转换,这表明我在绑定数据时提供的关键功能是按预期工作。但是当我再次调用enter时,它不只是绘制需要添加的一个段 - 相反,它会删除现有路径,并重新绘制整个行,这次包括新行段。
这里有什么我想念的吗?如何使其仅为新段的绘制设置动画,而不是擦除现有的线段?
所有相关代码如下 - 如果我需要澄清更多信息,请随时发表评论:
提前致谢!
this.line = d3.svg.line()
.interpolate('linear')
.x(function (d,i) {return x(d['date']);})
.y(function (d,i) {return y(d[this.key]) - this.yOffset;});
this.pathEnterData = function(selection) {
this.path = selection.enter().append('path')
.attr('class','segment')
.attr('d',function(d, i) {return mThis.line(d);})
.style('stroke', mThis.pathColor)
.style('stroke-width',2)
.style('fill','none');
};
this.pathEnterTransition = function(selection) {
return selection
.attr("stroke-dasharray", function(d) { var totLength = d3.select(this).node().getTotalLength();
return totLength + " " + totLength; })
.attr("stroke-dashoffset", function(d) { var totLength = d3.select(this).node().getTotalLength();
return totLength; })
.transition()
.delay(function(d,i) { return segmentDuration*i; })
.duration(segmentDuration)
.ease("linear")
.attr('stroke-dashoffset',0);
};
this.enterData = function() {
this.path.call(this.pathEnterData);
};
this.enterTransition = function() {
this.path.call(this.pathEnterTransition);
};
this.enter = function() {
this.enterData();
this.enterTransition();
};
this.exitTransition = function() {
this.path.exit().transition()
.duration(exitTransitionDuration)
.style("stroke-opacity", 0.0)
.style("fill-opacity", 0.0)
.remove();
};
this.update = function(newData) {
this.setData(newData);
this.exitTransition();
this.updateTransition();
setTimeout(function() {mThis.enter();},updateTransitionDuration);
};
this.updateTransition = function() {
this.bubbleCircles.transition()
.duration(updateTransitionDuration)
.attr("cx", function (d, i) { return x(d['date']); })
.call(mThis.setCircleY);
this.bubbleText.transition()
.duration(updateTransitionDuration)
.attr("x", function (d, i) { return x(d['date']) - (13.0/16)*bubbleNumberSize; })
.call(mThis.setTextY);
};
this.setData = function(points) {
var splitPoints = new Array(points.length-1);
for(var i=0; i<points.length-1; i++) {
splitPoints[i] = [points[i],points[i+1]];//{'start':points[i],'end':points[i+1]};
}
this.path = this.path.data(splitPoints,function(d,i){return d[1]['date']});
};