timer.restart()
не так полезен, как вы думаете. Из документов :
таймер . перезапуск ( обратный вызов [, задержка [, время ]])
Перезапустите таймер с указанным обратным вызовом и дополнительными задержкой и временем. Это эквивалентно остановке этого таймера и созданию нового таймера с указанными аргументами, хотя этот таймер сохраняет первоначальный приоритет вызова.
Так что это не сделает работу за вас. Он просто избавляет вас от создания нового таймера и (в случае нескольких таймеров) сохраняет свой приоритет.
Также, как видно из определения функции, параметр callback
является обязательным. Вот почему вы получаете TypeError: callback is not a function
в консоли.
По сути, вы должны преобразовать свою анонимную функцию обратного вызова в именованную функцию и передать ее как конструктору, так и методу restart
. Но если вы попытаетесь это сделать, вы увидите, что перезагрузка означает перезагрузку: она начинается с начала.
Итак, вы не можете рассчитывать на elapsed
, чтобы рассчитать положение вашей анимации, вам нужно посчитать время самостоятельно. Установите время запуска непосредственно перед созданием таймера, используя d3.now()
минус время, в течение которого анимация уже запущена (т. Е. 0 при первом вызове).
var totalElapsedTime = 0;
var startTime = d3.now() - totalElapsedTime;
var t = d3.timer(myCallback);
Затем внутри обратного вызова вычислите прошедшее время:
var elapsedTime = d3.now() - startTime;
// This is how d3.js calculates `elapsed`.
// The actual code is more complicated but the result is the same.
Запишите прошедшее время в обработчике события click
кнопки stop
:
on("click",function(){
totalElapsedTime = d3.now() - startTime;
ti.stop();
});
Обновление startTime
в обработчике событий click
кнопки restart
:
.on("click",function(){
startTime = d3.now() - totalElapsedTime;
ti.restart(myCallback);
});
И все готово.
Для записи, реальная функциональность паузы / возобновления была предложена на GitHub , но была отклонена. Другой разработчик разработал проект для его реализации на случай, если вы заинтересованы.
Примечание : в приведенном ниже фрагменте кода я немного упростил код и уменьшил размер холста, чтобы было проще отслеживать анимацию в окне фрагмента.
var width = 300,
height = 150;
var canvas = d3.select("body")
.append("canvas")
.attr("width", width)
.attr("height", height);
var context = canvas.node().getContext("2d");
d3.select("body")
.append("button")
.html("stop")
.on("click", function() {
totalElapsedTime = d3.now() - startTime;
ti.stop();
});
d3.select("body")
.append("button")
.html("restart")
.on("click", function() {
startTime = d3.now() - totalElapsedTime;
ti.restart(myCallback);
});
var startTime = d3.now();
var totalElapsedTime = 0;
var ti = d3.timer(myCallback);
function myCallback() {
var elapsedTime = d3.now() - startTime;
context.clearRect(0, 0, width, height);
context.fillStyle = "red";
var t = Math.min(1, elapsedTime / 10000)
context.fillRect( width * t, height * t, 10, 10);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>