繁体   English   中英

响应式D3缩放行为

[英]Responsive D3 zoom behavior

我正在使用D3制作一个以时间为中心的图表,该图表利用了可缩放的行为。 我正在遵循Mike Bostock在“迈向可重用图表”一文中提出的模式,此外,还尝试使该图表具有响应性。

可重用的图表模式使我可以简单地在setInterval中调用图表以处理响应性。 有些值(例如width)在每次调用时都会更新,其他值则封装在一个闭包中,并且仅在初始图表创建时设置。 需要潜在更新每个调用的值之一是音阶的范围。

此外,根据https://github.com/mbostock/d3/wiki/Zoom-Behavior的说明 ,修改由缩放行为自动调整的缩放比例的域或范围需要(重新)指定缩放比例以适应缩放行为(此外,缩放行为的比例和平移值将被重置)。

但是,以下是我在每次修改比例尺范围时都将比例尺重新指定为缩放行为的结果(并使用最新比例尺和缩放值更新缩放比例):

http://jsfiddle.net/xf3fk8hu/

 function test(config) { var aspectRatio = 10 / 3; var margin = { top: 0, right: 0, bottom: 30, left: 0 }; var current = new Date(); var xScale = d3.time.scale().domain([d3.time.year.offset(current, -1), current]); var xAxis = d3.svg.axis().scale(xScale).ticks(5); var currentScale = 1; var currentTranslate = [0, 0]; var zoom = d3.behavior.zoom().x(xScale).on('zoom', function() { currentScale = d3.event.scale; currentTranslate = d3.event.translate; d3.select(this.parentNode.parentNode.parentNode).call(result); }); var result = function(selection) { selection.each(function(data) { var outerWidth = $(this).width(); var outerHeight = outerWidth / aspectRatio; var width = outerWidth - margin.left - margin.right; var height = outerHeight - margin.top - margin.bottom; xScale.range([0, width]); zoom.x(xScale).scale(currentScale).translate(currentTranslate); var svg = d3.select(this).selectAll('svg').data([data]); var svgEnter = svg.enter().append('svg'); svg.attr('width', outerWidth).attr('height', outerHeight); var gEnter = svgEnter.append('g'); var g = svg.select('g').attr('transform', 'translate(' + margin.left + ' ' + margin.top + ')'); gEnter.append('rect').attr('class', 'background').style('fill', '#F4F4F4').call(zoom); g.select('rect.background').attr('width', width).attr('height', height); var rectItem = g.selectAll('rect.item').data(function(d) { return d; }); rectItem.enter().append('rect').attr('class', 'item').style('fill', '#00F'); rectItem.attr('x', function(d) { return xScale(d); }).attr('width', xScale(d3.time.day.offset(xScale.invert(0), 7))).attr('height', height); gEnter.append('g'); g.select('g').attr('transform', 'translate(0 ' + height + ')').call(xAxis); }); }; return result; } setInterval(function() { var selection = d3.select('#main').datum(d3.range(5).map(function() { var current = new Date(); var mean = -d3.time.minute.range(current, d3.time.month.offset(current, 6)).length; var deviation = d3.time.minute.range(current, d3.time.month.offset(current, 1)).length; var random = d3.random.normal(mean, deviation); return function() { return d3.time.minute.offset(current, random()); }; }())); var myTest = test(); return function() { selection.call(myTest); }; }(), 1000 / 60); 
 <div id="main"></div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 

我可以通过尝试最小化重新指定缩放比例来达到非常接近的效果。 在我调整窗口大小之前,以下操作有效,然后缩放焦点不再与鼠标对齐:

http://jsfiddle.net/xf3fk8hu/1/

 function test(config) { var aspectRatio = 10 / 3; var margin = { top: 0, right: 0, bottom: 30, left: 0 }; var current = new Date(); var xScale = d3.time.scale().domain([d3.time.year.offset(current, -1), current]); var isZoomControllingScale = false; var xAxis = d3.svg.axis().scale(xScale).ticks(5); var currentScale = 1; var currentTranslate = [0, 0]; var zoom = d3.behavior.zoom().on('zoom', function() { currentScale = d3.event.scale; currentTranslate = d3.event.translate; d3.select(this.parentNode.parentNode.parentNode).call(result); }); var result = function(selection) { selection.each(function(data) { var outerWidth = $(this).width(); var outerHeight = outerWidth / aspectRatio; var width = outerWidth - margin.left - margin.right; var height = outerHeight - margin.top - margin.bottom; xScale.range([0, width]); if(!isZoomControllingScale) { isZoomControllingScale = true; zoom.x(xScale).scale(currentScale).translate(currentTranslate); } var svg = d3.select(this).selectAll('svg').data([data]); var svgEnter = svg.enter().append('svg'); svg.attr('width', outerWidth).attr('height', outerHeight); var gEnter = svgEnter.append('g'); var g = svg.select('g').attr('transform', 'translate(' + margin.left + ' ' + margin.top + ')'); gEnter.append('rect').attr('class', 'background').style('fill', '#F4F4F4').call(zoom); g.select('rect.background').attr('width', width).attr('height', height); var rectItem = g.selectAll('rect.item').data(function(d) { return d; }); rectItem.enter().append('rect').attr('class', 'item').style('fill', '#00F'); rectItem.attr('x', function(d) { return xScale(d); }).attr('width', xScale(d3.time.day.offset(xScale.invert(0), 7))).attr('height', height); gEnter.append('g'); g.select('g').attr('transform', 'translate(0 ' + height + ')').call(xAxis); }); }; return result; } setInterval(function() { var selection = d3.select('#main').datum(d3.range(5).map(function() { var current = new Date(); var mean = -d3.time.minute.range(current, d3.time.month.offset(current, 6)).length; var deviation = d3.time.minute.range(current, d3.time.month.offset(current, 1)).length; var random = d3.random.normal(mean, deviation); return function() { return d3.time.minute.offset(current, random()); }; }())); var myTest = test(); return function() { selection.call(myTest); }; }(), 1000 / 60); 
 <div id="main"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 

如何以响应和可重用的方式使用缩放行为?

通过仅在检测到宽度变化后才将缩放比例重新指定为缩放行为,解决了缩放后缩放焦点无法与鼠标对齐的问题。 但是,新宽度仍然存在问题,导致在调整大小期间发生错误的平移。 在重置范围后 ,我在d3保留比例/转换时找到了答案,这使我找到了解决方案:

http://jsfiddle.net/xf3fk8hu/5/

 function test(config) { var aspectRatio = 10 / 3; var margin = { top: 0, right: 0, bottom: 30, left: 0 }; var current = new Date(); var xScale = d3.time.scale(); var xAxis = d3.svg.axis().scale(xScale).ticks(5); var zoom = d3.behavior.zoom().x(xScale).on('zoom', function() { currentScale = d3.event.scale; currentTranslate = d3.event.translate; d3.select(this.parentNode.parentNode.parentNode).call(result); }); var currentScale = zoom.scale(); var currentTranslate = zoom.translate(); var oldWidth; var result = function(selection) { selection.each(function(data) { var outerWidth = $(this).width(); var outerHeight = outerWidth / aspectRatio; var width = outerWidth - margin.left - margin.right; var height = outerHeight - margin.top - margin.bottom; if(oldWidth !== width) { if(oldWidth === undefined) oldWidth = width; currentTranslate[0] *= width / oldWidth; xScale.domain([d3.time.year.offset(current, -1), current]).range([0, width]); zoom.x(xScale).scale(currentScale).translate(currentTranslate); } oldWidth = width; var svg = d3.select(this).selectAll('svg').data([data]); var svgEnter = svg.enter().append('svg'); svg.attr('width', outerWidth).attr('height', outerHeight); var gEnter = svgEnter.append('g'); var g = svg.select('g').attr('transform', 'translate(' + margin.left + ' ' + margin.top + ')'); gEnter.append('rect').attr('class', 'background').style('fill', '#F4F4F4').call(zoom); g.select('rect.background').attr('width', width).attr('height', height); var rectItem = g.selectAll('rect.item').data(function(d) { return d; }); rectItem.enter().append('rect').attr('class', 'item').style('fill', '#00F'); rectItem.attr('x', function(d) { return xScale(d); }).attr('width', xScale(d3.time.day.offset(xScale.invert(0), 7))).attr('height', height); gEnter.append('g'); g.select('g').attr('transform', 'translate(0 ' + height + ')').call(xAxis); }); }; return result; } setInterval(function() { var selection = d3.select('#main').datum(d3.range(5).map(function() { var current = new Date(); var mean = -d3.time.minute.range(current, d3.time.month.offset(current, 6)).length; var deviation = d3.time.minute.range(current, d3.time.month.offset(current, 1)).length; var random = d3.random.normal(mean, deviation); return function() { return d3.time.minute.offset(current, random()); }; }())); var myTest = test(); return function() { selection.call(myTest); }; }(), 1000 / 60); 
 <div id="main"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM