fix(canvas): support stretched layout grids
This commit is contained in:
parent
64e8b21949
commit
5fcd8e0e9c
|
|
@ -54,10 +54,12 @@ function gridGeometry(grid: RawLayoutGrid): GridGeometry | null {
|
|||
if (grid.visible === false) return null
|
||||
const count = grid.count ?? grid.numSections ?? 1
|
||||
const sectionSize = grid.sectionSize ?? 0
|
||||
if (count <= 0 || sectionSize <= 0) return null
|
||||
const alignment = rawGridAlignment(grid)
|
||||
if (!Number.isFinite(count) || count <= 0) return null
|
||||
if (alignment !== 'STRETCH' && sectionSize <= 0) return null
|
||||
return {
|
||||
pattern: rawGridPattern(grid),
|
||||
alignment: rawGridAlignment(grid),
|
||||
alignment,
|
||||
count,
|
||||
offset: grid.offset ?? 0,
|
||||
sectionSize,
|
||||
|
|
@ -66,8 +68,14 @@ function gridGeometry(grid: RawLayoutGrid): GridGeometry | null {
|
|||
}
|
||||
}
|
||||
|
||||
function gridSectionSize(nodeSize: number, grid: GridGeometry): number {
|
||||
if (grid.alignment !== 'STRETCH') return grid.sectionSize
|
||||
return (nodeSize - grid.offset * 2 - Math.max(0, grid.count - 1) * grid.gutterSize) / grid.count
|
||||
}
|
||||
|
||||
function gridStart(nodeSize: number, grid: GridGeometry): number {
|
||||
const span = grid.count * grid.sectionSize + Math.max(0, grid.count - 1) * grid.gutterSize
|
||||
const sectionSize = gridSectionSize(nodeSize, grid)
|
||||
const span = grid.count * sectionSize + Math.max(0, grid.count - 1) * grid.gutterSize
|
||||
if (grid.alignment === 'CENTER') return (nodeSize - span) / 2 + grid.offset
|
||||
if (grid.alignment === 'MAX') return nodeSize - span - grid.offset
|
||||
return grid.offset
|
||||
|
|
@ -79,18 +87,22 @@ function drawColumnGrid(
|
|||
node: SceneNode,
|
||||
grid: GridGeometry
|
||||
): void {
|
||||
const sectionSize = gridSectionSize(node.width, grid)
|
||||
if (sectionSize <= 0) return
|
||||
const x0 = gridStart(node.width, grid)
|
||||
for (let index = 0; index < grid.count; index++) {
|
||||
const x = x0 + index * (grid.sectionSize + grid.gutterSize)
|
||||
canvas.drawRect(r.ck.LTRBRect(x, 0, x + grid.sectionSize, node.height), r.auxFill)
|
||||
const x = x0 + index * (sectionSize + grid.gutterSize)
|
||||
canvas.drawRect(r.ck.LTRBRect(x, 0, x + sectionSize, node.height), r.auxFill)
|
||||
}
|
||||
}
|
||||
|
||||
function drawRowGrid(r: SkiaRenderer, canvas: Canvas, node: SceneNode, grid: GridGeometry): void {
|
||||
const sectionSize = gridSectionSize(node.height, grid)
|
||||
if (sectionSize <= 0) return
|
||||
const y0 = gridStart(node.height, grid)
|
||||
for (let index = 0; index < grid.count; index++) {
|
||||
const y = y0 + index * (grid.sectionSize + grid.gutterSize)
|
||||
canvas.drawRect(r.ck.LTRBRect(0, y, node.width, y + grid.sectionSize), r.auxFill)
|
||||
const y = y0 + index * (sectionSize + grid.gutterSize)
|
||||
canvas.drawRect(r.ck.LTRBRect(0, y, node.width, y + sectionSize), r.auxFill)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -216,6 +216,9 @@ function applyImportedCanvasFields(page: FigExportPage, canvasNc: KiwiNodeChange
|
|||
page.source.fig.rawNodeFields.backgroundPaints
|
||||
) as NodeChange['backgroundPaints']
|
||||
}
|
||||
if ('guides' in page.source.fig.rawNodeFields) {
|
||||
canvasNc.guides = structuredClone(page.source.fig.rawNodeFields.guides)
|
||||
}
|
||||
const strokeJoin = page.source.fig.rawNodeFields.strokeJoin
|
||||
if (typeof strokeJoin === 'string') canvasNc.strokeJoin = strokeJoin
|
||||
const strokeWeight = page.source.fig.rawNodeFields.strokeWeight
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ const RAW_FIELD_COVERAGE = {
|
|||
'fontVariantCommonLigatures',
|
||||
'fontVariantContextualLigatures',
|
||||
'fontVariations',
|
||||
'guides',
|
||||
'layoutGrids',
|
||||
'leadingTrim',
|
||||
'letterSpacing',
|
||||
|
|
@ -88,7 +89,6 @@ const RAW_FIELD_COVERAGE = {
|
|||
'gridRowAnchor',
|
||||
'gridRows',
|
||||
'gridRowsSizing',
|
||||
'guides',
|
||||
'handoffStatusMap',
|
||||
'isPageDivider',
|
||||
'isSoftDeleted',
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ describe('fig roundtrip source metadata', () => {
|
|||
blendMode: 'NORMAL'
|
||||
}
|
||||
]
|
||||
page.source.fig.rawNodeFields.guides = [
|
||||
{ axis: 'X', offset: 42 },
|
||||
{ axis: 'Y', offset: 84 }
|
||||
]
|
||||
page.source.fig.rawNodeFields.strokeJoin = 'BEVEL'
|
||||
page.source.fig.rawNodeFields.strokeWeight = 0
|
||||
|
||||
|
|
@ -72,6 +76,7 @@ describe('fig roundtrip source metadata', () => {
|
|||
expect(canvas?.strokeWeight).toBe(0)
|
||||
expect(canvas?.backgroundColor).toEqual(page.source.fig.rawNodeFields.backgroundColor)
|
||||
expect(canvas?.backgroundPaints).toEqual(page.source.fig.rawNodeFields.backgroundPaints)
|
||||
expect(canvas?.guides).toEqual(page.source.fig.rawNodeFields.guides)
|
||||
|
||||
expect(changes.get('4:4812')?.parentIndex?.position).toBe('~~~~~~~~~~1')
|
||||
expect(changes.get('4:4813')?.parentIndex?.position).toBe('~~~~~~~~~~3')
|
||||
|
|
|
|||
|
|
@ -44,6 +44,31 @@ describe('layout grid rendering', () => {
|
|||
expect(mockCalls(r.ck.LTRBRect)[3]).toEqual([208, 0, 256, 160])
|
||||
})
|
||||
|
||||
test('renders stretched column grids', () => {
|
||||
const r = createMockRenderer()
|
||||
const canvas = createMockCanvas()
|
||||
const node = nodeWithLayoutGrids([
|
||||
{
|
||||
pattern: 'COLUMNS',
|
||||
visible: true,
|
||||
color: { r: 1, g: 0, b: 0, a: 0.1 },
|
||||
gutterSize: 10,
|
||||
alignment: 'STRETCH',
|
||||
count: 3,
|
||||
offset: 15
|
||||
}
|
||||
])
|
||||
|
||||
drawLayoutGrids(r, canvas as Canvas, node)
|
||||
|
||||
expect(mockCalls(canvas.drawRect)).toHaveLength(3)
|
||||
expect(mockCalls(r.ck.LTRBRect)).toEqual([
|
||||
[15, 0, 78.33333333333334, 160],
|
||||
[88.33333333333334, 0, 151.66666666666669, 160],
|
||||
[161.66666666666669, 0, 225.00000000000003, 160]
|
||||
])
|
||||
})
|
||||
|
||||
test('renders Kiwi row grids', () => {
|
||||
const r = createMockRenderer()
|
||||
const canvas = createMockCanvas()
|
||||
|
|
|
|||
Loading…
Reference in a new issue