Canvas在含transform属性的g元素内无法渲染问题求助
<g> Elements Hey there! Let's dig into why your Canvas (inside the <foreignObject>) isn't rendering right when nested inside transformed <g> elements, and how to fix it.
The Root of the Problem
When you nest multiple <g> elements with transform properties, SVG stacks those coordinate transformations. Your current code has two nested translate() transforms:
- Outer
<g>:translate(300, 20) - Inner
<g>:translate(250, 50)
This means your <foreignObject> is actually positioned at (300+250, 20+50) = (550,70) relative to the SVG viewport. But since you didn't set explicit x/y attributes on the <foreignObject>, some browsers miscalculate the rendering context for the embedded HTML (your #globe div/Canvas), leading to clipping, offset rendering, or invisible content.
Step-by-Step Solutions
1. Simplify Transform Hierarchy
Combine nested transforms to eliminate coordinate confusion. Instead of stacking two <g> elements with separate transforms, merge the values into a single transform:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" id="sake" stroke-opacity="0.3" style="width: 100%; height: 100%;"> <g id="1" class="squaregroup" transform="translate(550, 70)"> <!-- Removed inner transformed <g> --> <foreignObject id="fo_1" x="0" y="0" style="width: 500px; height:500px;"> <div id="globe" style="width:100%; height:100%;"></div> </foreignObject> </g> </svg>
2. Explicitly Set <foreignObject> Position
Always add x and y attributes to <foreignObject> to define its position relative to its parent element. This removes ambiguity for the browser when calculating where to render the embedded HTML content.
3. Match Canvas Dimensions to <foreignObject>'s Actual Size
If you're dynamically creating a Canvas inside #globe, make sure its pixel dimensions match the actual rendered size of the <foreignObject> (not just the percentage-based CSS). Use getBoundingClientRect() to grab accurate values:
const foreignObj = document.getElementById('fo_1'); const globeDiv = document.getElementById('globe'); const canvas = document.createElement('canvas'); // Get the actual rendered size of the foreignObject const rect = foreignObj.getBoundingClientRect(); canvas.width = rect.width; canvas.height = rect.height; globeDiv.appendChild(canvas); // Now draw on your canvas as usual
Why This Works
By simplifying transforms and explicitly defining positions, you eliminate the browser's guesswork when mapping the SVG coordinate system to the embedded HTML's rendering context. Matching the Canvas to the <foreignObject>'s actual size ensures your drawing doesn't get stretched, clipped, or offset.
内容的提问来源于stack exchange,提问作者Andy Shepherd

