src/render/appendChild.js
function transform(node, viewport) {
  let trans = getTranslation(viewport);

  // Let SVG natively transform the element
  node.setAttribute('transform', `scale(${viewport.scale}) rotate(${viewport.rotation}) translate(${trans.x}, ${trans.y})`);
  
  // Manually adjust x/y for nested SVG nodes
  if (!isFirefox && node.nodeName.toLowerCase() === 'svg') {
    node.setAttribute('x', parseInt(node.getAttribute('x'), 10) * viewport.scale);
    node.setAttribute('y', parseInt(node.getAttribute('y'), 10) * viewport.scale);

    let x = parseInt(node.getAttribute('x', 10));
    let y = parseInt(node.getAttribute('y', 10));
    let width = parseInt(node.getAttribute('width'), 10);
    let height = parseInt(node.getAttribute('height'), 10);
    let path = node.querySelector('path');
    let svg = path.parentNode;
   
    // Scale width/height
    [node, svg, path, node.querySelector('rect')].forEach((n) => {
      n.setAttribute('width', parseInt(n.getAttribute('width'), 10) * viewport.scale);
      n.setAttribute('height', parseInt(n.getAttribute('height'), 10) * viewport.scale);
    });

    // Transform path but keep scale at 100% since it will be handled natively
    transform(path, objectAssign({}, viewport, { scale: 1 }));
    
    switch(viewport.rotation % 360) {
      case 90:
        node.setAttribute('x', viewport.width - y - width);
        node.setAttribute('y', x);
        svg.setAttribute('x', 1);
        svg.setAttribute('y', 0);
        break;
      case 180:
        node.setAttribute('x', viewport.width - x - width);
        node.setAttribute('y', viewport.height - y - height);
        svg.setAttribute('y', 2);
        break;
      case 270:
        node.setAttribute('x', y);
        node.setAttribute('y', viewport.height - x - height);
        svg.setAttribute('x', -1);
        svg.setAttribute('y', 0);
        break;
    }
  }

  return node;
}
function transform(node, viewport) {
  let trans = getTranslation(viewport);

  // Let SVG natively transform the element
  node.setAttribute('transform', `scale(${viewport.scale}) rotate(${viewport.rotation}) translate(${trans.x}, ${trans.y})`);
  
  // Manually adjust x/y for nested SVG nodes
  if (!isFirefox && node.nodeName.toLowerCase() === 'svg') {
    node.setAttribute('x', parseInt(node.getAttribute('x'), 10) * viewport.scale);
    node.setAttribute('y', parseInt(node.getAttribute('y'), 10) * viewport.scale);

    let x = parseInt(node.getAttribute('x', 10));
    let y = parseInt(node.getAttribute('y', 10));
    let width = parseInt(node.getAttribute('width'), 10);
    let height = parseInt(node.getAttribute('height'), 10);
    let path = node.querySelector('path');
    let svg = path.parentNode;
   
    // Scale width/height
    [node, svg, path, node.querySelector('rect')].forEach((n) => {
      n.setAttribute('width', parseInt(n.getAttribute('width'), 10) * viewport.scale);
      n.setAttribute('height', parseInt(n.getAttribute('height'), 10) * viewport.scale);
    });

    // Transform path but keep scale at 100% since it will be handled natively
    transform(path, objectAssign({}, viewport, { scale: 1 }));
    
    switch(viewport.rotation % 360) {
      case 90:
        node.setAttribute('x', viewport.width - y - width);
        node.setAttribute('y', x);
        svg.setAttribute('x', 1);
        svg.setAttribute('y', 0);
        break;
      case 180:
        node.setAttribute('x', viewport.width - x - width);
        node.setAttribute('y', viewport.height - y - height);
        svg.setAttribute('y', 2);
        break;
      case 270:
        node.setAttribute('x', y);
        node.setAttribute('y', viewport.height - x - height);
        svg.setAttribute('x', -1);
        svg.setAttribute('y', 0);
        break;
    }
  }

  return node;
}
function transform ( node , viewport ) { let trans = getTranslation ( viewport ) ; // Let SVG natively transform the element node . setAttribute ( 'transform' , ` ${ viewport . scale } ${ viewport . rotation } ${ trans . x } ${ trans . y } ` ) ; // Manually adjust x/y for nested SVG nodes if ( ! isFirefox && node . nodeName . toLowerCase ( ) === 'svg' ) { node . setAttribute ( 'x' , parseInt ( node . getAttribute ( 'x' ) , 10 ) * viewport . scale ) ; node . setAttribute ( 'y' , parseInt ( node . getAttribute ( 'y' ) , 10 ) * viewport . scale ) ; let x = parseInt ( node . getAttribute ( 'x' , 10 ) ) ; let y = parseInt ( node . getAttribute ( 'y' , 10 ) ) ; let width = parseInt ( node . getAttribute ( 'width' ) , 10 ) ; let height = parseInt ( node . getAttribute ( 'height' ) , 10 ) ; let path = node . querySelector ( 'path' ) ; let svg = path . parentNode ; // Scale width/height [ node , svg , path , node . querySelector ( 'rect' ) ] . forEach ( ( n ) => { n . setAttribute ( 'width' , parseInt ( n . getAttribute ( 'width' ) , 10 ) * viewport . scale ) ; n . setAttribute ( 'height' , parseInt ( n . getAttribute ( 'height' ) , 10 ) * viewport . scale ) ; } ) ; // Transform path but keep scale at 100% since it will be handled natively transform ( path , objectAssign ( { } , viewport , { scale : 1 } ) ) ; switch ( viewport . rotation % 360 ) { case 90 : node . setAttribute ( 'x' , viewport . width - y - width ) ; node . setAttribute ( 'y' , x ) ; svg . setAttribute ( 'x' , 1 ) ; svg . setAttribute ( 'y' , 0 ) ; break ; case 180 : node . setAttribute ( 'x' , viewport . width - x - width ) ; node . setAttribute ( 'y' , viewport . height - y - height ) ; svg . setAttribute ( 'y' , 2 ) ; break ; case 270 : node . setAttribute ( 'x' , y ) ; node . setAttribute ( 'y' , viewport . height - x - height ) ; svg . setAttribute ( 'x' , - 1 ) ; svg . setAttribute ( 'y' , 0 ) ; break ; } } return node ; }
Transform the rotation and scale of a node using SVG's native transform attribute.

@param {Node} node The node to be transformed
@param {Object} viewport The page's viewport data
@return {Node}
Transform the rotation and scale of a node using SVG s native transform attribute .