Запекание преобразуется в команды SVG Path Element

tl; dr summary : Предоставьте мне ресурсы или помогите исправить приведенный ниже код для преобразования команд пути для элементов SVG с помощью произвольная матрица.

подробности :
Я пишу библиотеку для преобразования любой произвольной формы SVG в элемент . У меня он работает, когда в иерархии нет элементов transform = "..." , но теперь я хочу запечь локальное преобразование объекта в самих командах данных пути .

Это в основном работает (код ниже) при работе с простыми командами moveto / lineto. Однако я не уверен в подходящем способе преобразования маркеров Безье или параметров arcTo.

Например, я могу преобразовать этот скругленный прямоугольник в :


--> 

И Я получаю верный результат при преобразовании без каких-либо закруглений:


--> 

Однако преобразование только координат x / y команд эллиптической дуги дает забавные результаты: Rounded rectangle with green blobs oozing from the corners outside the boundary
Пунктирная линия - это фактический преобразованный прямоугольник, зеленая заливка - это мой путь.

Ниже приведен код, который у меня есть (немного урезанный). У меня также есть тестовая страница , где я тестирую различные формы. Пожалуйста, помогите мне определить, как правильно преобразовать эллиптическую дугу и различные другие команды Безье с произвольной матрицей преобразования.

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

22
задан Phrogz 1 March 2011 в 17:24
поделиться