Canvas или SVG для карты офиса: как мы выбрали и справились с неочевидными граблями
- вторник, 30 июня 2026 г. в 00:00:12
Если к вам придут с задачей внедрения интерактивной карты офиса, какой рендер вы выберете? Canvas или SVG? Верхнеуровневый обзор скажет, что Canvas хорош для частых перерисовок (географические карты, игры), а SVG — когда важна работа с отдельными элементами, которые естественным образом присутствуют в DOM.
Мы выбрали SVG. В этой статье не будет глубокого анализа, это живая история о том, почему мы отказались от идеи использовать Canvas, как строили карту с нуля, какие инструменты использовали, как организовали связь между SVG-элементами и данными в БД, и как сделали админку, где карту могут менять дизайнеры без участия разработчиков.
Как мы выбирали между Canvas и SVG
Итак, к нам пришли с задачей: заменить существующий модуль интерактивных карт офисов. Предыдущая система была сделана на Canvas, а координаты пинов рабочих мест хранились на бэкенде.
Это создавало проблему: любое изменение изображения карты офиса влекло риск несоответствия координат пина и самого рабочего места. Это был первый звоночек в пользу SVG — отрисовку пина можно привязать к конкретному объекту на карте, а не к абстрактным координатам.
Кроме того, информация на экране была перегружена. Ее имело смысл скрыть за всплывающими окнами, которые появлялись после выбора объекта пользователем. В SVG это сделать проще — каждый элемент доступен в DOM, и клик по нему обрабатывается нативно.
Более того, сами карты офиса предполагалось менять без участия разработчиков — силами дизайнеров и, в идеале, ответственными за офисную инфраструктуру. В крайнем случае — после короткого обучения персонала.
Этот пункт оказался критическим. Он отсеивает практически все популярные библиотеки для построения интерактивных карт, оставляя только вариант с использованием файлов SVG, нарисованных дизайнерами в привычных инструментах (Figma, Illustrator и т.п.).
Что должно быть интерактивным
По требованиям, взаимодействию с пользователем подлежат не все элементы, а только три типа:
Рабочие места
Переговорные комнаты
Оборудование
У каждого типа — своя информация, которая отображается при клике.
В результате хотелось бы видеть что-то такое:

Но некоторая зависимость в отображении от BE все же присутствует, поговорим на примере оборудования.
Placeholder-элементы: как мы подставляли иконки в зависимости от данных бэка
В отображении оборудования есть зависимость от бэкенда — иконка должна меняться в зависимости от типа оборудования (принтер, массажное кресло, сканер и т.д.). Для этого мы использовали placeholder-элементы.
В исходном SVG-файле оставляем элементы-заглушки, на место которых после загрузки карты подставляется нужная SVG-иконка в зависимости от ответа бэкенда. Одна маленькая SVG на каждый тип оборудования.
Исходный файл SVG выглядит примерно так:

Логика «инициализации» интерактивных элементов применяется и к рабочим местам, и к переговорным, но в немного другом виде.
Здесь пришлось поиграться с отрисовкой через JS. Нам понадобились инструменты для определения трансформации placeholder’а и применения ее к новому элементу. Огромную помощь оказала библиотека svgdotjs — она значительно упростила работу с SVG.
После вставки нужного элемента на место мы помечаем его классом inited-equipment. Это позволяет селектировать его для CSS и JS. Аналогичный процесс проделываем для рабочих мест (inited-workplace) и переговорных (inited-room).
Поповеры: как отображать информацию рядом с элементом
Всю информацию об объектах мы скрыли в поповеры — как и планировали. Сделаны они динамическими компонентами Angular.
Главный вопрос: как отобразить поповер в нужном месте?
Изначально идея была использовать foreignObject — позиционировать его относительно кликнутого элемента. Но мы столкнулись с тем, что SVG обрезает элементы, выходящие за его viewBox. Пришлось искать другой путь.
В итоге мы реализовали поповер как абсолютно позиционированный элемент-сосед тега SVG самой карты. Позицию определяем через CTM (Current Transformation Matrix) элемента — оборудования, рабочего места или переговорной.
Мягкая связь между SVG и БД: самая сложная часть
Уже упоминалось, но стоит остановиться подробнее на «мягкой» связи между сущностью в БД и отображаемой сущностью в SVG.
Да, мы можем использовать id элементов SVG для идентификации элемента в БД (например, чтобы получать информацию о конкретном рабочем месте в поповере). Но удаление рабочего места из файла SVG магическим образом не удалит его из БД.
Это вынудило нас создать серьезную логику на загрузку новой карты.
Админка: редактирование и замена карт
Из-за описанной выше проблемы админка логически разделилась на два функционала:
Редактирование самой карты SVG.
Замена карты SVG за определенным офисом со своей валидацией загружаемого файла.
К счастью, функционал редактирования SVG хорошо закрывается проектом SVGedit (https://github.com/svg-edit/svgedit) с небольшими доработками.
Что мы доработали:
Ограничили инструментарий редактора, оставив только добавление конкретных объектов из так называемой «библиотеки элементов». Это упрощает добавление интерактивных элементов, об интерактивности которых должны знать и фронтенд, и бэкенд.
До готовности админки оставалось добавить функционал upload файла карты с полноценным парсингом и валидацией на бэкенде.
Валидация нужна, чтобы исключить удаление рабочих мест, за которыми закреплены сотрудники.
Жесткая валидация: запрещаем загрузку, если удален элемент с привязанным человеком относительно текущей сохраненной карты.

Мягкая валидация: разрешаем сохранение новой карты, если удалены объекты без закрепленных людей.

Ключевые выводы:
SVG — правильный выбор, когда важна работа с отдельными элементами и их интерактивность.
Placeholder-элементы — удобный способ подстановки иконок в зависимости от данных бэкенда.
svgdotjs — отличный помощник для работы с трансформациями и манипуляциями SVG.
Поповеры через абсолютное позиционирование — рабочий обход ограничений foreignObject.
Валидация загрузки карт — важна, если у вас есть связь между визуалом, представленным в виде файла карты офиса, и данными в БД, закрепленными за отображенными объектами в том файле.
SVGedit с ограничениями — хорошее решение для админки, если карты должен менять персонал, ответственный за инфраструктуру, а не разработчики.
Мы не претендуем на идеальность решения. Но таков был наш ответ на задачу интерактивной карты офиса.
А как бы вы решали эту задачу? Использовали бы готовые библиотеки или пошли своим путем? Сталкивались ли с похожими проблемами привязки данных к SVG-элементам?