tl; dr summary : Предоставьте мне ресурсы или помогите исправить приведенный ниже код для преобразования команд пути для элементов SVG
с помощью произвольная матрица.
подробности :
Я пишу библиотеку для преобразования любой произвольной формы SVG в элемент
. У меня он работает, когда в иерархии нет элементов transform = "..."
, но теперь я хочу запечь локальное преобразование объекта в самих командах данных пути .
Это в основном работает (код ниже) при работе с простыми командами moveto / lineto. Однако я не уверен в подходящем способе преобразования маркеров Безье или параметров arcTo.
Например, я могу преобразовать этот скругленный прямоугольник в
:
-->
И Я получаю верный результат при преобразовании без каких-либо закруглений:
-->
Однако преобразование только координат x / y команд эллиптической дуги дает забавные результаты:
Пунктирная линия - это фактический преобразованный прямоугольник, зеленая заливка - это мой путь.
Ниже приведен код, который у меня есть (немного урезанный). У меня также есть тестовая страница , где я тестирую различные формы. Пожалуйста, помогите мне определить, как правильно преобразовать эллиптическую дугу
и различные другие команды Безье с произвольной матрицей преобразования.
function flattenToPaths(el,transform,svg){
if (!svg) svg=el; while(svg && svg.tagName!='svg') svg=svg.parentNode;
var doc = el.ownerDocument;
var svgNS = svg.getAttribute('xmlns');
// Identity transform if nothing passed in
if (!transform) transform= svg.createSVGMatrix();
// Calculate local transform matrix for the object
var localMatrix = svg.createSVGMatrix();
for (var xs=el.transform.baseVal,i=xs.numberOfItems-1;i>=0;--i){
localMatrix = xs.getItem(i).matrix.multiply(localMatrix);
}
// Transform the local transform by whatever was recursively passed in
transform = transform.multiply(localMatrix);
var path = doc.createElementNS(svgNS,'path');
switch(el.tagName){
case 'rect':
path.setAttribute('stroke',el.getAttribute('stroke'));
var x = el.getAttribute('x')*1, y = el.getAttribute('y')*1,
w = el.getAttribute('width')*1, h = el.getAttribute('height')*1,
rx = el.getAttribute('rx')*1, ry = el.getAttribute('ry')*1;
if (rx && !el.hasAttribute('ry')) ry=rx;
else if (ry && !el.hasAttribute('rx')) rx=ry;
if (rx>w/2) rx=w/2;
if (ry>h/2) ry=h/2;
path.setAttribute('d',
'M'+(x+rx)+','+y+
'L'+(x+w-rx)+','+y+
((rx||ry) ? ('A'+rx+','+ry+',0,0,'+(rx*ry<0?0:1)+','+(x+w)+','+(y+ry)) : '') +
'L'+(x+w)+','+(y+h-ry)+
((rx||ry) ? ('A'+rx+','+ry+',0,0,'+(rx*ry<0?0:1)+','+(x+w-rx)+','+(y+h)) : '')+
'L'+(x+rx)+','+(y+h)+
((rx||ry) ? ('A'+rx+','+ry+',0,0,'+(rx*ry<0?0:1)+','+x+','+(y+h-ry)) : '')+
'L'+x+','+(y+ry)+
((rx||ry) ? ('A'+rx+','+ry+',0,0,'+(rx*ry<0?0:1)+','+(x+rx)+','+y) : '')
);
break;
case 'circle':
var cx = el.getAttribute('cx')*1, cy = el.getAttribute('cy')*1,
r = el.getAttribute('r')*1, r0 = r/2+','+r/2;
path.setAttribute('d','M'+cx+','+(cy-r)+' A'+r0+',0,0,0,'+cx+','+(cy+r)+' '+r0+',0,0,0,'+cx+','+(cy-r) );
break;
case 'ellipse':
var cx = el.getAttribute('cx')*1, cy = el.getAttribute('cy')*1,
rx = el.getAttribute('rx')*1, ry = el.getAttribute('ry')*1;
path.setAttribute('d','M'+cx+','+(cy-ry)+' A'+rx+','+ry+',0,0,0,'+cx+','+(cy+ry)+' '+rx+','+ry+',0,0,0,'+cx+','+(cy-ry) );
break;
case 'line':
var x1=el.getAttribute('x1')*1, y1=el.getAttribute('y1')*1,
x2=el.getAttribute('x2')*1, y2=el.getAttribute('y2')*1;
path.setAttribute('d','M'+x1+','+y1+'L'+x2+','+y2);
break;
case 'polyline':
case 'polygon':
for (var i=0,l=[],pts=el.points,len=pts.numberOfItems;i