Я понимаю, что можно использовать арифметику и парсить аттрибут 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;
}
})();