2017-08-12 21 views
1

有時您需要在轉換「開始」和「結束」事件回調中進行計算密集型工作(轉換需要),這可能需要很長時間才能完成,即轉換開始時(或下一個鏈接轉換開始時爲「結束「事件),時間已經超過了轉換開始時間,導致轉換跳轉。如何適應d3.transition回調中的長計算時間?

這個問題可以在下面看到。第一個和第二個動畫過渡從其開始值直接跳到半完成。


<!DOCTYPE html> 
 
<meta charset="utf-8"> 
 
<body> 
 
<script src="//d3js.org/d3-selection.v1.min.js"></script> 
 
<!-- This script is d3-timer.min.js with https://github.com/d3/d3-timer/pull/28 that fixes https://github.com/d3/d3-timer/issues/27 --> 
 
<script>!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})}(this,function(t){"use strict";function n(){return h||(x(e),h=v.now()+y)}function e(){h=0}function o(){this._call=this._time=this._next=null}function i(t,n,e){var i=new o;return i.restart(t,n,e),i}function r(){n(),++_;for(var t,e=f;e;)(t=h-e._time)>=0&&e._call.call(null,t),e=e._next;--_}function u(){h=(d=v.now())+y,_=m=0;try{r()}finally{_=0,c(),h=0}}function l(){var t=v.now(),n=t-d;n>w&&(y-=n,d=t)}function c(){for(var t,n,e=f,o=1/0;e;)e._call?(o>e._time&&(o=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:f=n);s=t,a(o)}function a(t){_||(m&&(m=clearTimeout(m)),t-h>24?(t<1/0&&(m=setTimeout(u,t-v.now()-y)),p&&(p=clearInterval(p))):(p||(d=v.now(),p=setInterval(l,w)),_=1,x(u)))}var f,s,_=0,m=0,p=0,w=1e3,d=0,h=0,y=0,v="object"==typeof performance&&performance.now?performance:Date,x="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};o.prototype=i.prototype={constructor:o,restart:function(t,e,o){if("function"!=typeof t)throw new TypeError("callback is not a function");o=(null==o?n():+o)+(null==e?0:+e),this._next||s===this||(s?s._next=this:f=this,s=this),this._call=t,this._time=o,a()},stop:function(){this._call&&(this._call=null,this._time=1/0,a())}};t.now=n,t.timer=i,t.timerFlush=r,t.timeout=function(t,n,e){var i=new o;return n=null==n?0:+n,i.restart(function(e){i.stop(),t(e+n)},n,e),i},t.interval=function(t,e,i){var r=new o,u=e;return null==e?(r.restart(t,e,i),r):(e=+e,i=null==i?n():+i,r.restart(function n(o){o+=u,r.restart(n,u+=e,i),t(o)},e,i),r)},Object.defineProperty(t,"__esModule",{value:!0})});</script> 
 
<script src="//d3js.org/d3-dispatch.v1.min.js"></script> 
 
<script src="//d3js.org/d3-interpolate.v1.min.js"></script> 
 
<script src="//d3js.org/d3-color.v1.min.js"></script> 
 
<script src="//d3js.org/d3-ease.v1.min.js"></script> 
 
<script src="//d3js.org/d3-transition.v1.min.js"></script> 
 
<script src="//d3js.org/d3-scale.v1.min.js"></script> 
 
<script src="//d3js.org/d3-zoom.v1.min.js"></script> 
 
    <div style="text-align: center;"></div> 
 
    <script> 
 

 
var start = Date.now(); 
 

 
function elapsed() { 
 
    return Date.now() - start; 
 
} 
 

 
function waste(time) { 
 
    var t0 = Date.now(); 
 
    while (Date.now() - t0 < time) 
 
     ; 
 
} 
 

 
var svg = d3.select("div").append("svg") 
 
    .attr("width", 800) 
 
    .attr("height", 500); 
 
var g = svg.append("g"); 
 

 
var start1Waste = 2000; 
 
var end1Waste = 2000; 
 
var start2Waste = 0; 
 
var end2Waste = 0; 
 

 
g.selectAll("rect") 
 
    .data([10, 100, 200]) 
 
    .enter() 
 
    .append("rect") 
 
    .attr("width", d => d) 
 
    .attr("height", d => d) 
 
    .attr("fill", "none") 
 
    .attr("stroke", "black") 
 

 
var rect = g.append("rect") 
 
    .attr("width", 10) 
 
    .attr("height", 10) 
 
    .attr("fill", "#d62728") 
 
    .transition() 
 
    .delay(2000) 
 
    .duration(4000) 
 
    .ease(d3.easeLinear) 
 
    .attr("width", 100) 
 
    .attr("height", 100) 
 
    .on("start", function() { 
 
     console.log('Start event 1', elapsed()/1000); 
 
     waste(start1Waste); 
 
     console.log('Start event 1 returning', elapsed()/1000); 
 
    }) 
 
    .on("end", function() { 
 
     console.log('End event 1', elapsed()/1000); 
 
     waste(end1Waste); 
 
     console.log('End event 1 returning', elapsed()/1000); 
 
    }) 
 
    .transition() 
 
    .attr("width", 200) 
 
    .attr("height", 200) 
 
    .attr("fill", "#1f77b4") 
 
    .on("start", function() { 
 
     console.log('Start event 2', elapsed()/1000); 
 
     waste(start2Waste); 
 
     console.log('Start event 2 returning', elapsed()/1000); 
 
    }) 
 
    .on("end", function() { 
 
     console.log('End event 2', elapsed()/1000); 
 
     waste(end2Waste); 
 
     console.log('End event 2 returning', elapsed()/1000); 
 
    }) 
 

 
</script>


注:一個bug in d3-timerfixed, 但尚未發佈寫這篇文章的時候,要求這個例子中使用非官D3定時器.min.js。

+0

一)不要在一個網絡工作者的計算密集型任務。 b)使用SMIL代替動畫,瀏覽器將自動處理所有時間並解決任何滯後問題。 –

+0

@RobertLongson a)我自己想過一個web工作者,但是在這個例子中,如果轉換需要計算結果,那麼如何使用它呢? b)不會使用SMIL意味着放棄使用d3.transition?或者他們可以合併? – magjac

+0

@RobertLongson我已經闡明瞭計算需要通過 – magjac

回答

0
  • 對於「開始」事件,您不能。在之前進行計算密集型工作創建轉換時,或者如果這不可行,則在單獨的前轉換中,此轉換爲chained

  • 對於「結束」事件,您可以向第二個轉換添加延遲,該延遲等於或大於第一個轉換的結束事件回調的計算時間。如果你想讓這個客戶端比你自己的客戶端更慢,那麼延遲時間會更長。

<!DOCTYPE html> 
 
<meta charset="utf-8"> 
 
<body> 
 
<script src="//d3js.org/d3-selection.v1.min.js"></script> 
 
<!-- This script is d3-timer.min.js with https://github.com/d3/d3-timer/pull/28 that fixes https://github.com/d3/d3-timer/issues/27 --> 
 
<script>!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})}(this,function(t){"use strict";function n(){return h||(x(e),h=v.now()+y)}function e(){h=0}function o(){this._call=this._time=this._next=null}function i(t,n,e){var i=new o;return i.restart(t,n,e),i}function r(){n(),++_;for(var t,e=f;e;)(t=h-e._time)>=0&&e._call.call(null,t),e=e._next;--_}function u(){h=(d=v.now())+y,_=m=0;try{r()}finally{_=0,c(),h=0}}function l(){var t=v.now(),n=t-d;n>w&&(y-=n,d=t)}function c(){for(var t,n,e=f,o=1/0;e;)e._call?(o>e._time&&(o=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:f=n);s=t,a(o)}function a(t){_||(m&&(m=clearTimeout(m)),t-h>24?(t<1/0&&(m=setTimeout(u,t-v.now()-y)),p&&(p=clearInterval(p))):(p||(d=v.now(),p=setInterval(l,w)),_=1,x(u)))}var f,s,_=0,m=0,p=0,w=1e3,d=0,h=0,y=0,v="object"==typeof performance&&performance.now?performance:Date,x="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};o.prototype=i.prototype={constructor:o,restart:function(t,e,o){if("function"!=typeof t)throw new TypeError("callback is not a function");o=(null==o?n():+o)+(null==e?0:+e),this._next||s===this||(s?s._next=this:f=this,s=this),this._call=t,this._time=o,a()},stop:function(){this._call&&(this._call=null,this._time=1/0,a())}};t.now=n,t.timer=i,t.timerFlush=r,t.timeout=function(t,n,e){var i=new o;return n=null==n?0:+n,i.restart(function(e){i.stop(),t(e+n)},n,e),i},t.interval=function(t,e,i){var r=new o,u=e;return null==e?(r.restart(t,e,i),r):(e=+e,i=null==i?n():+i,r.restart(function n(o){o+=u,r.restart(n,u+=e,i),t(o)},e,i),r)},Object.defineProperty(t,"__esModule",{value:!0})});</script> 
 
<script src="//d3js.org/d3-dispatch.v1.min.js"></script> 
 
<script src="//d3js.org/d3-interpolate.v1.min.js"></script> 
 
<script src="//d3js.org/d3-color.v1.min.js"></script> 
 
<script src="//d3js.org/d3-ease.v1.min.js"></script> 
 
<script src="//d3js.org/d3-transition.v1.min.js"></script> 
 
<script src="//d3js.org/d3-scale.v1.min.js"></script> 
 
<script src="//d3js.org/d3-zoom.v1.min.js"></script> 
 
    <div style="text-align: center;"></div> 
 
    <script> 
 

 
var start = Date.now(); 
 

 
function elapsed() { 
 
    return Date.now() - start; 
 
} 
 

 
function waste(time) { 
 
    var t0 = Date.now(); 
 
    while (Date.now() - t0 < time) 
 
     ; 
 
} 
 

 
var svg = d3.select("div").append("svg") 
 
    .attr("width", 800) 
 
    .attr("height", 500); 
 
var g = svg.append("g"); 
 

 
var start1Waste = 0; // Can't compensate for wasted time at start 
 
var end1Waste = 2000; // Can be compensated with delay in next transition 
 
var start2Waste = 0; // Can't compensate for wasted time at start 
 
var end2Waste = 0; 
 

 

 
g.selectAll("rect") 
 
    .data([10, 100, 200]) 
 
    .enter() 
 
    .append("rect") 
 
    .attr("width", d => d) 
 
    .attr("height", d => d) 
 
    .attr("fill", "none") 
 
    .attr("stroke", "black") 
 
     
 
var rect = g.append("rect") 
 
    .attr("width", 10) 
 
    .attr("height", 10) 
 
    .attr("fill", "#d62728") 
 
    .transition() 
 
    .delay(2000) 
 
    .duration(4000) 
 
    .ease(d3.easeLinear) 
 
    .attr("width", 100) 
 
    .attr("height", 100) 
 
    .on("start", function() { 
 
     console.log('Start event 1', elapsed()/1000); 
 
     waste(start1Waste); 
 
     console.log('Start event 1 returning', elapsed()/1000); 
 
    }) 
 
    .on("end", function() { 
 
     console.log('End event 1', elapsed()/1000); 
 
     waste(end1Waste); 
 
     console.log('End event 1 returning', elapsed()/1000); 
 
    }) 
 
    .transition() 
 
    .delay(end1Waste) 
 
    .attr("width", 200) 
 
    .attr("height", 200) 
 
    .attr("fill", "#1f77b4") 
 
    .on("start", function() { 
 
     console.log('Start event 2', elapsed()/1000); 
 
     waste(start2Waste); 
 
     console.log('Start event 2 returning', elapsed()/1000); 
 
    }) 
 
    .on("end", function() { 
 
     console.log('End event 2', elapsed()/1000); 
 
     waste(end2Waste); 
 
     console.log('End event 2 returning', elapsed()/1000); 
 
    }) 
 

 
</script>

+0

這個問題的轉換我很感興趣看看是否有人有更好的解決方案。 – magjac