Показать сообщение отдельно
  #1 (permalink)  
Старый 30.11.2018, 17:31
Новичок на форуме
Отправить личное сообщение для Vad0k Посмотреть профиль Найти все сообщения от Vad0k
 
Регистрация: 30.11.2018
Сообщений: 8

Визуализация связей между блоками с использованием SVG и JS
Доброго времени форумчане.
Сижу сейчас на работе и тут мне прилетело задание сделать визуальный конфигуратор ... застрял на реализации связей между компонентами:
Реализовываю с использованием SVG + JS (ES6)... Перенос элементов реализовал, но линии прям не поддаются пока что сделать. Подумал перейти на библиотеку, чтобы упростить работу (связывания элементов).
Посоветуйте, по возможности алгоритм или библиотеку для манипулирования SVG (построение связей).


// Перетаскивание элементов
(function () {
    let $document = $(document);

    const $svg = $('#main .canvas-svg');
    // PC
    $document.on('mousedown', $svg, startDrag);
    $document.on('mousemove', $svg, drag);
    $document.on('mouseup', $svg, endDrag);
    $document.on('mouseleave', $svg, endDrag);

    // MOBILE
    $document.on('touchstart', $svg, startDrag);
    $document.on('touchmove', $svg, drag);
    $document.on('touchend', $svg, endDrag);
    $document.on('touchleave', $svg, endDrag);
    $document.on('touchcancel', $svg, endDrag);


    let selectedElement = false,
        offsetElement,
        transformElement;

    let selectLineChanel = false;
    let arrayLineChanel = [];

    function startDrag(e) {

        if (e.target.classList.contains('input-chanel')) { // при наведении на точку канала
            let lineChanel = document.createElementNS('http://www.w3.org/2000/svg', 'line');
            lineChanel.setAttributeNS(null, 'x1', e.target.getAttributeNS(null,'cx'));
            lineChanel.setAttributeNS(null, 'y1', e.target.getAttributeNS(null,'cy'));
            lineChanel.setAttributeNS(null, 'stroke-width', 5);
            lineChanel.setAttributeNS(null,'stroke', '#000');
            e.target.parentNode.insertBefore(lineChanel, e.target);
            arrayLineChanel.push(lineChanel); // добавляем линию в массив
            selectLineChanel = true;

            console.log('startDrawLine');
        } else if (e.target.classList.contains('draggable')) { // при наведении на элемент
            selectedElement = e.target;
            initialiseDragging(e);
            console.log('startDragElement')
        } else if (e.target.parentNode.classList.contains('draggable-group')) {
            selectedElement = e.target.parentNode;
            initialiseDragging(e);
            console.log('startDragElement');
        }
    }
    function drag(e) {
        if(selectLineChanel){
            e.preventDefault();
            let coord = getMousePosition(e);
            arrayLineChanel[arrayLineChanel.length-1].setAttributeNS(null, 'x2',coord.x - offsetElement.x);
            arrayLineChanel[arrayLineChanel.length-1].setAttributeNS(null, 'y2',coord.y - offsetElement.y);
            console.log('drawLine:',coord.x, offsetElement.x);
        } else if (selectedElement) {
            e.preventDefault();
            let coord = getMousePosition(e);
            transformElement.setTranslate(coord.x - offsetElement.x, coord.y - offsetElement.y);
            console.log('drag');
        }
    }
    function endDrag(e) {
        if(selectLineChanel && !e.target.classList.contains('output-chanel')){
            arrayLineChanel[arrayLineChanel.length-1].remove();
            selectLineChanel = false;
            console.log('endDrawLine');
        }

        if(selectedElement){
            selectedElement = false;
            console.log('endDragElement');
        }

    }

    function getMousePosition(e) {
        let CTM = activeSVG.getScreenCTM(); // Возвращает DOMMatrix, представляющую матрицу, которая преобразует систему координат текущего элемента в систему координат окна просмотра SVG для фрагмента документа SVG.
        if (e.touches) { e = e.touches[0]; } // iPhone
        return {
            x: (e.clientX - CTM.e) / CTM.a,
            y: (e.clientY - CTM.f) / CTM.d
        }
    }

    function initialiseDragging(e) {
        offsetElement = getMousePosition(e);
        // Make sure the first transformElement on the element is a translate transformElement
        let transforms = selectedElement.transform.baseVal;
        if (transforms.length === 0 || transforms.getItem(0).type !== SVGTransform.SVG_TRANSFORM_TRANSLATE) {
            // Create an transformElement that translates by (0, 0)
            let translate = activeSVG.createSVGTransform();
            translate.setTranslate(0, 0);
            selectedElement.transform.baseVal.insertItemBefore(translate, 0);
        }
        // Get initial translation
        transformElement = transforms.getItem(0);
        offsetElement.x -= transformElement.matrix.e;
        offsetElement.y -= transformElement.matrix.f;
    }

})();

Последний раз редактировалось Vad0k, 30.11.2018 в 17:35.
Ответить с цитированием