From 8a0633af62ecd624bb04cc205e9cd90b2cb7446b Mon Sep 17 00:00:00 2001 From: Chen <99816898+donteatfriedrice@users.noreply.github.com> Date: Mon, 15 Jan 2024 17:24:27 +0800 Subject: [PATCH] fix(edgeless): wrong transparent shape overlay (#5990) --- packages/blocks/src/_common/icons/edgeless.ts | 26 ++-------- .../components/toolbar/shape/shape-menu.ts | 27 +++------- .../toolbar/shape/shape-tool-button.ts | 10 +++- .../edgeless/controllers/tools/shape-tool.ts | 26 +++++++--- .../src/page-block/edgeless/utils/consts.ts | 11 +++-- .../page-block/edgeless/utils/tool-overlay.ts | 49 ++++++++++++++----- .../surface-block/managers/edit-session.ts | 10 ++-- tests/edgeless/shape.spec.ts | 4 +- 8 files changed, 94 insertions(+), 69 deletions(-) diff --git a/packages/blocks/src/_common/icons/edgeless.ts b/packages/blocks/src/_common/icons/edgeless.ts index 96c2503e25c4..10259e2c9fa1 100644 --- a/packages/blocks/src/_common/icons/edgeless.ts +++ b/packages/blocks/src/_common/icons/edgeless.ts @@ -1912,13 +1912,7 @@ export const rectSvg = html` - + `; export const ellipseSvg = html` - + `; export const triangleSvg = html` - + `; export const diamondSvg = html` @@ -1969,7 +1953,7 @@ export const roundedSvg = html` { if (this.edgeless.edgelessTool.type !== 'shape') return; - const { shapeStyle } = this; - const props: Record = { strokeColor }; - if (shapeStyle === ShapeStyle.General) { - props.fillColor = strokeColor.replace( - LINE_COLOR_PREFIX, - SHAPE_COLOR_PREFIX - ); - } + const fillColor = strokeColor.replace( + LINE_COLOR_PREFIX, + SHAPE_COLOR_PREFIX + ); + const filled = !isTransparent(fillColor); + props.fillColor = fillColor; + props.filled = filled; this.onChange(props); }; private _setShapeStyle = (shapeStyle: ShapeStyle) => { if (this.edgeless.edgelessTool.type !== 'shape') return; - const { strokeColor } = this; - - let fillColor; - if (shapeStyle === ShapeStyle.General) { - fillColor = strokeColor.replace(LINE_COLOR_PREFIX, SHAPE_COLOR_PREFIX); - } else { - fillColor = DEFAULT_SHAPE_FILL_COLOR; - } this.onChange({ shapeStyle, - fillColor, }); }; diff --git a/packages/blocks/src/page-block/edgeless/components/toolbar/shape/shape-tool-button.ts b/packages/blocks/src/page-block/edgeless/components/toolbar/shape/shape-tool-button.ts index 355393e0c731..c93e2eb1696c 100644 --- a/packages/blocks/src/page-block/edgeless/components/toolbar/shape/shape-tool-button.ts +++ b/packages/blocks/src/page-block/edgeless/components/toolbar/shape/shape-tool-button.ts @@ -21,6 +21,7 @@ import { } from '../../../../../surface-block/elements/shape/consts.js'; import { ShapeStyle } from '../../../../../surface-block/index.js'; import { ShapeToolController } from '../../../controllers/tools/shape-tool.js'; +import { isTransparent } from '../../panel/color-panel.js'; import { getTooltipWithShortcut } from '../../utils.js'; import { createPopper } from '../common/create-popper.js'; import { EdgelessToolButton } from '../edgeless-toolbar-button.js'; @@ -221,7 +222,14 @@ export class EdgelessShapeToolButton extends EdgelessToolButton<
${repeat(shapes, (shape, index) => { return html` { createOverlay() { this.clearOverlay(); const options = SHAPE_OVERLAY_OPTIONS; - const computedStyle = getComputedStyle(this._edgeless); const attributes = this._edgeless.surface.service.editSession.getLastProps('shape'); - options.stroke = computedStyle.getPropertyValue(attributes.strokeColor); - options.fill = computedStyle.getPropertyValue(attributes.fillColor); + options.stroke = attributes.strokeColor; + options.fill = attributes.fillColor; + switch (attributes.strokeStyle) { + case StrokeStyle.Dashed: + options.strokeLineDash = [12, 12]; + break; + case StrokeStyle.None: + options.strokeLineDash = []; + options.stroke = 'transparent'; + break; + default: + options.strokeLineDash = []; + } let shapeType: string = attributes.shapeType; if (attributes.radius > 0 && shapeType === 'rect') { shapeType = 'roundedRect'; } this._shapeOverlay = new ShapeOverlay(this._edgeless, shapeType, options, { shapeStyle: attributes.shapeStyle, - fillColor: attributes.fillColor, - strokeColor: attributes.strokeColor, + fillColor: options.fill, + strokeColor: options.stroke, }); this._edgeless.surface.viewport.addOverlay(this._shapeOverlay); } diff --git a/packages/blocks/src/page-block/edgeless/utils/consts.ts b/packages/blocks/src/page-block/edgeless/utils/consts.ts index 320a5b4cf351..6cfeccf54347 100644 --- a/packages/blocks/src/page-block/edgeless/utils/consts.ts +++ b/packages/blocks/src/page-block/edgeless/utils/consts.ts @@ -1,4 +1,8 @@ -import { DEFAULT_ROUGHNESS } from '../../../surface-block/consts.js'; +import { LineWidth } from '../../../_common/types.js'; +import { + DEFAULT_ROUGHNESS, + StrokeStyle, +} from '../../../surface-block/consts.js'; export const NOTE_MIN_WIDTH = 364; export const NOTE_MIN_HEIGHT = 78; @@ -25,9 +29,10 @@ export const SHAPE_OVERLAY_OFFSET_Y = 6; export const SHAPE_OVERLAY_OPTIONS = { seed: 666, roughness: DEFAULT_ROUGHNESS, - strokeLineDash: [0, 0], + strokeStyle: StrokeStyle.Solid, + strokeLineDash: [] as number[], stroke: 'black', - strokeWidth: 4, + strokeWidth: LineWidth.LINE_WIDTH_TWO, fill: 'transparent', }; diff --git a/packages/blocks/src/page-block/edgeless/utils/tool-overlay.ts b/packages/blocks/src/page-block/edgeless/utils/tool-overlay.ts index 0801aed92b41..459d2a319832 100644 --- a/packages/blocks/src/page-block/edgeless/utils/tool-overlay.ts +++ b/packages/blocks/src/page-block/edgeless/utils/tool-overlay.ts @@ -68,9 +68,10 @@ const drawGeneralShape = ( xywh: XYWH, options: Options ) => { - ctx.strokeStyle = options.stroke ?? ''; + ctx.setLineDash(options.strokeLineDash ?? []); + ctx.strokeStyle = options.stroke ?? 'transparent'; ctx.lineWidth = options.strokeWidth ?? 2; - ctx.fillStyle = options.fill ?? '#FFFFFF00'; + ctx.fillStyle = options.fill ?? 'transparent'; ctx.beginPath(); @@ -239,6 +240,10 @@ class ToolOverlay extends Overlay { protected edgeless: EdgelessPageBlockComponent; protected disposables!: DisposableGroup; + public isTransparent(color: string): boolean { + return color.includes('transparent'); + } + constructor(edgeless: EdgelessPageBlockComponent) { super(); this.x = 0; @@ -271,6 +276,30 @@ class ToolOverlay extends Overlay { export class ShapeOverlay extends ToolOverlay { public shape: Shape; + get computedStyle() { + return getComputedStyle(this.edgeless); + } + + private _isTransparent(color: string) { + return color.includes('transparent'); + } + + private _getRealStrokeColor(color: string) { + const realStrokeColor = this.computedStyle.getPropertyValue( + color as string + ); + if (!this._isTransparent(color)) return realStrokeColor; + + return 'transparent'; + } + + private _getRealFillColor(color: string) { + const realFillColor = this.computedStyle.getPropertyValue(color as string); + if (!this._isTransparent(color)) return realFillColor; + + return 'transparent'; + } + constructor( edgeless: EdgelessPageBlockComponent, type: string, @@ -288,24 +317,18 @@ export class ShapeOverlay extends ToolOverlay { SHAPE_OVERLAY_WIDTH, SHAPE_OVERLAY_HEIGHT, ] as XYWH; - const { shapeStyle } = style; + const { shapeStyle, fillColor, strokeColor } = style; + options.fill = this._getRealFillColor(fillColor); + options.stroke = this._getRealStrokeColor(strokeColor); this.shape = ShapeFactory.createShape(xywh, type, options, shapeStyle); this.disposables.add( this.edgeless.slots.edgelessToolUpdated.on(edgelessTool => { if (edgelessTool.type !== 'shape') return; const shapeType = edgelessTool.shapeType; - - const computedStyle = getComputedStyle(edgeless); - const strokeColor = computedStyle.getPropertyValue( - style.strokeColor as string - ); - const fillColor = computedStyle.getPropertyValue( - style.fillColor as string - ); const newOptions = { ...options, - stroke: strokeColor, - fill: fillColor, + stroke: this._getRealStrokeColor(strokeColor), + fill: this._getRealFillColor(fillColor), }; let { x, y } = this; diff --git a/packages/blocks/src/surface-block/managers/edit-session.ts b/packages/blocks/src/surface-block/managers/edit-session.ts index 189caeec0554..04b6f76b7b41 100644 --- a/packages/blocks/src/surface-block/managers/edit-session.ts +++ b/packages/blocks/src/surface-block/managers/edit-session.ts @@ -39,7 +39,7 @@ import { import type { SurfaceService } from '../surface-service.js'; const ConnectorEndpointSchema = z.nativeEnum(ConnectorEndpointStyle); -const StorkeStyleSchema = z.nativeEnum(StrokeStyle); +const StrokeStyleSchema = z.nativeEnum(StrokeStyle); const LineWidthSchema = z.nativeEnum(LineWidth); const ShapeStyleSchema = z.nativeEnum(ShapeStyle); const ShapeTextFontSizeSchema = z.nativeEnum(SHAPE_TEXT_FONT_SIZE); @@ -54,7 +54,7 @@ const LastPropsSchema = z.object({ connector: z.object({ frontEndpointStyle: ConnectorEndpointSchema, rearEndpointStyle: ConnectorEndpointSchema, - strokeStyle: StorkeStyleSchema, + strokeStyle: StrokeStyleSchema, stroke: LineColorsSchema, strokeWidth: LineWidthSchema, rough: z.boolean(), @@ -72,7 +72,7 @@ const LastPropsSchema = z.object({ filled: z.boolean(), radius: z.number(), strokeWidth: z.number().optional(), - strokeStyle: StorkeStyleSchema.optional(), + strokeStyle: StrokeStyleSchema.optional(), color: z.string().optional(), fontSize: ShapeTextFontSizeSchema.optional(), fontFamily: CanvasTextFontFamilySchema.optional(), @@ -98,7 +98,7 @@ const LastPropsSchema = z.object({ style: z.object({ borderRadius: z.number(), borderSize: z.number(), - borderStyle: StorkeStyleSchema, + borderStyle: StrokeStyleSchema, shadowType: NoteShadowsSchema, }), }), @@ -155,6 +155,8 @@ export class EditSessionStorage { shapeType: ShapeType.Rect, fillColor: DEFAULT_SHAPE_FILL_COLOR, strokeColor: DEFAULT_SHAPE_STROKE_COLOR, + strokeStyle: StrokeStyle.Solid, + strokeWidth: LineWidth.LINE_WIDTH_TWO, shapeStyle: ShapeStyle.General, filled: true, radius: 0, diff --git a/tests/edgeless/shape.spec.ts b/tests/edgeless/shape.spec.ts index 379e06128ddf..c80ef090606a 100644 --- a/tests/edgeless/shape.spec.ts +++ b/tests/edgeless/shape.spec.ts @@ -145,7 +145,7 @@ test('change shape stroke color', async ({ page }) => { await changeShapeStrokeColor(page, color); await page.waitForTimeout(50); const [picked] = await pickColorAtPoints(page, [ - [rect.start.x + 2, rect.start.y + 2], + [rect.start.x + 1, rect.start.y + 1], ]); await assertEdgelessColorSameWithHexColor(page, color, picked); @@ -478,7 +478,7 @@ test('change shape style', async ({ page }) => { const color = '--affine-palette-line-navy'; await changeShapeStrokeColor(page, color); await page.waitForTimeout(50); - const [picked] = await pickColorAtPoints(page, [[start.x + 2, start.y + 2]]); + const [picked] = await pickColorAtPoints(page, [[start.x + 1, start.y + 1]]); await assertEdgelessColorSameWithHexColor(page, color, picked); });