Почему не работает анимация прорисовки линии в Fabric.js 6?
При разработке на Next.js с библиотекой Fabric.js 6 вы можете столкнуться с ситуацией, когда анимация рисования линии (strokeDashOffset) выполняется в консоли, но на холсте линия появляется только целиком после завершения анимации. Это типичная проблема, связанная с особенностями рендеринга в Fabric.js 6. В этой статье мы подробно разберём причины и дадим рабочий код.
Основная причина: баг Fabric.js 6 с renderAll() в onChange
В версии 6 Fabric.js изменил внутреннюю механику вычисления свойств объекта во время анимации. Метод animate() вызывает onChange, но canvas.renderAll() внутри этого колбэка может не срабатывать корректно из-за того, что strokeDashOffset не помечен как свойство, требующее перерисовки. В результате холст обновляется только один раз - по завершении анимации.
Как исправить: принудительная установка dirty-флага
Решение - при каждом изменении strokeDashOffset вручную устанавливать флаг dirty = true для линии, а затем вызывать canvas.renderAll(). Это гарантирует, что Fabric.js перерисует объект на каждом кадре анимации.
Исправленная функция анимации
export function animateLineDraw(
canvas: Canvas,
line: Line,
duration: number = 1000
) {
const lineLength = Math.sqrt(
Math.pow(line.x1! - line.x2!, 2) + Math.pow(line.y1! - line.y2!, 2)
);
line.set({
strokeDashArray: [lineLength, lineLength],
strokeDashOffset: lineLength,
});
line.animate(
{ strokeDashOffset: 0 },
{
duration,
easing: util.ease.easeInOutQuad,
onChange: () => {
line.dirty = true; // <-- Ключевая строка
canvas.renderAll();
},
onComplete: () => {
line.set({
strokeDashArray: undefined,
strokeDashOffset: 0,
});
line.dirty = true;
canvas.renderAll();
},
}
);
}Дополнительные рекомендации для Next.js и Fabric.js 6
Убедитесь, что вы используете версию Fabric.js не ниже 6.0.0-beta7 - в ранних бет-версиях были серьёзные проблемы с анимацией. Также проверьте, что холст инициализируется после монтирования компонента (в useEffect с пустым массивом зависимостей).
Проверка инициализации canvas
Ваш код инициализации корректен, но добавьте вызов canvas.renderAll() после добавления линии и перед запуском анимации - это исключит пустой экран в первый момент.
function renderFabricCanvas() {
if (!fabricCanvasRef.current) return;
const line = createLine([300, 150, 400, 150]);
fabricCanvasRef.current.add(line);
fabricCanvasRef.current.renderAll(); // <-- принудительный рендер
animateLineDraw(fabricCanvasRef.current, line);
}Заключение
Проблема с анимацией линии в Fabric.js 6 почти всегда решается установкой line.dirty = true внутри колбэка onChange. Это заставляет движок перерисовывать объект на каждом шаге анимации. Также не забывайте вызывать canvas.renderAll() после добавления объектов на холст. Следуя этим простым шагам, вы получите плавную анимацию прорисовки линии.