Как эффективней отрисовывать много SVG графики?

Хочу реализовать интерфейс блок-схемы, с возможностью перетаскивания самой сетки и элементов мышью.
Первый вариант был таким:
5c46f52c2caa3449298850.png
  • Этот вариант использует просто длинные блоки вместо линий, то есть не SVG. Он тупит (чистый js).
  • Вторым вариантом было использование SVG для линий, а блоки вставлялись поверх тега svg. Сам svg-блок растянут на нужную величину в контейнере с overflow: scroll, как и в первом варианте, а мышью просто скролил. Тоже тупило, но меньше (использовал Vue.js)
  • Третий вариант, это использование в основном svg, скролил уже содержимое тега во вью-боксе. Результат - такой же, как и во втором варианте (тоже Vue)

Компьютер не самый мощный, я понимаю что в этом проблема, но вдруг есть какой-то лайфхак?).
Главный вопрос: как вообще происходит отрисовка элементов в браузере, и как оптимизировать это?
  • Вопрос задан
  • 391 просмотр
Решения вопроса 1
Vlad_IT
@Vlad_IT Куратор тега JavaScript
Front-end разработчик
По скорости работы, быстрее будет canvas, но он по скорости разработки будет хуже. У меня никаких тормозов на vue+svg нет, по крайней мере, до 500 объектов на холсте. Для оптимизации могу посоветовать некоторые вещи:
1) Используйте path вместо нескольких разных других фигур.
2) Для сетки не создавайте кучу линий или фигур, просто используйте pattern. Вот пример из моего проекта (он на React JSX, но не суть)
<pattern id={"bg-" + this.props.id} patternUnits="userSpaceOnUse" width="100" height="100">
    <rect width="100" height="100" fill={this.props.canvasColor}></rect>
    <g fill={this.props.canvasGridColor} style={{ fillOpacity: 0.34 }}>
        <rect width="100" height="1" y="20"></rect>
        <rect width="100" height="1" y="40"></rect>
        <rect width="100" height="1" y="60"></rect>
        <rect width="100" height="1" y="80"></rect>
        <rect width="1" height="100" x="20"></rect>
        <rect width="1" height="100" x="40"></rect>
        <rect width="1" height="100" x="60"></rect>
        <rect width="1" height="100" x="80"></rect>
    </g>
    <rect width="100" height="100" fill="none" strokeWidth="2" stroke={this.props.canvasGridColor}></rect>
</pattern>

вот так заливаю на холст
<rect style={{ 'fill': `url(#bg-${this.props.id}) #fff` }} ... />

3) Задавайте для изменяемых объектов атрибут уникальный атрибут key
4) Цельные объекты кидайте в группу, и на нее назначайте общие стили и позицию.
UPD: простой пример на 1000 объектов (можно добавить, поменяв константу COUNT_OBJECTS) с drag&drop
jsfiddle.net/Vlad_IT/81kegmxf
UPD2: вот тот же пример, только с сеткой jsfiddle.net/Vlad_IT/qt64rouL/1 если делать сетку не заливкой, а элементами, будут ощутимые тормоза.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы