Передача опций в плагин

В системе Chart.js плагины являются расширяемым слоем, который получает доступ к жизненному циклу графика и его конфигурации. Механизм передачи опций в плагины основан на строгой иерархии конфигурации: глобальные настройки, настройки на уровне экземпляра графика и локальные параметры конкретного плагина.


Каждый плагин в Chart.js идентифицируется строковым ключом id. Именно этот идентификатор используется как ключ в объекте plugins внутри конфигурации графика.

Базовая структура выглядит следующим образом:

const config = {
  type: 'line',
  data: {
    labels: ['A', 'B', 'C'],
    datasets: [{
      data: [10, 20, 30]
    }]
  },
  options: {
    plugins: {
      myPlugin: {
        enabled: true,
        color: 'red'
      }
    }
  }
};

Здесь myPlugin — это id плагина. Все вложенные поля объекта становятся его локальными настройками.


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

Плагин получает доступ к конфигурации через объект context, который передаётся в его методы жизненного цикла (beforeInit, afterDatasetsDraw, beforeUpdate и т.д.).

const myPlugin = {
  id: 'myPlugin',

  beforeDraw(chart, args, options) {
    console.log(options);
  }
};

Параметр options уже содержит итоговую конфигурацию, собранную из нескольких источников.


Иерархия разрешения опций

В Chart.js действует приоритет:

  1. Локальные опции плагина в options.plugins.<pluginId>
  2. Глобальные настройки Chart.defaults.plugins.<pluginId>
  3. Значения по умолчанию, заданные самим плагином

Итоговое значение формируется путём глубокого объединения объектов.


Глобальные настройки плагина

Глобальные параметры задаются через Chart.defaults.plugins. Они применяются ко всем экземплярам графиков, если не переопределены локально.

import { Chart } from 'chart.js';

Chart.defaults.plugins.myPlugin = {
  enabled: false,
  color: 'blue'
};

Это позволяет централизованно управлять поведением плагина без необходимости повторной конфигурации.


Переопределение на уровне конкретного графика

Локальная конфигурация имеет более высокий приоритет и перекрывает глобальные значения.

const config = {
  type: 'bar',
  data: {
    labels: ['X', 'Y'],
    datasets: [{ data: [5, 15] }]
  },
  options: {
    plugins: {
      myPlugin: {
        enabled: true
      }
    }
  },
  plugins: [myPlugin]
};

В этом случае enabled будет true, даже если глобально он установлен в false.


Передача сложных структур данных

Опции плагина не ограничены простыми типами. Допускается передача вложенных объектов, массивов и функций.

options: {
  plugins: {
    myPlugin: {
      thresholds: {
        low: 10,
        high: 50
      },
      formatLabel(value) {
        return `Value: ${value}`;
      }
    }
  }
}

Внутри плагина такие структуры доступны без ограничений:

beforeUpdate(chart, args, options) {
  const low = options.thresholds.low;
  const label = options.formatLabel(42);
}

Контекст исполнения и привязка опций

Каждый вызов плагина получает контекст, содержащий:

  • ссылку на экземпляр графика
  • текущие вычисленные опции плагина
  • аргументы события жизненного цикла
beforeDraw(chart, args, options) {
  const { ctx, width, height } = chart;
  const pluginOptions = options;
}

Таким образом, плагин не обращается напрямую к chart.options.plugins, а работает с уже разрешённой конфигурацией.


Использование context для динамических опций

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

options: {
  plugins: {
    myPlugin: {
      color(context) {
        return context.chart.data.datasets.length > 1
          ? 'red'
          : 'green';
      }
    }
  }
}

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


Поведение при отсутствии опций

Если конфигурация плагина не задана, Chart.js передаёт пустой объект {} в качестве options. Это исключает необходимость проверок на undefined внутри плагина.

beforeInit(chart, args, options) {
  // options всегда существует
}

Слияние конфигураций (deep merge)

Опции не заменяются полностью, а объединяются рекурсивно. Это означает, что частичное переопределение не уничтожает остальные поля.

Chart.defaults.plugins.myPlugin = {
  style: {
    color: 'blue',
    size: 10
  }
};

Локально:

options: {
  plugins: {
    myPlugin: {
      style: {
        color: 'red'
      }
    }
  }
}

Результат:

{
  style: {
    color: 'red',
    size: 10
  }
}

Передача опций через регистрацию плагина

Плагин может быть зарегистрирован глобально, после чего его конфигурация становится частью системы по умолчанию.

import { Chart } from 'chart.js';

Chart.register(myPlugin);

После регистрации options.plugins.myPlugin становится доступным во всех графиках без дополнительного подключения плагина в каждом конфиге.


Доступ к сырой конфигурации

Иногда требуется доступ не к итоговым опциям, а к исходной структуре конфигурации графика:

beforeInit(chart) {
  const rawOptions = chart.options;
}

Однако для логики плагинов предпочтительнее использовать уже обработанный options в аргументах методов.


Переиспользование конфигураций

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

const basePluginOptions = {
  enabled: true,
  color: '#333'
};

const config = {
  type: 'line',
  options: {
    plugins: {
      myPlugin: basePluginOptions
    }
  }
};

Такой подход уменьшает дублирование и упрощает поддержку сложных конфигураций.


Ошибки при передаче опций

Наиболее частые проблемы связаны с:

  • несоответствием id плагина и ключа в options.plugins
  • попыткой использовать опции до регистрации плагина
  • мутацией объектов конфигурации после инициализации графика

В системе Chart.js конфигурация считается неизменяемой после создания экземпляра, поэтому изменения могут не применяться без вызова обновления графика.


Принцип изоляции плагинов

Каждый плагин получает собственный набор опций, изолированный от других плагинов. Это предотвращает конфликты имён и побочные эффекты при масштабировании системы расширений.

options: {
  plugins: {
    pluginA: { color: 'red' },
    pluginB: { color: 'blue' }
  }
}

Каждый плагин получает только свой фрагмент конфигурации.


Использование функций как фабрик опций

Опции могут генерироваться динамически перед созданием графика:

function createPluginOptions(theme) {
  return {
    color: theme === 'dark' ? '#fff' : '#000'
  };
}

const config = {
  options: {
    plugins: {
      myPlugin: createPluginOptions('dark')
    }
  }
};

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