diff --git a/packages/blocks/src/root-block/edgeless/components/auto-complete/edgeless-auto-complete.ts b/packages/blocks/src/root-block/edgeless/components/auto-complete/edgeless-auto-complete.ts index 17dbc9310ce8..b9c7bae1da68 100644 --- a/packages/blocks/src/root-block/edgeless/components/auto-complete/edgeless-auto-complete.ts +++ b/packages/blocks/src/root-block/edgeless/components/auto-complete/edgeless-auto-complete.ts @@ -26,7 +26,6 @@ import { CanvasElementType, type IVec, Overlay, - rotatePoints, type RoughCanvas, Vec, } from '../../../../surface-block/index.js'; @@ -47,10 +46,11 @@ import { class AutoCompleteOverlay extends Overlay { linePoints: IVec[] = []; - shapePoints: IVec[] = []; stroke = ''; + renderShape: ((ctx: CanvasRenderingContext2D) => void) | null = null; + override render(ctx: CanvasRenderingContext2D, _rc: RoughCanvas) { - if (this.linePoints.length && this.shapePoints.length) { + if (this.linePoints.length && this.renderShape) { ctx.setLineDash([2, 2]); ctx.strokeStyle = this.stroke; ctx.beginPath(); @@ -58,11 +58,9 @@ class AutoCompleteOverlay extends Overlay { if (index === 0) ctx.moveTo(p[0], p[1]); else ctx.lineTo(p[0], p[1]); }); - this.shapePoints.forEach((p, index) => { - if (index === 0) ctx.moveTo(p[0], p[1]); - else ctx.lineTo(p[0], p[1]); - }); - ctx.closePath(); + ctx.stroke(); + + this.renderShape(ctx); ctx.stroke(); } } @@ -159,7 +157,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { _disposables.add( this.edgeless.service.selection.slots.updated.on(() => { this._autoCompleteOverlay.linePoints = []; - this._autoCompleteOverlay.shapePoints = []; + this._autoCompleteOverlay.renderShape = null; }) ); _disposables.add(() => this.removeOverlay()); @@ -320,11 +318,9 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { this._autoCompleteOverlay.stroke = this._surface.themeObserver.getVariableValue(current.strokeColor); this._autoCompleteOverlay.linePoints = path; - this._autoCompleteOverlay.shapePoints = rotatePoints( - shapeMethods[targetType].points(bound), - bound.center, - current.rotate - ); + this._autoCompleteOverlay.renderShape = ctx => { + shapeMethods[targetType].draw(ctx, { ...bound, rotate: current.rotate }); + }; surface.refresh(); } diff --git a/packages/blocks/src/root-block/edgeless/utils/tool-overlay.ts b/packages/blocks/src/root-block/edgeless/utils/tool-overlay.ts index a16010e2b54e..357844d8762e 100644 --- a/packages/blocks/src/root-block/edgeless/utils/tool-overlay.ts +++ b/packages/blocks/src/root-block/edgeless/utils/tool-overlay.ts @@ -2,7 +2,9 @@ import { DisposableGroup, noop, Slot } from '@blocksuite/global/utils'; import type { CssVariableName } from '../../../_common/theme/css-variables.js'; import type { ShapeStyle } from '../../../surface-block/element-model/shape.js'; +import { shapeMethods } from '../../../surface-block/element-model/shape.js'; import { + Bound, type Options, Overlay, type RoughCanvas, @@ -23,31 +25,6 @@ import { SHAPE_OVERLAY_WIDTH, } from '../utils/consts.js'; -const drawRectangle = (ctx: CanvasRenderingContext2D, xywh: XYWH) => { - const [x, y, w, h] = xywh; - ctx.rect(x, y, w, h); -}; - -const drawTriangle = (ctx: CanvasRenderingContext2D, xywh: XYWH) => { - const [x, y, w, h] = xywh; - ctx.moveTo(x + w / 2, y); - ctx.lineTo(x, y + h); - ctx.lineTo(x + w, y + h); -}; - -const drawDiamond = (ctx: CanvasRenderingContext2D, xywh: XYWH) => { - const [x, y, w, h] = xywh; - ctx.lineTo(x + w / 2, y); - ctx.lineTo(x + w, y + h / 2); - ctx.lineTo(x + w / 2, y + h); - ctx.lineTo(x, y + h / 2); -}; - -const drawEllipse = (ctx: CanvasRenderingContext2D, xywh: XYWH) => { - const [x, y, w, h] = xywh; - ctx.ellipse(x + w / 2, y + h / 2, w / 2, h / 2, 0, 0, 2 * Math.PI); -}; - const drawRoundedRect = (ctx: CanvasRenderingContext2D, xywh: XYWH) => { const [x, y, w, h] = xywh; const width = w; @@ -74,18 +51,19 @@ const drawGeneralShape = ( ctx.beginPath(); + const bound = Bound.fromXYWH(xywh); switch (type) { case 'rect': - drawRectangle(ctx, xywh); + shapeMethods.rect.draw(ctx, bound); break; case 'triangle': - drawTriangle(ctx, xywh); + shapeMethods.rect.draw(ctx, bound); break; case 'diamond': - drawDiamond(ctx, xywh); + shapeMethods.diamond.draw(ctx, bound); break; case 'ellipse': - drawEllipse(ctx, xywh); + shapeMethods.ellipse.draw(ctx, bound); break; case 'roundedRect': drawRoundedRect(ctx, xywh); @@ -191,13 +169,13 @@ export class RoundedRectShape extends Shape { const y0 = y + r; const y1 = y + h - r; const path = ` - M${x0},${y} L${x1},${y} - A${r},${r} 0 0 1 ${x1},${y0} - L${x1},${y1} - A${r},${r} 0 0 1 ${x1 - r},${y1} - L${x0 + r},${y1} - A${r},${r} 0 0 1 ${x0},${y1 - r} - L${x0},${y0} + M${x0},${y} L${x1},${y} + A${r},${r} 0 0 1 ${x1},${y0} + L${x1},${y1} + A${r},${r} 0 0 1 ${x1 - r},${y1} + L${x0 + r},${y1} + A${r},${r} 0 0 1 ${x0},${y1 - r} + L${x0},${y0} A${r},${r} 0 0 1 ${x0 + r},${y} `; diff --git a/packages/blocks/src/surface-block/element-model/utils/shape/diamond.ts b/packages/blocks/src/surface-block/element-model/utils/shape/diamond.ts index 1e1b7a70c287..4c9d5ed9846c 100644 --- a/packages/blocks/src/surface-block/element-model/utils/shape/diamond.ts +++ b/packages/blocks/src/surface-block/element-model/utils/shape/diamond.ts @@ -25,6 +25,24 @@ export const diamond = { [x + w / 2, y + h], ]; }, + draw(ctx: CanvasRenderingContext2D, { x, y, w, h, rotate = 0 }: IBound) { + const cx = x + w / 2; + const cy = y + h / 2; + + ctx.save(); + ctx.translate(cx, cy); + ctx.rotate((rotate * Math.PI) / 180); + ctx.translate(-cx, -cy); + + ctx.beginPath(); + ctx.moveTo(x, y + h / 2); + ctx.lineTo(x + w / 2, y); + ctx.lineTo(x + w, y + h / 2); + ctx.lineTo(x + w / 2, y + h); + ctx.closePath(); + + ctx.restore(); + }, hitTest( this: ShapeElementModel, diff --git a/packages/blocks/src/surface-block/element-model/utils/shape/ellipse.ts b/packages/blocks/src/surface-block/element-model/utils/shape/ellipse.ts index db667879864c..f381a884406e 100644 --- a/packages/blocks/src/surface-block/element-model/utils/shape/ellipse.ts +++ b/packages/blocks/src/surface-block/element-model/utils/shape/ellipse.ts @@ -21,6 +21,20 @@ export const ellipse = { [x + w / 2, y + h], ]; }, + draw(ctx: CanvasRenderingContext2D, { x, y, w, h, rotate = 0 }: IBound) { + const cx = x + w / 2; + const cy = y + h / 2; + + ctx.save(); + ctx.translate(cx, cy); + ctx.rotate((rotate * Math.PI) / 180); + ctx.translate(-cx, -cy); + + ctx.beginPath(); + ctx.ellipse(cx, cy, w / 2, h / 2, 0, 0, 2 * Math.PI); + + ctx.restore(); + }, hitTest( this: ShapeElementModel, x: number, diff --git a/packages/blocks/src/surface-block/element-model/utils/shape/rect.ts b/packages/blocks/src/surface-block/element-model/utils/shape/rect.ts index f777422fa3aa..c4357e00ff48 100644 --- a/packages/blocks/src/surface-block/element-model/utils/shape/rect.ts +++ b/packages/blocks/src/surface-block/element-model/utils/shape/rect.ts @@ -25,6 +25,14 @@ export const rect = { [x, y + h], ]; }, + draw(ctx: CanvasRenderingContext2D, { x, y, w, h, rotate = 0 }: IBound) { + ctx.save(); + ctx.translate(x + w / 2, y + h / 2); + ctx.rotate((rotate * Math.PI) / 180); + ctx.translate(-x - w / 2, -y - h / 2); + ctx.rect(x, y, w, h); + ctx.restore(); + }, hitTest( this: ShapeElementModel, x: number, diff --git a/packages/blocks/src/surface-block/element-model/utils/shape/triangle.ts b/packages/blocks/src/surface-block/element-model/utils/shape/triangle.ts index b8e8222afb4f..949e30298b80 100644 --- a/packages/blocks/src/surface-block/element-model/utils/shape/triangle.ts +++ b/packages/blocks/src/surface-block/element-model/utils/shape/triangle.ts @@ -23,6 +23,23 @@ export const triangle = { [x + w, y + h], ]; }, + draw(ctx: CanvasRenderingContext2D, { x, y, w, h, rotate = 0 }: IBound) { + const cx = x + w / 2; + const cy = y + h / 2; + + ctx.save(); + ctx.translate(cx, cy); + ctx.rotate((rotate * Math.PI) / 180); + ctx.translate(-cx, -cy); + + ctx.beginPath(); + ctx.moveTo(x, y + h); + ctx.lineTo(x + w / 2, y); + ctx.lineTo(x + w, y + h); + ctx.closePath(); + + ctx.restore(); + }, hitTest( this: ShapeElementModel, x: number,