В KgBase мы недавно переписали пользовательский интерфейс графа, чтобы использовать WebGL вместо SVG. Нашей целью было:
- Повышение производительности и возможность визуализации 1000 узлов.
- Если возможно, продолжайте использовать React. Мы хотим быстро внедрять новые функции, а React позволяет быстрее создавать прототипы.
Очень распространенным инструментом для рендеринга содержимого WebGL является Pixi.js. Обычно он используется для создания простых игр, но очень хорошо работает в нашем случае.
Если вы хотите интегрировать Pixi.js с React, вам нужно будет использовать React Pixi (или react-pixi-fiber, но я вернусь к этому позже).
В своей первоначальной версии наш код рендеринга был таким простым:
Вы можете просто взять все узлы и для каждого визуализировать свой собственный NodeView
компонент, который позаботится о визуализации одного узла:
Теперь обратите внимание на компонент Circle
. Это не часть react-pixi
. Мы импортируем это из нашей собственной ./Primitives
папки.
React Pixi показывает вам, как создавать свои собственные компоненты, как указано выше, прямо на их целевой странице:
Заметили что-нибудь не так с этим кодом?
Я тоже этого не делал, пока мы не попали в конкретную ситуацию:
Когда вы нажимаете на узел, мы хотим его выделить. Мы делаем это, устанавливая альфа щелкнутого узла на 1.0, уменьшая альфа всех остальных узлов до 0.2 или около того.
В приведенной выше реализации каждое изменение альфа-канала будет вызывать applyProps
, который перерисовывает всю фигуру. Итак, мы вызываем этот фрагмент 1000 раз каждый раз, когда пользователь щелкает узел:
Если мы просто хотим изменить альфа, это все, что нам нужно сделать:
Итак, правильный способ реализации вашего настраиваемого компонента Rectangle / Circle будет таким:
Важная часть - убедиться, что нет ненужного повторного рисования вашего компонента. Всякий раз, когда вы видите такой код:
Вам следует провести рефакторинг: всегда сравнивайте свой props
с oldProps
и выполняйте повторный рендеринг только в том случае, если что-то изменилось.
Интересный факт: реализация Text
в react-pixi
по умолчанию также будет обновлять компонент каждый раз, даже если ничего не изменилось. Реализация по умолчанию выглядит примерно так:
Установка нового текстового значения (instance.text = text
) - дорогостоящая операция! Это приведет к повторной визуализации вашего экземпляра Pixi. Вместо этого всегда проверяйте необходимость повторного рендеринга.
Чтобы исправить это, вам нужно создать свой собственный компонент, например, с именем FastText
:
И теперь рендеринг будет происходить только в том случае, если текст действительно был изменен.
При работе с Pixi и WebGL необходимо учитывать гораздо больше вопросов. То, что я описал выше, - хороший первый шаг к написанию высокопроизводительного кода. Всегда будьте осторожны с тем, что происходит в applyProps
. Он никогда не должен создавать новые Graphics
объекты, и он не должен даже изменять свойства без необходимости. Перед тем, как что-либо менять, всегда нужно сравнивать текущие и старые свойства.
Как я уже сказал, это хороший первый шаг. Благодаря этому подходу мы довольно легко смогли визуализировать до 5 000–10 000 узлов. Еще многое предстоит сделать для повышения FPS и большего количества узлов, но это тема для другого сообщения в блоге.