Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 27.10.2024, 20:09
Интересующийся
Отправить личное сообщение для wolfio Посмотреть профиль Найти все сообщения от wolfio
 
Регистрация: 10.02.2018
Сообщений: 22

Прошу помощи в доделывании скрипта (jsPlumb)
Уважаемые эксперты, прошу помощи.

Задача стоит следующим образом:
Есть таблицы в БД, мне нужно нарисовать кастомную ER (entity relation) диаграмму связей в БД. Кастомную в связи со спецификой продукта в БД.
Для управления приложением используется JavaFX и контроллер WebView.
Идея в том, что на Java идет работа с чтением БД, а при действиях пользователя я буду динамически добавлять таблицы на диаграмму (веб-страницу)

К сожалению, высоким уровнем компетенции на JS+CSS не обладаю, в связи с чем обратился к GPT но дошел до тупика.
GPT рекомендовал использовать jsPlumb. Из разных вариантов, что он предлагал, этот показался более менее читаемым.

Вот что я имею сейчас:
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>ER Диаграмма с jsPlumb</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jsPlumb/2.15.6/js/jsplumb.min.js"></script>
    <style>
        body { position: relative; width: 100%; height: 100%; margin: 0; overflow: hidden; }
        .table {
            width: 150px;
            padding: 10px;
            border: 1px solid #000;
            border-radius: 5px;
            background: #fff;
            position: absolute;
            cursor: move;
            box-shadow: 2px 2px 5px rgba(0,0,0,0.3);
        }
        .attribute {
            padding-left: 10px;
            cursor: default; /* Отключаем курсор для атрибутов */
            user-select: none; /* Отключаем выделение текста */
        }
        .aLabel {
            font-size: 12px;
            background: rgba(255,255,255,0.8);
            padding: 2px;
            border-radius: 3px;
        }
    </style>
</head>
<body>
<div id="diagram-container" style="width: 100%; height: 100%; position: relative;"></div>

<script>
    jsPlumb.ready(function() {
        const instance = jsPlumb.getInstance({
            Connector: "Bezier",
            Anchors: ["Right", "Left"],
            Endpoint: ["Dot", { radius: 5 }],
            PaintStyle: { stroke: "#999", strokeWidth: 2 },
            EndpointStyle: { fill: "#999" },
            Container: "diagram-container"
        });

        let allowConnection = false; // Флаг для разрешения соединений через код

        // Обработчик перед созданием соединения
        instance.bind("beforeDrop", function(info) {
            if (allowConnection) {
                allowConnection = false; // Сброс флага после разрешения
                return true; // Разрешить соединение
            }
            return false; // Запретить соединение, созданное пользователем
        });

        // Функция для добавления таблицы
        window.addTable = function(id, name, x, y, attributes) {
            if (document.getElementById(id)) {
                console.warn(`Таблица с id "${id}" уже существует.`);
                return;
            }

            const table = document.createElement("div");
            table.className = "table";
            table.id = id;
            table.style.left = x + "px";
            table.style.top = y + "px";

            const title = document.createElement("strong");
            title.innerText = name;
            table.appendChild(title);

            attributes.forEach(attr => {
                const attrDiv = document.createElement("div");
                attrDiv.className = "attribute";
                attrDiv.id = attr.id;
                attrDiv.innerText = attr.name;
                table.appendChild(attrDiv);

                // Настройка источника и цели для атрибутов
                instance.makeSource(attrDiv, {
                    anchor: "Continuous",
                    connectorStyle: { stroke: "#999", strokeWidth: 2 },
                    connectionType: "basic",
                    extract: { "action": "the-action" },
                    maxConnections: -1,
                    filter: ".attribute",
                    allowLoopback: false
                });

                instance.makeTarget(attrDiv, {
                    anchor: "Continuous",
                    allowLoopback: false,
                    maxConnections: -1,
                    dropOptions: { hoverClass: "dragHover" }
                });
            });

            document.getElementById("diagram-container").appendChild(table);

            // Сделать таблицу перетаскиваемой
            instance.draggable(table, {
                grid: [10, 10],
                stop: function() {
                    instance.repaintEverything();
                }
            });
        };

        // Функция для добавления связи
        window.addConnection = function(sourceId, targetId, type) {
            const sourceElem = document.getElementById(sourceId);
            const targetElem = document.getElementById(targetId);
            if (!sourceElem || !targetElem) {
                console.warn(`Элемент(ы) с id "${sourceId}" или "${targetId}" не найдены.`);
                return;
            }

            allowConnection = true; // Разрешить соединение через код
            instance.connect({
                source: sourceId,
                target: targetId,
                overlays: [
                    ["Label", { label: type, location: 0.5, id: "label", cssClass: "aLabel" }]
                ]
            });
        };

        // Отключаем возможность добавления соединений пользователем
        // Можно дополнительно скрыть эндпоинты, если необходимо
        
         addTable('users', 'Users', 100, 100, [
            { id: 'u_id', name: 'id' },
            { id: 'u_name', name: 'name' },
            { id: 'u_email', name: 'email' }
        ]);

        addTable('articles', 'Articles', 400, 100, [
            { id: 'a_id', name: 'id' },
            { id: 'a_title', name: 'title' },
            { id: 'a_content', name: 'content' },
            { id: 'a_author_id', name: 'author_id' }
        ]);

        addConnection('u_id', 'a_author_id', '1:M');






    });
</script>
</body>
</html>


С чем я прошу помощи:
Условия:
  • нужно запретить пользователю редактировать связи (сейчас если потянуть за точку вначале связи, ее можно убрать или подвинуть)
  • нужно сделать так, чтобы узел таблицы были оформлены именно как таблицы (сейчас это оформлено просто как облачко). Колонку можно для теста добавить любую
    Связи при этом должно отходить именно от строки таблицы, а не от всего узла целиком
  • нужно так же сделать возможность указывать связь саму на себя (т.е. например таблицу user может иметь поле "замещающий пользователь", в котором будет ссылка на эту же таблицу. в Этом случае от поля substitute_user связь должна отходить на колонку id

если кто-то знает менее трудоемкие инструменты для решения моей задачи, укажите пожалуйста.

Благодарю за внимание.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Прошу помощи в оптимизации кода eagle_nest Общие вопросы Javascript 0 07.10.2017 16:13
serialize-unserialize js php прошу помощи mrmammoth Общие вопросы Javascript 5 19.03.2014 16:16
Прошу помочь в изменении внешнего вида скрипта обратного отсчета 8585 Ваши сайты и скрипты 5 18.07.2013 11:42
Прошу помощи xavi AJAX и COMET 8 28.01.2013 10:36
Проблема скрипта карусели в firefox. Очень прошу помощи. -user21- jQuery 5 16.06.2010 13:38