From e6740fbeada7d4fbf333651f2d5662249606ee8c Mon Sep 17 00:00:00 2001 From: Zhilin Liu Date: Sat, 13 Jan 2024 13:45:07 +0800 Subject: [PATCH] feat: canvas pen --- src/BlockHub/BlockHub.ts | 2 + src/BlockHub/CanvasBlock/Canvas.vue | 65 +++++++++++++++++++ src/BlockHub/CanvasBlock/CanvasBlock.ts | 23 +++++++ src/Kernel/Store/ArrayStore.ts | 8 +++ src/Kernel/ToolBox/ToolBox.ts | 4 ++ .../ToolBox/controller/PenToolController.ts | 57 ++++++++++++++++ .../controller/TextBoxToolController.ts | 3 +- src/Kernel/ToolBox/controller/_index.ts | 2 + src/Lang/Locale/en-US/ToolBar.json | 6 +- src/Lang/Locale/zh-CN/ToolBar.json | 6 +- src/UserInterface/Slide/SlideContainer.vue | 5 +- src/UserInterface/ToolBar/ToolBar.vue | 2 + .../ToolBar/components/Draw/Tools.vue | 14 ++++ .../ToolBar/components/Draw/index.vue | 7 ++ 14 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 src/BlockHub/CanvasBlock/Canvas.vue create mode 100644 src/BlockHub/CanvasBlock/CanvasBlock.ts create mode 100644 src/Kernel/ToolBox/controller/PenToolController.ts create mode 100644 src/UserInterface/ToolBar/components/Draw/Tools.vue create mode 100644 src/UserInterface/ToolBar/components/Draw/index.vue diff --git a/src/BlockHub/BlockHub.ts b/src/BlockHub/BlockHub.ts index 22138a5..6db2193 100644 --- a/src/BlockHub/BlockHub.ts +++ b/src/BlockHub/BlockHub.ts @@ -3,6 +3,7 @@ import { type Block } from './Block/Block' import TextBox from './TextBoxBlock/TextBox.vue' import Table from './TableBlock/Table.vue' import Picture from './PictureBlock/Picture.vue' +import Canvas from './CanvasBlock/Canvas.vue' class BlockHub { private _blockMap = Object.create(null) @@ -21,6 +22,7 @@ export const BlockViews: { [key: string]: Component } = { TextBox, Table, Picture, + Canvas, } export const blockHub = new BlockHub() diff --git a/src/BlockHub/CanvasBlock/Canvas.vue b/src/BlockHub/CanvasBlock/Canvas.vue new file mode 100644 index 0000000..9f8df2a --- /dev/null +++ b/src/BlockHub/CanvasBlock/Canvas.vue @@ -0,0 +1,65 @@ + + + diff --git a/src/BlockHub/CanvasBlock/CanvasBlock.ts b/src/BlockHub/CanvasBlock/CanvasBlock.ts new file mode 100644 index 0000000..10ad3bf --- /dev/null +++ b/src/BlockHub/CanvasBlock/CanvasBlock.ts @@ -0,0 +1,23 @@ +import { ArrayStore } from '@Kernel/Store/ArrayStore' +import { Block } from '../Block/Block' + +export class CanvasBlock extends Block { + constructor(x: number, y: number, width: number, height: number) { + super('Canvas', x, y, width, height) + this.props.set('points', new ArrayStore()) + + const points = this.props.get('points') as ArrayStore + points.events.update.on(() => { + // TODO: fix from + this.props.events.update.emit({ key: 'points', from: this.points, to: this.points }) + }) + } + + get points() { + return this.props.get('points') as ArrayStore + } + + set points(points: ArrayStore) { + this.props.set('points', points) + } +} diff --git a/src/Kernel/Store/ArrayStore.ts b/src/Kernel/Store/ArrayStore.ts index 609a570..8fcedef 100644 --- a/src/Kernel/Store/ArrayStore.ts +++ b/src/Kernel/Store/ArrayStore.ts @@ -13,10 +13,18 @@ export class ArrayStore { }>(), } + get length() { + return this._store.length + } + get(index: number) { return this._store[index] } + slice(index: number) { + return this._store.slice(index) + } + insert(index: number, ...values: Array) { const from = [] as Array const to = values diff --git a/src/Kernel/ToolBox/ToolBox.ts b/src/Kernel/ToolBox/ToolBox.ts index 1fc8ec8..f9b1cd8 100644 --- a/src/Kernel/ToolBox/ToolBox.ts +++ b/src/Kernel/ToolBox/ToolBox.ts @@ -59,4 +59,8 @@ export class ToolBox { _addListener() }) } + + get currentToolType() { + return this._currentToolType + } } diff --git a/src/Kernel/ToolBox/controller/PenToolController.ts b/src/Kernel/ToolBox/controller/PenToolController.ts new file mode 100644 index 0000000..75aabfe --- /dev/null +++ b/src/Kernel/ToolBox/controller/PenToolController.ts @@ -0,0 +1,57 @@ +import { toSlideCoords } from '@Utils/toSlideCoords' +import { ToolController } from './_ToolController' +import { CanvasBlock } from '@BlockHub/CanvasBlock/CanvasBlock' +import { selectionManager, slideManager, toolBox } from '@Kernel/index' +import { ArrayStore } from '@Kernel/Store/ArrayStore' +import { OriginMap } from '@Kernel/Store/_Store' + +export class PenToolController extends ToolController { + private _drawing = false + private _canvasBlock?: CanvasBlock + private _range = { left: Infinity, top: Infinity, right: -Infinity, bottom: -Infinity } + + handleClick() {} + + handleMouseDown(event: MouseEvent): void { + this._drawing = true + const slideElement = event.currentTarget as HTMLElement + const slideRect = slideElement.getBoundingClientRect() + this._canvasBlock = new CanvasBlock(0, 0, slideRect.width, slideRect.height) + slideManager.currentSlide.addBlock(this._canvasBlock) + } + + handleMouseMove(event: MouseEvent) { + if (this._drawing) { + const { x, y } = toSlideCoords(event.currentTarget as HTMLElement, event.clientX, event.clientY) + this._range.left = Math.min(this._range.left, x) + this._range.right = Math.max(this._range.right, x) + this._range.top = Math.min(this._range.top, y) + this._range.bottom = Math.max(this._range.bottom, y) + this._canvasBlock?.points.push({ x, y }) + } + } + + handleMouseUp() { + if (this._drawing) { + this._drawing = false + const block = new CanvasBlock( + this._range.left, + this._range.top, + this._range.right - this._range.left, + this._range.bottom - this._range.top + ) + for (const point of this._canvasBlock?.points as ArrayStore) { + const { x, y } = point as OriginMap + block.points.push({ + x: (x as number) - this._range.left, + y: (y as number) - this._range.top, + }) + } + const slide = slideManager.currentSlide + slide.removeBlock(this._canvasBlock as CanvasBlock) + slide.addBlock(block) + selectionManager.focus(block) + } + toolBox.events.toolChange.emit('Default') + } +} diff --git a/src/Kernel/ToolBox/controller/TextBoxToolController.ts b/src/Kernel/ToolBox/controller/TextBoxToolController.ts index 8136193..c26c5a2 100644 --- a/src/Kernel/ToolBox/controller/TextBoxToolController.ts +++ b/src/Kernel/ToolBox/controller/TextBoxToolController.ts @@ -1,6 +1,6 @@ import { TextBoxBlock } from '@BlockHub/TextBoxBlock/TextBoxBlock' import { ToolController } from './_ToolController' -import { slideManager, toolBox } from '@Kernel/index' +import { selectionManager, slideManager, toolBox } from '@Kernel/index' import { TEXT_BOX_DEFAULT_HEIGHT, TEXT_BOX_DEFAULT_WIDTH } from '@Const/block' import { toSlideCoords } from '@Utils/toSlideCoords' @@ -49,6 +49,7 @@ export class TextBoxToolController extends ToolController { } this._currentBlock = undefined this._dragging = false + selectionManager.focus(block) toolBox.events.toolChange.emit('Default') } } diff --git a/src/Kernel/ToolBox/controller/_index.ts b/src/Kernel/ToolBox/controller/_index.ts index 921ef66..d05821c 100644 --- a/src/Kernel/ToolBox/controller/_index.ts +++ b/src/Kernel/ToolBox/controller/_index.ts @@ -1,4 +1,5 @@ import { DefaultToolController } from './DefaultToolController' +import { PenToolController } from './PenToolController' import { PictureToolController } from './PictureToolController' import { TextBoxToolController } from './TextBoxToolController' import { ToolController } from './_ToolController' @@ -7,4 +8,5 @@ export const controllers: { [key: string]: ToolController } = { Default: new DefaultToolController(), Picture: new PictureToolController(), TextBox: new TextBoxToolController(), + Pen: new PenToolController(), } diff --git a/src/Lang/Locale/en-US/ToolBar.json b/src/Lang/Locale/en-US/ToolBar.json index 17d081f..1d30eb6 100644 --- a/src/Lang/Locale/en-US/ToolBar.json +++ b/src/Lang/Locale/en-US/ToolBar.json @@ -95,7 +95,11 @@ } }, "draw": { - "text": "Draw" + "text": "Draw", + "tools": { + "title": "Tools", + "pen": "Pen" + } }, "design": { "text": "Design" diff --git a/src/Lang/Locale/zh-CN/ToolBar.json b/src/Lang/Locale/zh-CN/ToolBar.json index cb17226..97a211a 100644 --- a/src/Lang/Locale/zh-CN/ToolBar.json +++ b/src/Lang/Locale/zh-CN/ToolBar.json @@ -95,7 +95,11 @@ } }, "draw": { - "text": "绘图" + "text": "绘图", + "tools": { + "title": "工具", + "pen": "画笔" + } }, "design": { "text": "设计" diff --git a/src/UserInterface/Slide/SlideContainer.vue b/src/UserInterface/Slide/SlideContainer.vue index b9250bb..6bfd98e 100644 --- a/src/UserInterface/Slide/SlideContainer.vue +++ b/src/UserInterface/Slide/SlideContainer.vue @@ -1,6 +1,6 @@ diff --git a/src/UserInterface/ToolBar/components/Draw/Tools.vue b/src/UserInterface/ToolBar/components/Draw/Tools.vue new file mode 100644 index 0000000..7086820 --- /dev/null +++ b/src/UserInterface/ToolBar/components/Draw/Tools.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/UserInterface/ToolBar/components/Draw/index.vue b/src/UserInterface/ToolBar/components/Draw/index.vue new file mode 100644 index 0000000..2a0790e --- /dev/null +++ b/src/UserInterface/ToolBar/components/Draw/index.vue @@ -0,0 +1,7 @@ + + +