Вы должны использовать requestAnimationFrame
для анимации, чтобы результаты рендеринга отображались синхронно с аппаратным обновлением дисплея.
setTimeout
очень неточно, и ваша функция со временем отстает.Если вы используете requestAnimationFrame
, вы можете использовать первый аргумент (время в мс) для точного определения времени.
ctx.save
и ctx.restore
могут быть очень дорогими вызовами, и их следует избегать, если вы можете.Поскольку вы только восстанавливаете преобразование, вы можете установить его вручную при необходимости с помощью ctx.setTransform()
Нет необходимости перезапускать анимацию, просто дайте ей повториться.
Пример переписывает ваш код с приведенным вышеИмеются в виду и некоторые другие изменения.Для получения дополнительной информации см. Комментарии к коду.
// Define constants and query DOM outside animation functions
const canvas = document.getElementById("animCanvas");
const ctx = canvas.getContext("2d");
Math.PI2 = Math.PI * 2;
var startTime;
restartAnimate();
function restartAnimate() {
if (startTime === undefined) {
requestAnimationFrame(runAnimation);
} else {
startTime = 0; // next frame animation we have restarted
}
// setTimeout(restartAnimate(),1000); // No need to restart as angle is cyclic.
}
function runAnimation(time) {
if (!startTime) { startTime = time }
const currentTime = time - startTime;
ctx.setTransform(1,0,0,1,0,0); // resets transform, better than using save and restore
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); // avoid magic numbers
//ctx.save(); // not needed
ctx.setTransform(1,0,0,1,150, 75); // last two values set the origin
// and is the point we rotate around
ctx.strokeStyle = "#99ebff";
ctx.lineWidth = 10;
ctx.beginPath();
ctx.arc(0, 0, 40, 0, Math.PI2); // rendering at the origin
ctx.stroke();
//ctx.restore(); // not needed
//ctx.save(); // not needed
ctx.fillStyle = "#000000";
//ctx.translate(150,75); // working from origin so don't need to translate
ctx.rotate(Math.PI2 * currentTime / 1000);
//ctx.translate(-150,-75); // working from origin so don't need to translate
ctx.beginPath();
ctx.arc(36.5, 0 ,13, 0, Math.PI2);
ctx.fill();
//ctx.restore(); not needed
requestAnimationFrame(runAnimation);
}
<canvas id="animCanvas"></canvas>