我有一个带有count和date对象的对象数组。使用它们在时间尺度上创建一系列rects。效果很好。但是我想使用jQuery UI中的滑块来允许用户将结果缩小到整个范围的一部分,并更好地查看更精细的细节。但是我无法弄清楚如何从我的矩形选择中动态添加和删除数据点。这是代码。有问题的部分位于滑块幻灯片事件处理程序的最底部。我非常感谢有关如何正确管理数据的任何帮助。
var data=env.client.data;
var selected=env.client.selected;
var max=_.max(data,function(element){
return(element.count);
}).count;
var height=250;
var width=960;
var padding={
bottom:25,
left:30,
right:10,
top:10
};
var barwidth=(width-(padding.left+padding.right))/data.length;
var chart=d3.select('#chart')
.html('')
.append('svg')
.attr('height',height)
.attr('width',width);
var scale={};
scale.x=d3.time
.scale
.utc()
.domain([d3.first(data).date,d3.last(data).date])
.range([padding.left,width-padding.right]);
scale.yy=d3.scale
.linear()
.domain([0,max||1])
.range([height-padding.bottom,padding.top]);
scale.yh=d3.scale
.linear()
.domain([0,max||1])
.range([0,height-(padding.bottom+padding.top)]);
var axis={};
axis.x=d3.svg
.axis()
.scale(scale.x)
.orient('bottom');
axis.y=d3.svg
.axis()
.scale(scale.yy)
.orient('left')
.ticks(12);
if(max<12) axis.y.ticks(max);
var xa=chart.append('g')
.attr('class','xAxis')
.attr('transform','translate(0,'+(height-padding.bottom)+')')
.call(axis.x);
var ya=chart.append('g')
.attr('class','yAxis')
.attr('transform','translate('+(padding.left)+',0)')
.call(axis.y);
var rects=chart.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x',function(d){
return(scale.x(d.date));
})
.attr('y',function(d){
return(scale.yy(d.count));
})
.attr('height',function(d){
return(scale.yh(d.count));
})
.attr('fill',function(d){
return(d3.hsl(120-(120*(d.count/50)),1,0.1));
})
.attr('width',barwidth)
.attr('title',function(d){
return(d.tooltip);
})
.on('mouseover',function(d){
d3.select(this)
.attr('fill',d3.hsl(120-(120*(d.count/50)),1,0.5));
})
.on('mouseout',function(d){
d3.select(this)
.attr('fill',d3.hsl(120-(120*(d.count/50)),1,0.1));
})
.on('click',function(d){
var selected=moment(d.date.getTime()).utc();
env.client.range.selected=selected;
$('#client-datetime').val(selected.format('YYYY MMM DD, HH:mm'));
_.publish('client date changed');
});
var be=d3.first(data).date.getTime();
var ee=d3.last(data).date.getTime();
$('#slider').slider({
range:true,
min:be,
max:ee,
values:[be,ee],
slide:function(event,ui){
var bd=new Date(ui.values[0]);
var ed=new Date(ui.values[1]);
var subdata=_.filter(data,function(element){
return((element.date>=bd)&&(element.date<=ed));
});
var barwidth=(width-(padding.left+padding.right))/subdata.length;
scale.x.domain([bd,ed]);
xa.call(axis.x);
rects.data(subdata)
.remove();
rects.enter()
.append('rect')
.attr('x',function(d){
return(scale.x(d.date))
})
.attr('width',barwidth);
}
});
答案 0 :(得分:2)
据我所知,你走在正确的轨道上。
您获得subdata
,然后将其应用于
rects.data(subdata)
.remove();// this is wrong!!
我不确定你为什么要调用remove()
,但这实际上是删除了子数据中的所有DOM元素。这应该被拿出来。
接下来,(我很确定)您需要将rects重新分配给新绑定。即。
rects = rects.data(subdata);
接下来,您会附加所有enter()
个字词。但是你错过了一些设置('y','fill'等属性)。但是,您还需要更新未添加或从集合中删除的所有子数据成员。所以它变成了:
rects.enter()
.append('rect')
.attr('y',function(d) {
return(scale.yy(d.count));
})
.attr('height',function(d){
return(scale.yh(d.count));
})
.attr('fill',function(d){
return(d3.hsl(120-(120*(d.count/50)),1,0.1));
});
rects// This happens for all updated AND entering rects
.attr('x',function(d){
return(scale.x(d.date))
})
.attr('width',barwidth);
最后,您需要删除不再属于子数据的那些:
rects.exit().remove();
这个逻辑很像你在init脚本中的更高级别(除了仅在enter()
'集合上运行的init版本)。所以你应该把它全部转移到一个函数中:
updateChart(newData) {
rects = rects.data(subdata);
rects.enter()
// etc....
rects.remove()
}
并在初始时和正在应用新子数据时调用此函数。