Разбираемся, как рисовать SVG-иконки на канвасе. Придумываем способ единообразно использовать одни и те же SVG-файлы из UI-кита как в DOM, так и на канвасе.

В нашем приложении Focus Calendar для производительной отрисовки событий календаря мы используем Canvas 2D API. Помимо этого у нас есть и «обычные» интерфейсы, написанные на React.

Также у нас есть и библиотека UI-компонентов, которую мы успешно использовали в Реакт-частях интерфейса.

И вот, наконец, возникла потребность отрисовывать SVG-иконки на канвасе. При этом, конечно, хотелось брать их из UI-кита — придумать как единообразно использовать одни и те же SVG-файлы как в DOM, так и на канвасе.

В этом посте я расскажу, как мы справились с этой задачей.

SVG на канвасе

Для рисования на Canvas мы используем библиотеку Konva и её React-байндинги — react-konva. Она позволяет работать с канвасом в привычной реакт-парадигме.

В документации описано несколько способов отрисовки SVG на канвасе:

1. Konva.Image

Выглядит как самый прямолинейный способ, минимально увеличивающий сложность системы и подходящий для любых изображений. Чтение исходников только прибавило уверенности: используется вызов drawImage() из Canvas 2D API и никакой магии.

2. Konva.Path

Любопытный способ, но, как выяснилось, Path поддерживает не все атрибуты, используемые в наших SVG-иконках. Например fill-rule="evenodd". Ну и первый способ по-прежнему кажется проще.

3. External library to render SVG to canvas

Тоже отбрасываем, т.к. мы не нашли причин его использовать, при наличии более простого способа №1.

Итак, выбираем Konva.Image. Простая демка от создателя библиотеки:

Значит, берём SVG в виде строки, конвертируем в data URI, превращаем в инстанс HTMLImageElement с помощью хука useImage, и полученное изображение передаём в компонент Конвы <Image/> .

Выглядит весьма просто.

Но что если нужно менять цвет этой SVG?

Кастомизация цвета

SVG как Реакт-компоненты