Библиотека GoJS: создание интерактивных диаграмм
Работа с библиотекой GoJS для построения диаграмм
GoJS - это мощная JavaScript-библиотека для создания интерактивных диаграмм, графов и схем. Она поддерживает широкий набор визуальных элементов, автоматические раскладки, привязку данных и пользовательские взаимодействия. Библиотека распространяется по коммерческой лицензии, но доступна для ознакомления в режиме trial.
Как создать простую блок-схему с помощью GoJS?
Рассмотрим базовый сценарий - построение диаграммы с тремя узлами и связями между ними. Для этого подключим GoJS через CDN, создадим экземпляр Diagram и определим шаблоны узлов и связей.
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/gojs@2.3.22/release/go.js"></script>
</head>
<body>
<div id="myDiagramDiv" style="width:800px; height:600px; border:1px solid black"></div>
<script>
const $ = go.GraphObject.make;
const diagram = $(go.Diagram, "myDiagramDiv");
// шаблон узла
diagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, "RoundedRectangle", { fill: "lightblue", stroke: "blue" }),
$(go.TextBlock, { margin: 10, text: "Узел" },
new go.Binding("text", "key"))
);
// шаблон связи
diagram.linkTemplate =
$(go.Link,
$(go.Shape, { stroke: "gray", strokeWidth: 2 }),
$(go.Shape, { toArrow: "Standard", fill: "gray" })
);
// данные модели
diagram.model = new go.GraphLinksModel(
[
{ key: "Начало" },
{ key: "Процесс" },
{ key: "Конец" }
],
[
{ from: "Начало", to: "Процесс" },
{ from: "Процесс", to: "Конец" }
]
);
</script>
</body>
</html>Go js (библиотека gojs для диаграмм)
После загрузки страницы отобразится диаграмма с тремя узлами и стрелками. Узлы имеют закруглённые углы, синюю обводку и светло-голубой фон. Связи рисуются серыми линиями со стрелками на конце.
Как использовать GoJS внутри React-приложения?
Для интеграции с React требуется обёртка, которая управляет жизненным циклом Diagram. Один из подходов - создать компонент, который инициализирует диаграмму в useEffect и уничтожает её при размонтировании.
import React, { useEffect, useRef } from 'react';
import go from 'gojs';
const GoDiagram = () => {
const divRef = useRef(null);
useEffect(() => {
const $ = go.GraphObject.make;
const diagram = $(go.Diagram, divRef.current);
diagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, "RoundedRectangle", { fill: "white" }),
$(go.TextBlock, { margin: 10 },
new go.Binding("text", "key"))
);
diagram.model = new go.GraphLinksModel(
[{ key: "A" }, { key: "B" }],
[{ from: "A", to: "B" }]
);
return () => diagram.div = null;
}, []);
return <div ref={divRef} style={{ width: '100%', height: '500px' }} />;
};
export default GoDiagram;Chart js script (библиотека chart.js)
Компонент использует ref вместо ID, что удобно для повторного использования. Очистка при размонтировании предотвращает утечки памяти.
Как изменить внешний вид узлов с использованием пользовательских SVG-шаблонов?
GoJS позволяет задавать сложные фигуры и встраивать интерактивные элементы. Например, создадим узел с иконкой и текстом, используя панели.
diagram.nodeTemplate =
$(go.Node, "Horizontal",
$(go.Picture, { source: "https://example.com/icon.png", width: 30, height: 30 }),
$(go.TextBlock, { margin: 5, font: "14px sans-serif" },
new go.Binding("text", "name"))
);Для более сложных форм (например, «шестиугольник») можно использовать Geometry:
$(go.Shape,
{ geometryString: "M0,0 L40,0 L50,30 L40,60 L0,60 L-10,30 Z", fill: "lightgreen" })Такие шаблоны позволяют строить диаграммы, не ограниченные стандартными фигурами.
Как реализовать автоматическую раскладку (layout) дерева?
Для иерархических графов используйте TreeLayout. Достаточно заменить свойство layout диаграммы.
diagram.layout = $(go.TreeLayout, { angle: 90, layerSpacing: 40, nodeSpacing: 20 });
// ... далее модель должна содержать данные с указанием parentПример модели для дерева:
diagram.model = new go.TreeModel([
{ key: "Корень" },
{ key: "Дочерний1", parent: "Корень" },
{ key: "Дочерний2", parent: "Корень" }
]);Диаграмма автоматически расположится сверху вниз. В GoJS доступны также ForceDirectedLayout, CircularLayout и LayeredDigraphLayout.
Как добавить поддержку перетаскивания (drag & drop) узлов?
По умолчанию узлы в GoJS можно перетаскивать, если не отключено свойство movable. Для добавления возможности перетаскивания из внешнего источника (например, панели инструментов) требуется обработчик события.
// Разрешить перетаскивание из HTML-элемента
diagram.div.addEventListener('dragover', e => {
e.preventDefault();
});
diagram.div.addEventListener('drop', e => {
const data = e.dataTransfer.getData('text');
const point = diagram.lastInput.documentPoint;
diagram.model.addNodeData({ key: data });
// новое положение узла
const node = diagram.findNodeForKey(data);
if (node) node.location = point;
});Также можно настроить MouseDrop событие самого Diagram.
Расширенные примеры работы с GoJS
Пример 1: Синхронизация данных диаграммы с внешним JSON
Часто данные диаграммы приходят с сервера. Ниже показано, как загрузить модель из JSON и обновить её в реальном времени.
async function loadDiagram() {
const response = await fetch('/api/diagram');
const data = await response.json();
diagram.model = new go.GraphLinksModel(data.nodes, data.links);
}
// Обновление при каждом изменении: слушаем событие 'Modified'
diagram.addModelChangedListener(e => {
if (e.isTransactionFinished) {
const modelData = diagram.model.toJSON();
sendToServer(modelData); // отправка на бэкенд
}
});Это позволяет создавать многопользовательские редакторы. Важно сериализовать модель в формат, совместимый с GoJS. Метод toJSON возвращает объект, который можно сохранить.
Пример 2: Привязка данных по загрузке изображения в узел
Узлы могут отображать изображения, загружаемые асинхронно. Используем Binding с конвертером.
diagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, { fill: "white" }),
$(go.Panel, "Vertical",
$(go.Picture, { width: 80, height: 80, imageStretch: go.GraphObject.UniformToFill },
new go.Binding("source", "imageUrl").makeTwoWay(),
new go.Binding("visible", "imageUrl", url => url ? true : false)
),
$(go.TextBlock, { margin: 5 },
new go.Binding("text", "label"))
)
);
// данные
{ key: 1, label: "Пример", imageUrl: "https://example.com/photo.jpg" }Если URL недоступен, изображение скроется, и узел покажет только текст.
Пример 3: Создание пользовательского инструмента для рисования связей
По умолчанию связи рисуются через инструмент LinkingTool. Можно расширить его, чтобы добавлять логику при создании связи.
class CustomLinkingTool extends go.LinkingTool {
doActivate() {
// дополнительная проверка перед началом рисования
if (!this.diagram.selection.first() || !this.diagram.selection.first() instanceof go.Node) {
alert("Выберите узел-источник");
return;
}
super.doActivate();
}
}
diagram.toolManager.linkingTool = new CustomLinkingTool();Такой подход полезен, когда нужно ограничить типы связей или добавить подтверждение.
Пример 4: Экспорт диаграммы в PNG с высоким разрешением
GoJS поддерживает встроенный экспорт в изображение. Можно задать масштаб.
function exportToPNG() {
const imgData = diagram.makeImageData({
scale: 2, // Retina-качество
background: "white",
type: "image/png"
});
const link = document.createElement('a');
link.download = 'diagram.png';
link.href = imgData;
link.click();
}Результат - изображение с разрешением в два раза выше экранного.
Пример 5: Интерактивная панель свойств при клике на узел
При выборе узла можно отображать его свойства в отдельном блоке. Используем событие DiagramEvent.
diagram.addDiagramListener('ChangedSelection', e => {
const selection = diagram.selection.first();
if (selection instanceof go.Node) {
const data = selection.data;
document.getElementById('propertyPanel').innerHTML =
`Имя: ${data.key}
Описание: ${data.description || ''}`;
}
});Это позволяет строить редакторы диаграмм с контекстной панелью.