Визуализировать связи данных между компонентами таблиц на React JS
Я визуализирую данные двух таблиц:
const json ={
"tables": [
{
"tableName": "One",
"coordinates": {
"x": "100",
"y": "100"
},
"columns": [
{"name": "smthLike",
"type": "string",
"typeFormat": "",
"example": "",
"descriptor": ""},
{"name": "@MainColumn",
"type": "integer",
"typeFormat": "int64",
"example": "",
"descriptor": "codePlatform"}
]
},
{
"tableName": "Two",
"coordinates": {
"x": "200",
"y": "200"
},
"columns": [
{"name": "codePlatform",
"type": "string",
"typeFormat": "",
"example": "",
"descriptor": ""},
{"name": "namePlatform",
"type": "string",
"typeFormat": "",
"example": "",
"descriptor": ""}
]
}
]
}
введите сюда код
В работе я использую код библиотеки react-xarrows, Example 4: https://codesandbox.io/embed/github/Eliav2/react-xarrows/tree/master/examples?fontsize=14&hidenavigation=1&theme=dark
У таблиц есть ключи name descriptor. Если дескриптор совпадает с именем (codePlatform в данном случае), то стрелка связи данных должна тянуться от поля с codePlatform к тому полю, у которого является дескриптором (@MainColumn).
Я пыталась прописать такое условие, но пока не выходит. Чтобы отрисовать стрелку, нужно задать ей точку начала и точку конца. Подскажите, как можно прописать такое условие в компонент поля Column?
import React from "react";
import styles from "./Column.module.css";
import Xarrow, { useXarrow, Xwrapper } from "react-xarrows";
export const Column = ({ column, index }) => {
const { name, descriptor } = column;
const line = {
from: "",
to: "",
};
return (
<>
<div className={styles.ColumnContainer}>
{name}: {descriptor}
</div>
</>
);
};
код компонента таблиц:
import Draggable from 'react-draggable';
import React from 'react';
import Xarrow, { useXarrow, Xwrapper } from 'react-xarrows';
import { Column } from '../Column/Column';
export const DraggableBox = ({table, key, reference = undefined, id = undefined, ...style }) => {
const {tableName, coordinates} = table;
const updateXarrow = useXarrow();
//if (initialOffset) moreStyle = { position: 'absolute', left: initialOffset.x, top: initialOffset.y };
return (
<Draggable onDrag={updateXarrow} onStop={updateXarrow}>
<div ref={reference} id={id} style={{position: 'absolute', left: coordinates.x + 'px', top: coordinates.y + 'px', border: '2px solid'}}>
<p>Название: {tableName}</p>
<div>
{table.columns.map((column, index) => (
<Column table={table} column={column} key={index} />
))}
</div>
</div>
</Draggable>
);
};
введите сюда код
и компонент, где перебираю весь массив данных:
import { Table } from "../Table/Table";
import styles from "./Tables.module.css";
import tableData from "../utils/all_db_schema.json";
export const Tables = () => {
const [tableState, setTableState] = useState(tableData);
return (
<>
{tableState.map((elem, index) => (
<div
className={styles.AreaContainer}
key={index}
style={{ color: elem.color }}
>
<p>Имя: {elem.groupName}</p>
<div className={styles.ClassesContainer}>
{elem.tables.map((table, index) => (
DraggableBox table={table} key={index} />
))}
</div>
</div>
))}
</>
);
};
Ответы (1 шт):
В документации react-xarrows сказано что в качестве start и end могут выступать строки, поэтому я предпочел их использование useRef (которые пришлось бы прокидывать через все приложение), достаточно чтобы это были уникальные id (по всему приложению!), я внес их в данные колонок, как selfId:
{
name: "smthLike",
type: "string",
typeFormat: "",
example: "",
descriptor: "",
selfId: "box1" <--- добавляем Id (уникальное среди всех)
},
при cоздании колонки id присваивается элементу:
export const Column = ({ column, index }) => {
const { name, descriptor, selfId } = column;
return (
<div id={selfId} className={styles.ColumnContainer}> // Присваиваем id
{name}: {descriptor}
</div>
);
};
Хранение самих ссылок можно организовывать абсолютно по-разному, поэтому эту часть я не делал, это может быть отдельный массив, что упростит парсинг для рендера или эта информация может хранится в колонке вместе с selfId (имена разумеется могут бы по вкусу, я назвал так чтобы не было путаницы)
В Tables выводим все имеющиеся стрелки
<Xarrow start="box1" end="box3" />
Обновляем при перетаскивании onMouseMove={() => setUpd(!upd)}можно обновлять любым другим способом, так как используемый здесь способ может повлиять на производительность.
Я встречал такой способ обновления, возможно у него есть свои плюсы, но все это рассчитано на плоскую структуру (когда нет вложенности компонент), т.е. текущий случай иной.
const [, reRender] = useReducer(() => ({}), {});
const renderCount = useRef(0);
useEffect(() => {
renderCount.current += 1;
if (renderCount.current === 2) {
reRender();
renderCount.current = 0;
}
});
К сожалению updateXarrow в DraggableBox почему-то не приводит к обновлению.
export const Tables = () => {
const [upd, setUpd] = useState(false);
return (
.........
<div
onMouseMove={() => setUpd(!upd)} // Обновляем при движении мыши
>
.........
<div className={styles.ClassesContainer}>
{elem.tables.map((table, index) => (
<DraggableBox table={table} key={index} />
))}
<Xarrow start="box1" end="box3" /> // Cтрелки
</div>
.........
);
Ссылка на песочницу с приведенными изменениями (файлы компонент, импорт немного модифицировались!)
