fix(editor): enable outlining grouped strokes
This commit is contained in:
parent
28f7ef165b
commit
b1ad6d41e9
|
|
@ -66,7 +66,9 @@ function lineStrokePath(r: SkiaRenderer, node: SceneNode): Path | null {
|
|||
path.moveTo(0, 0)
|
||||
path.lineTo(node.width, node.height)
|
||||
const stroke = node.strokes.find((item) => item.visible)
|
||||
return path.stroke({ width: stroke?.weight ?? 1 })
|
||||
const outline = path.stroke({ width: stroke?.weight ?? 1 })
|
||||
path.delete()
|
||||
return outline
|
||||
}
|
||||
|
||||
function baseShapePath(r: SkiaRenderer, node: SceneNode): Path | null {
|
||||
|
|
@ -180,6 +182,15 @@ export function makeBooleanSourcePath(
|
|||
return path
|
||||
}
|
||||
|
||||
export function hasVisibleStrokeSourceNode(node: SceneNode, graph: SceneGraph): boolean {
|
||||
if (nodeHasVisibleStroke(node)) return true
|
||||
if (!canContainFlattenableChildren(node)) return false
|
||||
return node.childIds.some((childId) => {
|
||||
const child = graph.getNode(childId)
|
||||
return child?.visible === true && hasVisibleStrokeSourceNode(child, graph)
|
||||
})
|
||||
}
|
||||
|
||||
export function makeStrokeOutlinePath(
|
||||
r: SkiaRenderer,
|
||||
node: SceneNode,
|
||||
|
|
@ -220,7 +231,6 @@ export function makeStrokeOutlinePath(
|
|||
if (node.type === 'LINE') return path
|
||||
const outline = new r.ck.Path()
|
||||
addVisibleStrokeOutlines(outline, path, node)
|
||||
path.delete()
|
||||
return outline
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
export { canMakeBooleanSourceNode, canMakeBooleanSourcePath, nodeHasVisibleStroke } from './boolean'
|
||||
export {
|
||||
canMakeBooleanSourceNode,
|
||||
canMakeBooleanSourcePath,
|
||||
hasVisibleStrokeSourceNode,
|
||||
nodeHasVisibleStroke
|
||||
} from './boolean'
|
||||
export { SkiaRenderer, type RenderOverlays, type RulerTheme } from './renderer'
|
||||
export { getAbsolutePositionFull, getAbsoluteRotation, getWorldHandles } from './coordinate'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { canMakeBooleanSourceNode, nodeHasVisibleStroke } from '#core/canvas/boolean'
|
||||
import { canMakeBooleanSourceNode, hasVisibleStrokeSourceNode } from '#core/canvas/boolean'
|
||||
import { flattenNodesToVectorProps, outlineStrokeNodesToVectorProps } from '#core/canvas/flatten'
|
||||
import { restoreSubtree, snapshotSubtree } from '#core/editor/clipboard/subtree-history'
|
||||
import type { EditorContext } from '#core/editor/types'
|
||||
|
|
@ -76,7 +76,7 @@ export function outlineStrokeSelected(ctx: EditorContext, selectedNodes: SceneNo
|
|||
return flattenSelected(ctx, selectedNodes, {
|
||||
label: 'Outline stroke',
|
||||
canFlattenNode: (node) =>
|
||||
canMakeBooleanSourceNode(node, ctx.graph) && nodeHasVisibleStroke(node),
|
||||
canMakeBooleanSourceNode(node, ctx.graph) && hasVisibleStrokeSourceNode(node, ctx.graph),
|
||||
vectorPropsFactory: outlineStrokeNodesToVectorProps
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { computed } from 'vue'
|
||||
|
||||
import { canMakeBooleanSourceNode, nodeHasVisibleStroke } from '@open-pencil/core/canvas'
|
||||
import { canMakeBooleanSourceNode, hasVisibleStrokeSourceNode } from '@open-pencil/core/canvas'
|
||||
|
||||
import { useSelectionState } from '#vue/editor/selection-state/use'
|
||||
import { useSceneComputed } from '#vue/internal/scene-computed/use'
|
||||
|
|
@ -56,7 +56,9 @@ export function useSelectionCapabilities() {
|
|||
return (
|
||||
nodes.length > 0 &&
|
||||
nodes.every(
|
||||
(node) => nodeHasVisibleStroke(node) && canMakeBooleanSourceNode(node, editor.graph)
|
||||
(node) =>
|
||||
hasVisibleStrokeSourceNode(node, editor.graph) &&
|
||||
canMakeBooleanSourceNode(node, editor.graph)
|
||||
)
|
||||
)
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -94,6 +94,30 @@ describe('flattenSelected', () => {
|
|||
surface.delete()
|
||||
})
|
||||
|
||||
test('outlines stroked descendants inside groups', async () => {
|
||||
const { editor, surface } = await createEditorWithRenderer()
|
||||
const pageId = editor.state.currentPageId
|
||||
const rect = editor.graph.createNode('RECTANGLE', pageId, {
|
||||
x: 20,
|
||||
y: 30,
|
||||
width: 40,
|
||||
height: 30,
|
||||
fills: [TRANSPARENT],
|
||||
strokes: [{ type: 'SOLID', color: BLACK, weight: 8, opacity: 1, visible: true }]
|
||||
})
|
||||
editor.select([rect.id])
|
||||
editor.groupSelected()
|
||||
|
||||
editor.outlineStrokeSelected()
|
||||
|
||||
const [vectorId] = [...editor.state.selectedIds]
|
||||
const vector = editor.graph.getNode(vectorId)
|
||||
expect(vector?.type).toBe('VECTOR')
|
||||
expect(vector?.name).toBe('Outline stroke')
|
||||
expect(vector?.vectorNetwork?.vertices.length).toBeGreaterThan(0)
|
||||
surface.delete()
|
||||
})
|
||||
|
||||
test('does not outline fill-only shapes as strokes', async () => {
|
||||
const { editor, surface } = await createEditorWithRenderer()
|
||||
const pageId = editor.state.currentPageId
|
||||
|
|
|
|||
Loading…
Reference in a new issue