fix(io): ignore inside stroke geometry bounds

This commit is contained in:
Danila Poyarkov 2026-05-18 13:52:45 +03:00
parent ff85febddb
commit 945560b5a9
3 changed files with 36 additions and 14 deletions

View file

@ -327,9 +327,12 @@ export function nodeVisualBounds(
maxY: base.y + base.height
}
const hasNonInsideStroke = node.strokes?.some(
(stroke) => stroke.visible && stroke.align !== 'INSIDE'
)
const localGeometry = geometryBlobBounds([
...(node.fillGeometry ?? []),
...(node.type === 'COMPONENT_SET' ? [] : (node.strokeGeometry ?? []))
...(hasNonInsideStroke ? (node.strokeGeometry ?? []) : [])
])
if (localGeometry) {
bounds = unionVisualBounds(bounds, transformedLocalBounds(node, localGeometry, abs)) ?? bounds

View file

@ -176,7 +176,8 @@ async function exportOpenPencilSubset(indices: number[], path: string): Promise<
}
try {
const nodeIds = indices.map((index) => childIds[index])
const nodeIds =
rootNode.type === 'CANVAS' ? indices.map((index) => childIds[index]) : [rootNode.id]
const data = await headlessRenderNodes(graph, page.id, nodeIds, {
scale,
format: 'PNG',

View file

@ -337,7 +337,7 @@ describe('computeVisualBounds', () => {
expect(multiStroke.height).toBe(noEffects.height + 8)
})
test('component set stroke geometry does not expand export bounds', () => {
test('inside stroke geometry does not expand export bounds', () => {
const strokeGeometry = [
{
commandsBlob: commandsBlobFromPoints([
@ -347,39 +347,57 @@ describe('computeVisualBounds', () => {
}
]
const nodes = {
set: {
id: 'set',
type: 'COMPONENT_SET',
inside: {
id: 'inside',
type: 'COMPONENT',
width: 100,
height: 50,
visible: true,
strokes: [
{
weight: 1,
visible: true,
align: 'INSIDE' as const,
color: { r: 0, g: 0, b: 0, a: 1 },
opacity: 1
}
],
strokeGeometry,
childIds: []
},
frame: {
id: 'frame',
outside: {
id: 'outside',
type: 'FRAME',
width: 100,
height: 50,
visible: true,
strokes: [
{
weight: 1,
visible: true,
align: 'OUTSIDE' as const,
color: { r: 0, g: 0, b: 0, a: 1 },
opacity: 1
}
],
strokeGeometry,
childIds: []
}
}
const componentSetBounds = computeDescendantVisualBounds(
['set'],
const insideBounds = computeDescendantVisualBounds(
['inside'],
(id) => nodes[id as keyof typeof nodes],
() => ({ x: 10, y: 20 })
)
const frameBounds = computeDescendantVisualBounds(
['frame'],
const outsideBounds = computeDescendantVisualBounds(
['outside'],
(id) => nodes[id as keyof typeof nodes],
() => ({ x: 10, y: 20 })
)
expect(componentSetBounds).toEqual({ minX: 10, minY: 20, maxX: 110, maxY: 70 })
expect(frameBounds).toEqual({ minX: 9, minY: 19, maxX: 111, maxY: 71 })
expect(insideBounds).toEqual({ minX: 10, minY: 20, maxX: 110, maxY: 70 })
expect(outsideBounds).toEqual({ minX: 9, minY: 19, maxX: 111, maxY: 71 })
})
test('multiple effects accumulate directional overflow', () => {