Так же как и всегда с помощью арифметики.
Посмотри какие X и Y у тебя есть и сложение каких даст нужный размер. |
Я забыл упомянуть, что необходимо использовать JS (ES6 >).
|
Цитата:
|
Я понимаю, что можно использовать арифметику и парсить аттрибут transform="translate(x y)" рекурсивно к родителю, но есть некоторые сложности, что не всегда я перемещаю элементы через translate, а иногда на некоторых узлах используя атрибуты x, y или cx, cy, а может вообще быть path... .
let outputChanel = e.target; // наведенный элемент let cx = +outputChanel.getAttributeNS(null, 'cx'); // получить [B]локальную[/B] координату относительно группы <g>, но т.к <g> может быть рекурсивное множество вложенных и относительно смещенных между собой. let cy = +outputChanel.getAttributeNS(null, 'cy'); let cc = getAbsoluteCoords(outputChanel, cx, cy); // вот хотелось реализовать данную функцию, которая будет брать матрицу и смотреть её параметр смещения по осям (matrix.e и matrix.f), НО относительно родительского <SVG> selectLineChanel.setAttributeNS(null, 'x2', cc.x); selectLineChanel.setAttributeNS(null, 'y2', cc.y); selectLineChanel = false; console.log('endDrawLine (ok)', cc.cx, cc.cy, e.target); а вот весь участок // Перетаскивание элементов (function () { let $document = $(document); const $svg = $('#main .canvas-svg'); // 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; function startDrag(e) { if (e.target.classList.contains('output-chanel')) { // при наведении на точку канала selectLineChanel = document.createElementNS('http://www.w3.org/2000/svg', 'line'); //initialiseDragging(e, selectLineChanel); let outputChanel = e.target; let coord = getMousePosition(e); selectLineChanel.setAttributeNS(null, 'x1', coord.x); selectLineChanel.setAttributeNS(null, 'y1', coord.y); selectLineChanel.setAttributeNS(null, 'stroke-width', 5); selectLineChanel.setAttributeNS(null,'stroke', '#000'); selectLineChanel.setAttributeNS(null,'stroke-linecap', 'round'); let groupChanelLine = activeSVG.querySelector('.chanel-lines'); groupChanelLine.appendChild(selectLineChanel); console.log('startDrawLine'); } else if (e.target.classList.contains('draggable')) { // при наведении на элемент selectedElement = e.target; initialiseDragging(e, selectedElement); console.log('startDragElement') } else if (e.target.parentNode.classList.contains('draggable-group')) { selectedElement = e.target.parentNode; initialiseDragging(e, selectedElement); console.log('startDragElement'); } } function drag(e) { e.preventDefault(); if(selectLineChanel){ let coord = getMousePosition(e); selectLineChanel.setAttributeNS(null, 'x2', coord.x); selectLineChanel.setAttributeNS(null, 'y2', coord.y); //console.log('drawLine: x =',coord.x, 'offsetElementX =', offsetElement.x, 'y =', coord.y, 'offsetElementY =', offsetElement.y); } else if (selectedElement) { let coord = getMousePosition(e); transformElement.setTranslate(coord.x - offsetElement.x, coord.y - offsetElement.y); console.log('drag'); } } function endDrag(e) { if (selectLineChanel) { console.log(e.target); if (e.target.classList.contains('input-chanel')) { let outputChanel = e.target; let cx = +outputChanel.getAttributeNS(null, 'cx'); let cy = +outputChanel.getAttributeNS(null, 'cy'); let cc = getAbsoluteCoords(outputChanel, cx, cy); selectLineChanel.setAttributeNS(null, 'x2', cc.x); selectLineChanel.setAttributeNS(null, 'y2', cc.y); selectLineChanel = false; console.log('endDrawLine (ok)', cc.cx, cc.cy, e.target); } else { selectLineChanel.remove(); selectLineChanel = false; console.log('endDrawLine (cancel)'); } } if(selectedElement){ selectedElement = false; console.log('endDragElement'); } } function convertCoords(element, x, y) { let offset = activeSVG.getBoundingClientRect(); let matrix = element.getScreenCTM(); return { x: (matrix.a * x) + (matrix.c * y) + matrix.e - offset.left, y: (matrix.b * x) + (matrix.d * y) + matrix.f - offset.top }; } function getAbsoluteCoords(element, x, y) { let offset = activeSVG.getBoundingClientRect(); let matrix = element.getScreenCTM(); return { x: (x + matrix.e), y: (y + matrix.f) }; } 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, element) { offsetElement = getMousePosition(e); let transforms = element.transform.baseVal; if (transforms.length === 0 || transforms.getItem(0).type !== SVGTransform.SVG_TRANSFORM_TRANSLATE) { let translate = activeSVG.createSVGTransform(); translate.setTranslate(0, 0); element.transform.baseVal.insertItemBefore(translate, 0); } transformElement = transforms.getItem(0); offsetElement.x -= transformElement.matrix.e; offsetElement.y -= transformElement.matrix.f; } })(); |
Цитата:
<body> <svg width="100%" height="100%" viewBox="0 0 1000 1000" preserveAspectRatio="xMidYMin slice" x="0" y="0" class="canvas-svg" tabindex="1"> <g transform="translate(100 100)"> <g transform="translate(100 100)"> <circle r="50" cx="25" cy="25" fill="yellow" /> </g> </g> <svg> <script> _=(document.querySelector("g")).getCTM(); alert ( "x="+_.e+" y="+_.f); </script> |
Я немного изучил характеристики данного примера
Физ. размер svg (x: 840px) в обозревателе, viewbox width: 1000px для svg => w:0.84 per 1px. Значение отображается x: 84,0px относительно вложенной группы не учитывая другие вложенности. По сути из примера я бы хотел бы получить значение: x: 100 + 100 + 25 независимо от уровня вложенности, без перевода viewbox в viewport. Возможно, я не сумел объяснить, что мне нужно... мне просто бы хотелось получить физ. абсолютное позиционирование внутри SVG <svg width="100%" height="100%" viewBox="0 0 1000 1000" preserveAspectRatio="xMidYMin slice" x="0" y="0" class="canvas-svg" tabindex="1"> <g transform="translate(100 100)"> <g transform="translate(100 100)"> <circle r="50" cx="25" cy="25" fill="yellow" /> </g> </g> <svg> function getAbsoluteCoords(element, x, y) { let matrix = element.getCTM(); return { x: (x + matrix.e), y: (y + matrix.f) }; } но данный пример возвращает относительно вложенной выше группы родителя, тоесть x: 84px. |
Vad0k,
здесь более демократичные правила общения, любой может задать вопрос или написать комментарий в созданной вами теме, я задал вопрос, получил ответ и поблагодарил, я ни коим образом не закрывал вашу тему. |
Я ни в коем случае не обвиняю никого. Я просто посчитал, что любой кто зайдет помочь, может увидеть сообщение "Спасибо", и подумать не вдаваясь в детали, что вопрос уже решен.
Помню, когда сидел на 4pda, не разрешали внутри темы создавать подтем вопросы(модерировали) (для меня это просто не привычно,... поймите меня тоже, правильно.). На случай прикреплю ветку ещё вопроса, может, кому поможет, если будет искать подобное решение. На случай спросил у англоязычной аудитории решение |
|
Эх... я уже попадал на данный пример из Реализация Drag and Drop
На основе него уже действительно хорошо разобрался и реализовал хороший drag & drop. У меня возникла сложность в другом моменте (при рисовании линий из рис. в теме). Когда я навожу на окружность, я пытаюсь взять абсолютные координаты окружности (чтобы линию привязать к центру окружности независимо, где человек щелкнет и потянет линию. но сама окружность находиться в группе (прямоугольник визуально), и если доставить координаты окружности, то получаю их относительно группы, что не подходит) (линии рисуются в другой группе, чтобы визуально отделить от блоков). На данный момент линии тянуться и располагаются где надо используя координаты курсора мыши и это выглядит немного некрасиво (тоесть человеку, для красоты, нужно щелкать идеально по центру окружности, а я бы хотел бы немного помочь удобней сделать, для этого нужно как-то получить эти координаты). Вижу решение одно, но оно мне не нравиться: это рекурсивно перебирать группы и смотреть их позиционирование распарсивая transform="translate" и суммируя в координату, но скорее это ресурсоемкая будет задачей, когда элементов будет больше <!-- СЕТКА --> <g class="grid"><rect width="100%" height="100%" fill="url(#grid)" /></g> <!-- СЕТКА --> <!-- СПИСОК КАНАЛОВ --> <g class="chanel-lines"></g> <!-- СПИСОК КАНАЛОВ --> <!-- УСТРОЙТСВА --> <g class="svg-schema"></g> <!-- УСТРОЙТСВА --> Внутри устройств лежат уже сами блоки обернуты в <g> с transform="translate(x y)"... В общем как-то так |
Решение найдено. Готовых методов нет в ES6+ для SVG2.0... Можно только рекурсией к родительскому элементу получить.
решение |
Цитата:
<head> <script type="text/javascript"> function test(){ let svgns = "http://www.w3.org/2000/svg"; let svg = document.getElementsByClassName('canvas-svg')[0]; let elm_g = document.getElementById("circle"); let CTM = svg.getScreenCTM(); let elm_g_pos_x = (elm_g.getBoundingClientRect().left - CTM.e) / CTM.a; let path_x = document.createElementNS(svgns, "path"); path_x.setAttributeNS(null, "d", "M"+elm_g_pos_x+",0 v1000"); path_x.setAttributeNS(null, "fill", "transparent"); path_x.setAttributeNS(null, "stroke", "black"); svg.appendChild(path_x); let elm_g_pos_y = (elm_g.getBoundingClientRect().top - CTM.f) / CTM.d; let path_y = document.createElementNS(svgns, "path"); path_y.setAttributeNS(null, "d", "M0,"+elm_g_pos_y+" h1000"); path_y.setAttributeNS(null, "fill", "transparent"); path_y.setAttributeNS(null, "stroke", "black"); svg.appendChild(path_y); let elm_g_pos_cx = elm_g_pos_x + elm_g.getAttributeNS(null, "r") * 1; let path_cx = document.createElementNS(svgns, "path"); path_cx.setAttributeNS(null, "d", "M"+elm_g_pos_cx+",0 v1000"); path_cx.setAttributeNS(null, "fill", "transparent"); path_cx.setAttributeNS(null, "stroke", "black"); path_cx.setAttributeNS(null, "stroke-dasharray", "4"); svg.appendChild(path_cx); let elm_g_pos_cy = elm_g_pos_y + elm_g.getAttributeNS(null, "r") * 1; let path_cy = document.createElementNS(svgns, "path"); path_cy.setAttributeNS(null, "d", "M0,"+elm_g_pos_cy+" h1000"); path_cy.setAttributeNS(null, "fill", "transparent"); path_cy.setAttributeNS(null, "stroke", "black"); path_cy.setAttributeNS(null, "stroke-dasharray", "4"); svg.appendChild(path_cy); } window.onload = test; </script> </head> <body> <svg width="100%" height="100%" viewBox="0 0 1000 1000" preserveAspectRatio="xMidYMin slice" x="0" y="0" class="canvas-svg" tabindex="1"> <g transform="translate(100 100)"> <g transform="translate(100 100)"> <circle id="circle" r="50" cx="25" cy="25" fill="yellow" /> </g> </g> <svg> </body> |
RX200,
на всякий случай getBoundingClientRect() и run [html run] ... минимальный код страницы с вашей проблемой [/html] О том, как вставить в сообщение исполняемый javascript и html-код, а также о дополнительных возможностях форматирования - читайте http://javascript.ru/formatting. |
рони,
Исправил. А вот красным он не те строки почему то выделяет. от *!* и */!* пришлось отказаться) |
Цитата:
*!* и */!* 123 *!* и */!* |
Цитата:
|
Часовой пояс GMT +3, время: 18:25. |