Javascript d3.js时间序列无限滚动
我正在制作一个时间序列折线图,让用户可以从现在开始向后滚动。我可以找到关于实时d3.js图表的教程,可以找到关于缩放和平移的教程,还可以找到关于使用外部数据源的教程。我很难把这些知识整合起来 以下是我正在寻找的行为:Javascript d3.js时间序列无限滚动,javascript,d3.js,Javascript,D3.js,我正在制作一个时间序列折线图,让用户可以从现在开始向后滚动。我可以找到关于实时d3.js图表的教程,可以找到关于缩放和平移的教程,还可以找到关于使用外部数据源的教程。我很难把这些知识整合起来 以下是我正在寻找的行为: 图表可以在时间上向后平移(意味着线、数据点和轴随着鼠标或手指的拖动而移动) 平移应仅影响x轴,不应进行缩放 当用户平移图表时,会加载更多的数据,从而提供无限滚动的体验 我计划缓冲至少一个额外的“页面”数据,让用户滚动到其中(这部分已经解决了) 我认为我不需要转换,因为图表的平移已
- 图表可以在时间上向后平移(意味着线、数据点和轴随着鼠标或手指的拖动而移动)
- 平移应仅影响x轴,不应进行缩放
- 当用户平移图表时,会加载更多的数据,从而提供无限滚动的体验
- 我计划缓冲至少一个额外的“页面”数据,让用户滚动到其中(这部分已经解决了)
- 我认为我不需要转换,因为图表的平移已经可以顺利地转换它了
// set up a zoom handler only for panning
// by limiting the scaleExtent
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 1])
.on("zoom", pan);
var loadedPage = 1; // begin with one page of data loaded
var nextPage = 2; // next page will be page 2
var panX = 0;
function pan()
{
if (d3.event)
{
panX = d3.event ? d3.event.translate[0] : 0;
// is there a better way to determine when
// to load the next page?
nextPage = panX / (width + margin.left + margin.right) + 2;
nextPage = Math.floor(nextPage);
// if we haven't loaded in the next page's data
// load it in so that the user can scroll into it
if (nextPage > loadedPage) {
console.log("Load a new page");
loadedPage += 1;
// load more data
Chart.query( /*params will be here*/ ).then(
function(response) {
// append the new data onto the front of the array
data = data.concat(response);
console.log(data.length);
// I need to add the new data into the line chart
// but how do I make that work with the pan
// logic from zoom?
}
);
}
// is this where I update the axes and scroll the chart?
// What's the best way to do that?
}
}
在这段代码中,我可以知道何时从服务器提取更多数据,但我不确定如何将数据插入到图表中,以使用平移偏移量。我是使用transform translate,还是可以更新直线路径的d值
欢迎提出任何建议。。。此外,如果有人知道任何演示已经通过时间序列数据显示了无限平移,那将非常感谢。这太晚了,但回答只是为了万一有人需要再次。我已经为我的散点图准备好了大部分代码,所以上传了。希望对你有帮助。这段代码是在我学习这个特性时创建的。所以使用前请检查 注: 使用缩放行为实现D3js平移, 使用scaleExtent禁用缩放, Y平移限制。 达到x极限时加载的数据。 请检查一下电话号码
//代码在这里
window.chartBuilder={};
(功能(ns){
函数getMargin(){
var保证金={
前20名,
右:15,
底数:60,
左:60
};
变量宽度=960-margin.left-margin.right;
变量高度=500-margin.top-margin.bottom;
返回{
保证金:保证金,
宽度:宽度,
高度:高度
};
}
函数getData(){
风险值数据=[
[5, 3],
[10, 17],
[15, 4],
[2, 8]
];
返回数据;
}
//功能定义范围(数据、宽度、高度){
//var x=d3.scale.linear()
//.domain([0,d3.max(数据,函数(d)){
//返回d[0];
// })])
//.范围([0,宽度]);
//
//变量y=d3.scale.linear()
//.domain([0,d3.max(数据,函数(d)){
//返回d[1];
// })])
//.范围([高度,0]);
//返回{x:x,y:y};
//}
函数定义范围(数据、域、范围){
var domainArr=域;
如果(!domain | | domain.length==0){
domainArr=[0,d3.max(数据,函数(d)){
返回d[1];
})];
}
变量y=d3.scale.linear()
.domain(domainArr)
.射程(射程);
返回y;
}
函数定义比例(数据、域、范围){
var domainArr=域;
如果(!domain | | domain.length==0){
domainArr=[d3.min(数据,函数(d)){
返回d[0];
}),d3.max(数据,函数(d){
返回d[0];
})];
}
var x=d3.scale.linear()
.domain(domainArr)
.射程(射程);
返回x;
}
函数getSvg(宽度、边距、高度){
变量图表=d3。选择('主体')
.append('svg:svg')
.attr('width',width+margin.right+margin.left)
.attr('height',height+margin.top+margin.bottom)
.attr(“类别”、“图表”);
收益表;
}
函数getContainerGroup(图表、边距、宽度、高度){
var main=chart.append('g')
.attr('transform','translate('+margin.left+','+margin.top+'))
.attr('width',width)
.attr('height',height)
.attr('class','main');
回水总管;
}
功能渲染x轴(x、主视图、高度){
var xAxis=d3.svg.axis()
.比例(x)
.orient(“底部”);
var xAxisElement=main.select('.x.axis');
if(xAxisElement.empty()){
xAxisElement=main.append('g')
.attr('transform','translate(0',+height+'))
.attr('class','x轴')
}
调用(xAxis);
返回xAxis;
}
功能渲染轴(y,主){
var yAxis=d3.svg.axis()
.比例(y)
.东方(左);
var yAxisElement=main.select('.y.axis');
if(yAxisElement.empty()){
yAxisElement=main.append('g')
.attr('transform','translate(0,0'))
.attr('class','y轴');
}
yAxis元素调用(yAxis);
返回yAxis;
}
功能渲染器散射图(主、数据、比例){
var g=main.append(“svg:g”);
var divTooltip=d3.select('.tooltip1');
if(divTooltip.empty()){
divTooltip=d3。选择('body')。追加('div'))
.attr('class','tooltip1')
.style('opacity',0);
}
g、 选择全部(“散点”)
.数据(数据、功能(d、i){
返回i;
})
.enter().append(“svg:circle”)
.attr(“cx”,函数(d,i){
回归标度.x(d[0]);
})
.attr(“cy”,函数(d){
回归尺度y(d[1]);
})
.on('点击')功能(d){
//log(d.toString());
})
.attr(“r”,8);
}
函数addZoomRect(主、缩放、缩放){
var zoomRect=main.append('rect')
.attr('width',function(){
返回scales.x(d3.max(scales.x.domain());
})
.attr('height',function(){
返回scales.y(d3.min(scales.y.domain());
})
.attr('x',0)
.attr('y',0)
.attr('填充','透明')
.attr('stroke','red');
如果(缩放){
zoomRect.call(缩放);
}
返回zoomRect;
}
功能限制规划(缩放){
var zoomTranslate=this.translate();
this.translate([zoomTranslate[0],0]);
}
功能addXScrollEndEvent(比例,
var pan = d3.behavior.zoom()
.x(x_scale)
.scale(scale)
.size([width, height])
.scaleExtent([scale, scale])
.on('zoom', function(e) { ... });
// Apply the behavior
viz.call(pan);
// Now that we've scaled in, find the farthest point that
// we'll allow users to pan forward in time (to the right)
max_translate_x = width - x_scale(new Date(now));
viz.call(pan.translate([max_translate_x, 0]).event);
...
.scaleExtent([scale, scale])
.on('zoom', function(e) {
var current_domain = x_scale.domain(),
current_max = current_domain[1].getTime();
// If we go past the max (i.e. now), reset translate to the max
if (current_max > now)
pan.translate([max_translate_x, 0]);
// Update the data & points once user hits the point where current data ends
if (pan.translate()[0] > min_translate_x) {
updateData();
addNewPoints();
}
// Redraw any components defined by the x axis
x_axis.call(x_axis_generator);
circles.attr('cx', function(d) {
return x_scale(new Date(d.registered));
});
});