Когда использовать Canvas вместо SVG

Разница между SVG и Canvas в экосистеме Nivo определяется прежде всего масштабом данных, требованиями к производительности и характером интерактивности. SVG-модель опирается на DOM-дерево, где каждый графический элемент представлен отдельным узлом, тогда как Canvas использует пиксельный буфер и перерисовывает сцену целиком при каждом обновлении.

SVG в Nivo строится на декларативном описании графика: каждая линия, точка, подпись или ось становится отдельным DOM-элементом. Это обеспечивает удобную работу с событиями, стилизацией через CSS и доступностью, но увеличивает нагрузку при большом количестве элементов.

Canvas-реализация работает иначе: график отрисовывается в одном или нескольких canvas-слоях. Отдельных DOM-узлов для каждой точки нет, что снижает стоимость рендеринга, но лишает части «структурной» интерактивности, характерной для SVG.

Ключевая разница формулируется так: SVG масштабируется по количеству DOM-элементов, Canvas — по количеству операций перерисовки.

Когда SVG становится узким местом

SVG-подход в Nivo начинает деградировать при росте плотности данных и количества визуальных примитивов. Типичные сценарии:

  • линейные графики с десятками тысяч точек
  • scatter plot с высокой плотностью распределения
  • частые обновления данных (реалтайм-стриминг)
  • множественные слои (area + line + points + annotations)

Проблема заключается не только в рендеринге, но и в стоимости diff-обновлений виртуального DOM и синхронизации событий.

В таких условиях даже оптимизированные SVG-компоненты Nivo начинают потреблять значительные ресурсы CPU, особенно на слабых устройствах.

Canvas-реализация в Nivo

В экосистеме Nivo для большинства графиков существуют Canvas-версии компонентов, например:

  • @nivo/line и @nivo/line-canvas
  • @nivo/bar и @nivo/bar-canvas
  • аналогичные canvas-варианты для точечных и комбинированных графиков

Canvas-версии используют императивный рендеринг: библиотека вручную управляет отрисовкой точек, линий и текста через 2D-context.

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

  1. очистка canvas
  2. вычисление масштабов и координат
  3. отрисовка осей
  4. отрисовка серии данных
  5. наложение интерактивных слоёв (tooltip, crosshair)

Такой подход минимизирует количество объектов, находящихся в памяти браузера, и снижает нагрузку на layout engine.

Производительность и масштаб данных

Canvas демонстрирует устойчивое поведение при увеличении числа точек, так как стоимость отрисовки зависит линейно от количества пиксельных операций, а не от количества DOM-узлов.

O(n)

SVG при этом фактически приближается к более дорогим моделям из-за накладных расходов DOM:

O(n n)

На практике это выражается в следующем:

  • до ~1–2 тыс. точек SVG работает стабильно
  • 5–10 тыс. точек требуют оптимизаций (clipping, memoization)
  • 50k+ точек почти всегда требуют Canvas

Canvas также выигрывает в сценариях постоянного обновления данных, поскольку перерисовка выполняется быстрее, чем reconciliation DOM.

Интерактивность и её ограничения

SVG в Nivo предоставляет нативную интерактивность:

  • hover на отдельной точке
  • события на уровне path/rect/circle
  • точечная стилизация через props
  • удобная работа с tooltip слоями

Canvas не имеет DOM-элементов, поэтому интерактивность реализуется через математическое сопоставление координат курсора и данных.

Типичный механизм:

  • вычисление ближайшей точки через hit-testing
  • поиск по индексам или spatial index (quadtree)
  • ручное управление tooltip-слоем

Это делает Canvas более сложным в настройке при высокой интерактивности, но даёт выигрыш в производительности.

Компромисс между качеством и скоростью

SVG обеспечивает:

  • идеальную масштабируемость без потери качества
  • доступность через DOM
  • удобную отладку через DevTools

Canvas обеспечивает:

  • стабильный FPS при больших объёмах данных
  • меньшую нагрузку на память
  • предсказуемое время рендеринга

Однако Canvas не сохраняет «структуру сцены» в DOM, поэтому такие операции, как инспекция элемента или CSS-стилизация отдельных частей графика, становятся невозможными.

Масштабирование интерфейса и DPI

SVG автоматически адаптируется к DPI без дополнительных усилий. Canvas требует учёта devicePixelRatio, иначе графики становятся размытыми на Retina-экранах.

Типичный подход в Canvas-версии Nivo:

  • масштабирование canvas buffer до физического разрешения
  • использование CSS для визуального размера
  • компенсация координат при обработке событий

Без этого визуальная четкость деградирует при увеличении плотности пикселей.

Сложные графики и многослойность

SVG удобнее при построении сложных композиций:

  • комбинированные графики (line + bar + annotations)
  • динамические подписи и аннотации
  • кастомные маркеры и элементы управления

Canvas требует ручной композиции слоёв. Nivo решает это через последовательные draw-pass’ы, но сложность растёт экспоненциально при увеличении количества слоёв.

В сценариях аналитических дашбордов с высокой плотностью данных Canvas предпочтительнее, тогда как SVG остаётся более гибким для дизайнерских и low-to-mid data задач.

Паттерны выбора в Nivo

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

SVG используется, когда:

  • данных немного
  • важна интерактивность на уровне элементов
  • требуется доступность и SEO-индексация
  • график является частью UI-композиции

Canvas используется, когда:

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

Поведение при анимации

SVG-анимации в Nivo используют transitions, основанные на интерполяции атрибутов DOM-элементов. Это удобно, но дорого при большом количестве объектов.

Canvas-анимация реализуется через полную или частичную перерисовку сцены. При грамотной оптимизации (dirty rectangles, throttling) Canvas сохраняет плавность даже при высоких нагрузках.

Влияние на архитектуру приложения

Выбор Canvas или SVG в Nivo влияет на структуру данных и уровень абстракции:

  • SVG допускает декларативную модель, ближе к React-подходу
  • Canvas требует более явного управления жизненным циклом отрисовки

В Canvas-режиме чаще используются:

  • мемоизация вычисленных координат
  • предрасчёт шкал
  • кеширование transformed datasets

SVG-режим позволяет полагаться на React reconciliation и минимизировать ручные оптимизации.

Итоговое различие подходов

SVG и Canvas в Nivo представляют не просто разные технологии рендеринга, а разные модели мышления о графике: объектную и пиксельную. Первая ориентирована на структуру и семантику, вторая — на производительность и контроль над пикселями.