Коллбеки onProgress и onComplete

В Chart.js система анимаций построена вокруг управляемого цикла перерисовки, в котором каждый рендер кадра проходит через этапы вычисления промежуточных значений, применения easing-функций и обновления canvas. В рамках этого процесса предусмотрены коллбеки, позволяющие внедряться в жизненный цикл анимации — ключевыми из них являются onProgress и onComplete.

Эти функции относятся к объекту конфигурации options.animation и выполняются в контексте конкретной анимации графика. Они позволяют отслеживать ход выполнения анимации и реагировать на её завершение, не вмешиваясь напрямую в механизм отрисовки.


Каждая анимация в Chart.js представляет собой последовательность кадров, где:

  • задаётся общее количество шагов (frames / duration),
  • вычисляется текущий прогресс,
  • применяется easing-функция,
  • пересчитываются значения элементов графика,
  • выполняется отрисовка canvas.

На каждом шаге система может вызывать пользовательские коллбеки.


Коллбек onProgress

onProgress вызывается на каждом шаге анимации, то есть многократно в процессе её выполнения. Он предоставляет доступ к текущему состоянию анимации и позволяет отслеживать прогресс в реальном времени.

Сигнатура контекста

В современных версиях Chart.js (v3/v4) callback получает объект состояния:

onProgress: (animation) => {}

Объект animation содержит информацию о текущем состоянии:

  • animation.currentStep — текущий шаг анимации
  • animation.numSteps — общее количество шагов
  • animation.chart — ссылка на экземпляр графика
  • animation.initial — признак начального состояния
  • animation.easing — используемая easing-функция

Пример использования onProgress

const config = {
  type: 'line',
  data: {
    labels: ['A', 'B', 'C', 'D'],
    datasets: [{
      label: 'Продажи',
      data: [10, 25, 15, 40]
    }]
  },
  options: {
    animation: {
      duration: 2000,
      easing: 'easeOutQuart',

      onProgress: (animation) => {
        const progress = animation.currentStep / animation.numSteps;

        const chart = animation.chart;
        chart.options.plugins.title = {
          display: true,
          text: `Прогресс анимации: ${(progress * 100).toFixed(0)}%`
        };
      }
    }
  }
};

В данном случае каждый кадр анимации изменяет состояние заголовка графика в зависимости от прогресса. Это демонстрирует, что onProgress может использоваться для синхронизации интерфейса с отрисовкой графика.


Особенности поведения onProgress

Повторяющийся характер вызова накладывает ограничения:

  • выполнение должно быть максимально лёгким,
  • тяжёлые вычисления приводят к падению FPS,
  • прямое изменение данных графика внутри callback требует осторожности,
  • любые изменения конфигурации могут вызвать дополнительную перерисовку.

Коллбек onComplete

onComplete вызывается один раз после завершения всей анимации. Он срабатывает, когда currentStep достигает numSteps, и все элементы графика завершили переход в конечное состояние.

Сигнатура

onComplete: (animation) => {}

Объект animation аналогичен используемому в onProgress, но в момент вызова анимация уже завершена.


Пример использования onComplete

const config = {
  type: 'bar',
  data: {
    labels: ['Q1', 'Q2', 'Q3'],
    datasets: [{
      label: 'Доход',
      data: [30, 50, 80]
    }]
  },
  options: {
    animation: {
      duration: 1500,

      onComplete: (animation) => {
        const chart = animation.chart;

        chart.options.plugins.legend.labels.color = 'black';
        chart.update();
      }
    }
  }
};

Здесь после завершения анимации изменяется стиль легенды и выполняется обновление графика.


Различие onProgress и onComplete

Поведение обоих коллбеков определяется моментом их вызова внутри анимационного цикла:

Коллбек Момент вызова Частота Назначение
onProgress каждый кадр анимации многократно отслеживание состояния
onComplete завершение анимации один раз финализация состояния

Контекст исполнения и доступ к chart

Оба коллбека получают объект, содержащий ссылку на экземпляр графика:

animation.chart

Через него доступно:

  • обновление данных (chart.data)
  • изменение опций (chart.options)
  • перерисовка (chart.update())
  • доступ к плагинам

Использование этой ссылки позволяет синхронизировать анимацию с внешними событиями интерфейса или логикой приложения.


Пример синхронизации с внешним состоянием

let loading = true;

const config = {
  type: 'line',
  data: {
    labels: ['Jan', 'Feb', 'Mar'],
    datasets: [{
      label: 'Трафик',
      data: [120, 90, 140]
    }]
  },
  options: {
    animation: {
      duration: 3000,

      onProgress: (animation) => {
        loading = true;
      },

      onComplete: (animation) => {
        loading = false;

        const chart = animation.chart;
        chart.data.datasets[0].borderWidth = 3;
        chart.update();
      }
    }
  }
};

В данном сценарии состояние загрузки привязывается к жизненному циклу анимации, а финальная стилизация применяется только после её завершения.


Влияние update() внутри коллбеков

Вызов chart.update() внутри onProgress или onComplete может приводить к повторному запуску анимации, если не учитывать параметры обновления. В Chart.js предусмотрены режимы обновления:

  • 'none' — без анимации
  • 'active' — частичное обновление
  • 'resize' — перерасчёт размеров
  • 'normal' — стандартное обновление

Пример безопасного обновления после завершения:

onComplete: (animation) => {
  animation.chart.update('none');
}

Практика оптимизации onProgress

Для снижения нагрузки применяются следующие подходы:

  • минимизация логики внутри callback
  • кэширование вычислений вне цикла анимации
  • использование локальных переменных вместо обращения к глубоким свойствам
  • отказ от частых вызовов update() внутри onProgress

Работа с несколькими анимациями

В сложных графиках с несколькими datasets каждая анимация может иметь свой жизненный цикл. В таких случаях onProgress и onComplete отражают состояние всей анимации графика, а не отдельных элементов.

options: {
  animation: {
    onProgress: (animation) => {
      const { numSteps, currentStep } = animation;
    },

    onComplete: (animation) => {
      const chart = animation.chart;
    }
  }
}

Поведение при отключённой анимации

Если параметр:

animation: false

то:

  • onProgress не вызывается,
  • onComplete не вызывается,
  • график отрисовывается мгновенно в финальном состоянии.

Взаимодействие с плагинами Chart.js

Коллбеки анимации часто используются совместно с плагинами, например:

  • кастомные подписи значений,
  • динамическая подстройка осей,
  • визуальные эффекты поверх canvas.

Плагины могут использовать данные анимации, переданные через animation.chart и синхронизировать собственные рендеры с прогрессом анимации.