Skip to content

Commit

Permalink
fix: use getCTM() for nested SVGs so transforms stack correctly
Browse files Browse the repository at this point in the history
Previously nested `<svg>`s would not be layouted correctly because the getScreenCTM()
matrices would stack incorrectly.
  • Loading branch information
felixfbecker committed Apr 17, 2021
1 parent e302413 commit a9309e4
Showing 1 changed file with 18 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,25 @@ export function handleSvgElement(element: SVGElement, context: SvgTraversalConte
continue
}

// When this function is called on the original DOM, we want getScreenCTM() to map it to the DOM
// coordinate system. When this function is called from inlineResources() the <svg> is already embedded
// into the output <svg>. In that case the output SVG already has a viewBox, and the coordinate system
// of the SVG is not equal to the coordinate system of the screen, therefor we need to use getCTM() to
// map it into the output SVG's coordinate system.
let viewBoxTransformMatrix =
child.ownerDocument !== context.svgDocument ? child.getScreenCTM()! : child.getCTM()!
// When this function is called on an inline <svg> element in the original DOM, we want
// getScreenCTM() to map it to the DOM coordinate system. When this function is called from
// inlineResources() the <svg> is already embedded into the output <svg>. In that case the output
// SVG already has a viewBox, and the coordinate system of the SVG is not equal to the coordinate
// system of the screen, therefor we need to use getCTM() to map it into the output SVG's
// coordinate system.
child.ownerDocument !== context.svgDocument &&
// When we inline an SVG, we put a transform on it for the getScreenCTM(). When that SVG also
// contains another SVG, the inner SVG should just get transformed relative to the outer SVG, not
// relative to the screen, because the transforms will stack in the output SVG.
!element.parentElement?.closest('svg')
? child.getScreenCTM()
: child.getCTM()

// This should only be null if the <svg> is `display: none`
if (!viewBoxTransformMatrix) {
break
}

// Make sure to handle a child that already has a transform. That transform should only apply to the
// child, not to the entire SVG contents, so we need to calculate it out.
Expand Down

0 comments on commit a9309e4

Please sign in to comment.