05.12.2018, 13:20
|
Новичок на форуме
|
|
Регистрация: 30.11.2018
Сообщений: 8
|
|
Абсолютное (translate) смешение элемента <g> внутри SVG
Доброго времени суток, форумчане.
Подскажите, как правильно получить координаты элемента группы <g> и элементов вложенных в эту группу относительно 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>
Хотелось бы получить абсолютные координаты окружности относительно родительского SVG, а не относительные относительно контейнера используя JS(ES6+ )<g>.
Может это поможет, что я имею ввиду.
Последний раз редактировалось Vad0k, 05.12.2018 в 17:32.
|
|
05.12.2018, 14:03
|
|
Профессор
|
|
Регистрация: 07.03.2011
Сообщений: 1,138
|
|
Так же как и всегда с помощью арифметики.
Посмотри какие X и Y у тебя есть и сложение каких даст нужный размер.
|
|
05.12.2018, 14:11
|
Новичок на форуме
|
|
Регистрация: 30.11.2018
Сообщений: 8
|
|
Я забыл упомянуть, что необходимо использовать JS (ES6 >).
Последний раз редактировалось Vad0k, 05.12.2018 в 14:43.
|
|
05.12.2018, 14:33
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,109
|
|
Сообщение от MallSerg
|
Так же как и всегда с помощью арифметики.
Посмотри какие X и Y у тебя есть и сложение каких даст нужный размер.
|
можно пример?
|
|
05.12.2018, 15:20
|
Новичок на форуме
|
|
Регистрация: 30.11.2018
Сообщений: 8
|
|
Я понимаю, что можно использовать арифметику и парсить аттрибут 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;
}
})();
Последний раз редактировалось Vad0k, 05.12.2018 в 15:30.
|
|
05.12.2018, 15:59
|
|
Профессор
|
|
Регистрация: 07.03.2011
Сообщений: 1,138
|
|
Сообщение от рони
|
можно пример?
|
Не думаю что это поможет автору. К тому же в документации есть функция которая сама делает сложение и масштабирование для ленивых.
<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>
Последний раз редактировалось MallSerg, 05.12.2018 в 16:02.
|
|
05.12.2018, 16:44
|
Новичок на форуме
|
|
Регистрация: 30.11.2018
Сообщений: 8
|
|
Я немного изучил характеристики данного примера
Физ. размер 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, 05.12.2018 в 17:33.
|
|
05.12.2018, 18:22
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,109
|
|
Vad0k,
здесь более демократичные правила общения, любой может задать вопрос или написать комментарий в созданной вами теме, я задал вопрос, получил ответ и поблагодарил, я ни коим образом не закрывал вашу тему.
|
|
05.12.2018, 18:33
|
Новичок на форуме
|
|
Регистрация: 30.11.2018
Сообщений: 8
|
|
Я ни в коем случае не обвиняю никого. Я просто посчитал, что любой кто зайдет помочь, может увидеть сообщение "Спасибо", и подумать не вдаваясь в детали, что вопрос уже решен.
Помню, когда сидел на 4pda, не разрешали внутри темы создавать подтем вопросы(модерировали) (для меня это просто не привычно,... поймите меня тоже, правильно.).
На случай прикреплю ветку ещё вопроса, может, кому поможет, если будет искать подобное решение.
На случай спросил у англоязычной аудитории решение
Последний раз редактировалось Vad0k, 05.12.2018 в 18:37.
|
|
05.12.2018, 18:34
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,109
|
|
|
|
|
|