2015-10-05 130 views
2

我正在使用D3製作一個使用可縮放行爲的時間聚焦圖。我遵循邁克·博斯托克的「邁向可重用圖表」文章中規定的模式,此外,還試圖使圖表反應靈敏。響應D3縮放行爲

可重複使用的圖表模式允許我簡單地在setInterval中調用我的圖表來處理響應。某些值(如寬度)會在每次調用時更新,其他值則封裝在閉包中,並僅在初始圖表創建時進行設置。需要潛在更新每個呼叫的值之一是比例範圍。

此外,根據https://github.com/mbostock/d3/wiki/Zoom-Behavior,修改由縮放行爲自動調整的比例的域或範圍時,需要(重新)指定縮放行爲的比例(此外,縮放行爲的比例和轉換值將被重置)。

但是,下面是結果我得到respecifying規模,每當我修改規模的範圍縮放行爲(也與最新的大規模更新縮放和平移值):

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); 
 
\t    var gEnter = svgEnter.append('g'); 
 
\t    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); 
 

 
      \t \t var rectItem = g.selectAll('rect.item').data(function(d) { 
 
         return d; 
 
        }); 
 
      \t \t rectItem.enter().append('rect').attr('class', 'item').style('fill', '#00F'); 
 
\t \t \t \t \t 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() { 
 
    \t selection.call(myTest); 
 
\t }; 
 
}(), 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>

我可以試圖通過規模最小respecify變焦性能非常接近。下面的工作,直到我調整窗口的大小,然後將變焦重點不是用鼠標排隊了:

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; 
 
      \t 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); 
 
\t    var gEnter = svgEnter.append('g'); 
 
\t    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); 
 

 
      \t \t var rectItem = g.selectAll('rect.item').data(function(d) { 
 
         return d; 
 
        }); 
 
      \t \t rectItem.enter().append('rect').attr('class', 'item').style('fill', '#00F'); 
 
\t \t \t \t \t 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() { 
 
    \t selection.call(myTest); 
 
\t }; 
 
}(), 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>

如何在響應使用縮放行爲和可重用的方式?

回答

3

我解決了縮放焦點沒有與調整大小鼠標排列的問題,只有在檢測到寬度變化後纔將縮放比例指定爲縮放行爲。但是,新寬度仍然存在問題,導致在調整大小時出現錯誤的翻譯。我找到了答案,在d3 Preserve scale/translate after resetting range,這使我的解決方案:

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() { 
 
    \t 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>