Получить границы повернутого элемента SVG в пикселях экрана?

Я пытаюсь найти лучший способ получить ограничивающую рамку произвольного элемента SVG в пикселях экрана, чтобы правильно наложить элемент HTML. До сих пор мой подход заключался в том, чтобы использовать .getBBox() и .getCTM() для получения ограничивающей рамки объекта и матрицы преобразования, а затем применять преобразование к точкам ограничивающей рамки, как описано в принятом ответе на этот вопрос.

// get the element
var el = $(selector)[0],
    pt = $(selector).closest('svg')[0].createSVGPoint();

// get the bounding box and matrix
var bbox = el.getBBox(),
    matrix = el.getScreenCTM();

pt.x = bbox.x;
pt.y = bbox.y;
var nw = pt.matrixTransform(matrix);
pt.x += bbox.width;
pt.y += bbox.height;
var se = pt.matrixTransform(matrix);

// make a div in the screen space around the object
var $div = $('<div class="bbox"/>').css({
        left: nw.x,
        top: nw.y,
        width: se.x - nw.x,
        height: se.y - nw.y
    })
    .appendTo('body');

Вы можете увидеть мой тест здесь: http://jsfiddle.net/nrabinowitz/zr2jX/

Однако, как показывает тест, этот подход не работает, когда в преобразование включено вращение — похоже, что ограничивающая рамка вычисляется до поворота, поэтому получение углов повернутой ограничивающей рамки не работает.

Как правильно рассчитать невращающуюся ограничивающую рамку преобразованных элементов?


person nrabinowitz    schedule 30.08.2012    source источник


Ответы (2)


После некоторых исследований, вот лучшие варианты, которые я нашел:

  • getBoundingClientRect() хорошо работает с элементами SVG в современных браузерах, и довольно быстро, но результаты могут несколько отличаться от платформы к платформе (особенно если у вас значительная ширина хода). Однако, по мнению @Sergiu, это не учитывает изменения формы и дает вам границы повернутой ограничительной рамки, а не фактический путь или объект, поэтому он может быть довольно неточным - см. критику здесь. Пример скрипта: http://jsfiddle.net/stevenbenner/6M5zf/

  • Моя главная цель состояла в том, чтобы получить позиционные углы и середины ограничивающего прямоугольника, и в конце концов я решил, что использование повернутой ограничивающей рамки может быть даже предпочтительнее «реальной» ограничивающей рамки повернутой формы. Я смог сделать это, используя подход, описанный выше, а затем чередуя точки, чтобы максимально приблизиться к позициям N, S, E, W. Вы можете увидеть мой пример скрипта здесь: http://jsfiddle.net/nrabinowitz/sPtzV/

person nrabinowitz    schedule 05.09.2012

Я не думаю, что это возможно, потому что перекос и поворот связаны с изменением профиля или того, как выглядят проекции фигуры на две оси.

Вы можете вычислить матрицу преобразования, которая будет игнорировать вращающуюся часть CTM, но тогда у вас нет никакой гарантии, что новый BBox все еще будет окружать ваш повернутый элемент. Например, если у вас есть круг, вращение не влияет на размеры ограничивающей рамки. Если, с другой стороны, у вас есть ромб в качестве базового пути, и вы поворачиваете его на 45 градусов, так что в итоге он становится просто квадратом, ограничительная рамка другая: первоначально вы измеряли диагональ, а теперь вам нужно получить ограничительную рамку, которая измеряет длину стороны. Как бы вы ни использовали CTM, вы не сможете учесть изменение формы.

Итак, ротация на самом деле очень важна, игнорировать ее нельзя; но только локальная ограничивающая рамка и матрица преобразования ничего не говорят о том, как изменяется профиль формы при его вращении.

person Sergiu Dumitriu    schedule 30.08.2012
comment
Это хороший момент, но а) было бы лучше, если бы я мог получить основные границы повернутой ограничивающей рамки, и б) я надеюсь, что есть что-то, чего я не знаю в SVG API, что может дать мне новую границу коробка на основе преобразованной формы. - person nrabinowitz; 31.08.2012
comment
Теоретически вы могли бы использовать checkEnclosure для выполнения своего рода бинарного поиска наименьший прямоугольник, который полностью охватывает ваш элемент. К сожалению, это еще не реализовано в Firefox. - person Sergiu Dumitriu; 31.08.2012