From e6dc4c1ab0c9138148e65d91cea8d4d65e091cda Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Sat, 15 Apr 2023 14:37:15 +0800 Subject: [PATCH] refactor: refactor framework for v0.4 --- packages/board/src/index.ts | 506 ++++---------- packages/board/src/lib/calculator.ts | 99 +++ packages/board/src/lib/event.ts | 93 --- packages/board/src/lib/istype.ts | 3 - packages/board/src/lib/screen-watcher.ts | 366 ----------- packages/board/src/lib/screen.ts | 172 ----- packages/board/src/lib/scroller.ts | 275 -------- packages/board/src/lib/sharer.ts | 61 ++ packages/board/src/lib/style.ts | 95 --- packages/board/src/lib/temp.ts | 43 -- packages/board/src/lib/viewer.ts | 77 +++ packages/board/src/lib/watcher-temp.ts | 47 -- packages/board/src/lib/watcher.ts | 224 ++----- packages/core/src/constant/element.ts | 15 - packages/core/src/constant/static.ts | 12 - packages/core/src/index.ts | 337 +--------- packages/core/src/lib/calculate.ts | 63 -- packages/core/src/lib/check.ts | 150 ----- packages/core/src/lib/config.ts | 27 - packages/core/src/lib/core-event.ts | 124 ---- packages/core/src/lib/diff.ts | 123 ---- packages/core/src/lib/draw/base.ts | 108 --- packages/core/src/lib/draw/wrapper.ts | 269 -------- packages/core/src/lib/element.ts | 622 ------------------ packages/core/src/lib/engine-temp.ts | 50 -- packages/core/src/lib/engine.ts | 430 ------------ packages/core/src/lib/helper.ts | 445 ------------- packages/core/src/lib/index.ts | 13 - packages/core/src/lib/is.ts | 153 ----- packages/core/src/lib/mapper.ts | 119 ---- packages/core/src/lib/parse.ts | 40 -- packages/core/src/lib/temp.ts | 31 - packages/core/src/lib/transform.ts | 35 - packages/core/src/lib/value.ts | 9 - .../src/middleware/select/draw-wrapper.ts | 52 ++ packages/core/src/middleware/select/index.ts | 112 ++++ packages/core/src/mixins/element.ts | 216 ------ packages/core/src/plugins/helper.ts | 34 - packages/core/src/util/filter.ts | 4 - packages/idraw/dev/data.ts | 243 ++++--- packages/idraw/dev/images/github.png | Bin 0 -> 201891 bytes packages/idraw/dev/images/lena.png | Bin 0 -> 146364 bytes packages/idraw/dev/main.ts | 64 +- packages/idraw/src/config.ts | 12 - packages/idraw/src/index.ts | 119 +--- packages/idraw/src/lib/keyboard-watcher.ts | 104 --- packages/idraw/src/lib/keyboard.ts | 6 - packages/idraw/src/lib/temp.ts | 40 -- packages/idraw/src/mixins/file.ts | 41 -- packages/idraw/src/mixins/keyboard.ts | 104 --- packages/idraw/src/mixins/record.ts | 52 -- packages/idraw/src/types.ts | 16 - packages/renderer/src/constant/element.ts | 15 - packages/renderer/src/constant/static.ts | 12 - packages/renderer/src/draw/circle.ts | 31 + packages/renderer/src/draw/elements.ts | 42 ++ packages/renderer/src/draw/image.ts | 14 + packages/renderer/src/draw/index.ts | 4 + packages/renderer/src/draw/rect.ts | 22 + packages/renderer/src/index.ts | 237 ++----- packages/renderer/src/lib/calculate.ts | 63 -- packages/renderer/src/lib/diff.ts | 123 ---- packages/renderer/src/lib/draw/base.ts | 107 --- packages/renderer/src/lib/draw/circle.ts | 73 -- packages/renderer/src/lib/draw/html.ts | 16 - packages/renderer/src/lib/draw/image.ts | 41 -- packages/renderer/src/lib/draw/index.ts | 69 -- packages/renderer/src/lib/draw/rect.ts | 6 - packages/renderer/src/lib/draw/svg.ts | 40 -- packages/renderer/src/lib/draw/text.ts | 163 ----- packages/renderer/src/lib/index.ts | 6 - packages/renderer/src/lib/loader-event.ts | 103 --- packages/renderer/src/lib/loader.ts | 347 ---------- packages/renderer/src/lib/parse.ts | 40 -- packages/renderer/src/lib/renderer-event.ts | 89 --- packages/renderer/src/lib/temp.ts | 50 -- packages/renderer/src/lib/transform.ts | 35 - packages/renderer/src/lib/value.ts | 9 - packages/renderer/src/loader.ts | 118 ++++ packages/renderer/src/util/filter.ts | 4 - packages/types/src/index.ts | 3 + packages/types/src/lib/board.ts | 12 +- packages/types/src/lib/core.ts | 7 + packages/types/src/lib/idraw.ts | 3 + packages/types/src/lib/middleware.ts | 0 packages/types/src/lib/renderer.ts | 2 +- packages/types/src/lib/watcher.ts | 5 + tsconfig.web.json | 10 +- 88 files changed, 1138 insertions(+), 7238 deletions(-) create mode 100644 packages/board/src/lib/calculator.ts delete mode 100644 packages/board/src/lib/event.ts delete mode 100644 packages/board/src/lib/istype.ts delete mode 100644 packages/board/src/lib/screen-watcher.ts delete mode 100644 packages/board/src/lib/screen.ts delete mode 100644 packages/board/src/lib/scroller.ts create mode 100644 packages/board/src/lib/sharer.ts delete mode 100644 packages/board/src/lib/style.ts delete mode 100644 packages/board/src/lib/temp.ts create mode 100644 packages/board/src/lib/viewer.ts delete mode 100644 packages/board/src/lib/watcher-temp.ts delete mode 100644 packages/core/src/constant/element.ts delete mode 100644 packages/core/src/constant/static.ts delete mode 100644 packages/core/src/lib/calculate.ts delete mode 100644 packages/core/src/lib/check.ts delete mode 100644 packages/core/src/lib/config.ts delete mode 100644 packages/core/src/lib/core-event.ts delete mode 100644 packages/core/src/lib/diff.ts delete mode 100644 packages/core/src/lib/draw/base.ts delete mode 100644 packages/core/src/lib/draw/wrapper.ts delete mode 100644 packages/core/src/lib/element.ts delete mode 100644 packages/core/src/lib/engine-temp.ts delete mode 100644 packages/core/src/lib/engine.ts delete mode 100644 packages/core/src/lib/helper.ts delete mode 100644 packages/core/src/lib/index.ts delete mode 100644 packages/core/src/lib/is.ts delete mode 100644 packages/core/src/lib/mapper.ts delete mode 100644 packages/core/src/lib/parse.ts delete mode 100644 packages/core/src/lib/temp.ts delete mode 100644 packages/core/src/lib/transform.ts delete mode 100644 packages/core/src/lib/value.ts create mode 100644 packages/core/src/middleware/select/draw-wrapper.ts create mode 100644 packages/core/src/middleware/select/index.ts delete mode 100644 packages/core/src/mixins/element.ts delete mode 100644 packages/core/src/plugins/helper.ts delete mode 100644 packages/core/src/util/filter.ts create mode 100644 packages/idraw/dev/images/github.png create mode 100644 packages/idraw/dev/images/lena.png delete mode 100644 packages/idraw/src/config.ts delete mode 100644 packages/idraw/src/lib/keyboard-watcher.ts delete mode 100644 packages/idraw/src/lib/keyboard.ts delete mode 100644 packages/idraw/src/lib/temp.ts delete mode 100644 packages/idraw/src/mixins/file.ts delete mode 100644 packages/idraw/src/mixins/keyboard.ts delete mode 100644 packages/idraw/src/mixins/record.ts delete mode 100644 packages/idraw/src/types.ts delete mode 100644 packages/renderer/src/constant/element.ts delete mode 100644 packages/renderer/src/constant/static.ts create mode 100644 packages/renderer/src/draw/circle.ts create mode 100644 packages/renderer/src/draw/elements.ts create mode 100644 packages/renderer/src/draw/image.ts create mode 100644 packages/renderer/src/draw/index.ts create mode 100644 packages/renderer/src/draw/rect.ts delete mode 100644 packages/renderer/src/lib/calculate.ts delete mode 100644 packages/renderer/src/lib/diff.ts delete mode 100644 packages/renderer/src/lib/draw/base.ts delete mode 100644 packages/renderer/src/lib/draw/circle.ts delete mode 100644 packages/renderer/src/lib/draw/html.ts delete mode 100644 packages/renderer/src/lib/draw/image.ts delete mode 100644 packages/renderer/src/lib/draw/index.ts delete mode 100644 packages/renderer/src/lib/draw/rect.ts delete mode 100644 packages/renderer/src/lib/draw/svg.ts delete mode 100644 packages/renderer/src/lib/draw/text.ts delete mode 100644 packages/renderer/src/lib/index.ts delete mode 100644 packages/renderer/src/lib/loader-event.ts delete mode 100644 packages/renderer/src/lib/loader.ts delete mode 100644 packages/renderer/src/lib/parse.ts delete mode 100644 packages/renderer/src/lib/renderer-event.ts delete mode 100644 packages/renderer/src/lib/temp.ts delete mode 100644 packages/renderer/src/lib/transform.ts delete mode 100644 packages/renderer/src/lib/value.ts create mode 100644 packages/renderer/src/loader.ts delete mode 100644 packages/renderer/src/util/filter.ts create mode 100644 packages/types/src/lib/core.ts create mode 100644 packages/types/src/lib/idraw.ts create mode 100644 packages/types/src/lib/middleware.ts create mode 100644 packages/types/src/lib/watcher.ts diff --git a/packages/board/src/index.ts b/packages/board/src/index.ts index 8cb0348..9ac4982 100644 --- a/packages/board/src/index.ts +++ b/packages/board/src/index.ts @@ -1,408 +1,148 @@ -import { - ScreenPosition, - ScreenSize, - ScreenContext, - Point, - PointCursor, - BoardOptions, - BoardSizeOptions, - IDrawContext -} from '@idraw/types'; -import util from '@idraw/util'; -import { ScreenWatcher } from './lib/screen-watcher'; -import { setStyle } from './lib/style'; -import { TypeBoardEventArgMap } from './lib/event'; -import { Scroller } from './lib/scroller'; -import { Screen } from './lib/screen'; -// import { TempData } from './lib/temp'; +import { Renderer } from '@idraw/renderer'; +import { throttle } from '@idraw/util'; +import type { Data, BoardMode, BoardOptions, BoardMiddleware, BoardMiddlewareObject, BoardWatcherEventMap } from '@idraw/types'; +import { Calculator } from './lib/calculator'; +import { BoardWatcher } from './lib/watcher'; +import { Sharer } from './lib/sharer'; +import { Viewer } from './lib/viewer'; -const { throttle, Context } = util; +const frameTime = 16; // ms -type PrivateOptions = BoardOptions & { - devicePixelRatio: number; -}; +const LOCK_MODES: BoardMode[] = ['RULER']; -export default class Board { - private _hasRendered = false; - - private _canvas: HTMLCanvasElement; - private _helperCanvas: HTMLCanvasElement; - private _displayCanvas: HTMLCanvasElement; - private _mount: HTMLDivElement; - private _opts: PrivateOptions; - private _ctx: IDrawContext; - private _helperCtx: IDrawContext; - // private _watcher: Watcher; - private _watcher: ScreenWatcher; - private _scroller: Scroller; - private _screen: Screen; - // private _tempData: TempData; - - constructor(mount: HTMLDivElement, opts: BoardOptions) { - // this._tempData = new TempData(opts); - - this._mount = mount; - this._canvas = document.createElement('canvas'); - this._helperCanvas = document.createElement('canvas'); - this._displayCanvas = document.createElement('canvas'); - this._mount.appendChild(this._displayCanvas); - this._opts = this._parsePrivateOptions(opts); - - const originCtx2d = this._canvas.getContext( - '2d' - ) as CanvasRenderingContext2D; - const displayCtx2d = this._displayCanvas.getContext( - '2d' - ) as CanvasRenderingContext2D; - const helperCtx2d = this._helperCanvas.getContext( - '2d' - ) as CanvasRenderingContext2D; - this._ctx = new Context(originCtx2d, this._opts); - this._helperCtx = new Context(helperCtx2d, this._opts); - this._screen = new Screen(this._ctx, this._opts); - // this._watcher = new Watcher(this._displayCanvas); - this._watcher = new ScreenWatcher(this._displayCanvas, this._ctx); - this._scroller = new Scroller(displayCtx2d, { - width: opts.width, - height: opts.height, - devicePixelRatio: opts.devicePixelRatio || 1, - scrollConfig: opts.scrollConfig +export class Board { + private _opts: BoardOptions; + private _middlewares: BoardMiddleware[] = []; + private _middlewareObjs: BoardMiddlewareObject[] = []; + private _activeMiddlewareObjs: BoardMiddlewareObject[] = []; + private _watcher: BoardWatcher; + private _sharer: Sharer; + private _renderer: Renderer; + private _viewer: Viewer; + private _calculator: Calculator; + private _activeMode: BoardMode = 'SELECT'; + constructor(opts: BoardOptions) { + const { viewContent } = opts; + const sharer = new Sharer(); + const calculator = new Calculator({ viewContent }); + const watcher = new BoardWatcher({ + viewContent }); - this._render(); - } - - getDisplayContext2D(): CanvasRenderingContext2D { - return this._displayCanvas.getContext('2d') as CanvasRenderingContext2D; - } - - getOriginContext2D(): CanvasRenderingContext2D { - return this._ctx.getContext(); - } - - getHelperContext2D(): CanvasRenderingContext2D { - return this._helperCtx.getContext(); - } - - getContext(): IDrawContext { - return this._ctx; - } - - getHelperContext(): IDrawContext { - return this._helperCtx; - } - - scale(scaleRatio: number): ScreenContext { - if (scaleRatio > 0) { - this._ctx.setTransform({ scale: scaleRatio }); - this._helperCtx.setTransform({ scale: scaleRatio }); - } - const { position, size } = this._screen.calcScreen(); - return { position, size }; - } - - scrollX(x: number) { - this._watcher.setStatusMap({ - canScrollYPrev: true, - canScrollYNext: true, - canScrollXPrev: true, - canScrollXNext: true + const renderer = new Renderer({ + viewContent, + sharer, + calculator }); - if (x >= 0 || x < 0) { - this._ctx.setTransform({ scrollX: x }); - this._helperCtx.setTransform({ scrollX: x }); - } - const { - position, - size, - canScrollXNext, - canScrollYNext, - canScrollXPrev, - canScrollYPrev - } = this._screen.calcScreen(); - this._watcher.setStatusMap({ - canScrollYPrev, - canScrollYNext, - canScrollXPrev, - canScrollXNext + + this._opts = opts; + this._sharer = sharer; + this._renderer = renderer; + this._watcher = watcher; + this._calculator = calculator; + this._viewer = new Viewer({ + viewContent: opts.viewContent, + sharer, + renderer, + beforeDrawFrame: (e) => { + this._handleBeforeDrawFrame(e); + }, + afterDrawFrame: (e) => { + this._handleAfterDrawFrame(e); + } }); - return { position, size }; + this._init(); + this._resetActiveMiddlewareObjs(); } - scrollY(y: number): ScreenContext { - this._watcher.setStatusMap({ - canScrollYPrev: true, - canScrollYNext: true, - canScrollXPrev: true, - canScrollXNext: true - }); - if (y >= 0 || y < 0) { - this._ctx.setTransform({ scrollY: y }); - this._helperCtx.setTransform({ scrollY: y }); - } - const { - position, - size, - canScrollXNext, - canScrollYNext, - canScrollXPrev, - canScrollYPrev - } = this._screen.calcScreen(); - this._watcher.setStatusMap({ - canScrollYPrev, - canScrollYNext, - canScrollXPrev, - canScrollXNext - }); - return { position, size }; - } - - getTransform() { - return this._ctx.getTransform(); - } - - draw(): ScreenContext { - this.clear(); - const { position, deviceSize, size } = this._screen.calcScreen(); - const displayCtx = this._displayCanvas.getContext('2d'); - displayCtx?.drawImage( - this._canvas, - deviceSize.x, - deviceSize.y, - deviceSize.w, - deviceSize.h + private _init() { + this._watcher.on('pointStart', this._handlePointStart.bind(this)); + this._watcher.on('pointEnd', this._handlePointEnd.bind(this)); + this._watcher.on( + 'pointMove', + throttle((e) => { + this._handlePointMove(e); + }, frameTime) ); - displayCtx?.drawImage( - this._helperCanvas, - deviceSize.x, - deviceSize.y, - deviceSize.w, - deviceSize.h - ); - if (this._opts.canScroll === true) { - this._scroller.draw(position); - } - return { position, size }; - } - - clear() { - const displayCtx = this._displayCanvas.getContext('2d'); - displayCtx?.clearRect( - 0, - 0, - this._displayCanvas.width, - this._displayCanvas.height + this._watcher.on( + 'hover', + throttle((e) => { + this._handleHover(e); + }, frameTime) ); } - on( - name: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ) { - this._watcher.on(name, callback); - } - - off( - name: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ) { - this._watcher.off(name, callback); - } - - getScreenInfo(): { - size: ScreenSize; - position: ScreenPosition; - deviceSize: ScreenSize; - width: number; - height: number; - devicePixelRatio: number; - // eslint-disable-next-line indent - } { - return this._screen.calcScreen(); - } - - setCursor(cursor: PointCursor) { - this._displayCanvas.style.cursor = cursor; - } - - resetCursor() { - this._displayCanvas.style.cursor = 'auto'; - } - - resetSize(opts: BoardSizeOptions) { - this._opts = { ...this._opts, ...opts }; - this._resetContext(); - this._ctx.resetSize(opts); - this._helperCtx.resetSize(opts); - this._screen.resetSize(opts); - this._scroller.resetSize({ - width: this._opts.width, - height: this._opts.height, - devicePixelRatio: this._opts.devicePixelRatio - }); - this.draw(); - } - - getScrollLineWidth(): number { - let lineWidth = 0; - if (this._opts.canScroll === true) { - lineWidth = this._scroller.getLineWidth(); - } - return lineWidth; - } - - pointScreenToContext(screenPoint: Point): Point { - const { scrollX, scrollY, scale } = this.getTransform(); - const ctxPoint = { - x: (screenPoint.x - scrollX) / scale, - y: (screenPoint.y - scrollY) / scale - }; - return ctxPoint; - } - - pointContextToScreen(ctxPoint: Point): Point { - const { scrollX, scrollY, scale } = this.getTransform(); - const screenPoint = { - x: ctxPoint.x * scale + scrollX, - y: ctxPoint.y * scale + scrollY - }; - return screenPoint; - } - - private _render() { - if (this._hasRendered === true) { - return; - } - this._resetContext(); - this._initEvent(); - this._hasRendered = true; - } - - private _resetContext() { - const { width, height, contextWidth, contextHeight, devicePixelRatio } = - this._opts; - this._canvas.width = contextWidth * devicePixelRatio; - this._canvas.height = contextHeight * devicePixelRatio; - - this._helperCanvas.width = contextWidth * devicePixelRatio; - this._helperCanvas.height = contextHeight * devicePixelRatio; - - this._displayCanvas.width = width * devicePixelRatio; - this._displayCanvas.height = height * devicePixelRatio; - - setStyle(this._displayCanvas, { - width: `${width}px`, - height: `${height}px` + private _handlePointStart(e: BoardWatcherEventMap['pointStart']) { + this._activeMiddlewareObjs.forEach((obj) => { + obj?.pointStart?.(e); }); } - private _parsePrivateOptions(opts: BoardOptions): PrivateOptions { - const defaultOpts = { - devicePixelRatio: 1 - }; - return { ...defaultOpts, ...opts }; + private _handlePointEnd(e: BoardWatcherEventMap['pointEnd']) { + this._activeMiddlewareObjs.forEach((obj) => { + obj?.pointEnd?.(e); + }); } - private _initEvent() { - if (this._hasRendered === true) { - return; - } - if (this._opts.canScroll === true) { - this.on( - 'wheelX', - throttle((deltaX) => { - this._doScrollX(deltaX); - }, 16) - ); - this.on( - 'wheelY', - throttle((deltaY: number) => { - this._doScrollY(deltaY); - }, 16) - ); - - let scrollType: 'x' | 'y' | null = null; - this.on( - 'moveStart', - throttle((p: Point) => { - if (this._scroller.isPointAtScrollX(p)) { - scrollType = 'x'; - } else if (this._scroller.isPointAtScrollY(p)) { - scrollType = 'y'; - } - }, 16) - ); - - this.on( - 'move', - throttle((p: Point) => { - if (scrollType) { - this._doMoveScroll(scrollType, p); - } - }, 16) - ); - - this.on( - 'moveEnd', - throttle((p: Point) => { - if (scrollType) { - this._doMoveScroll(scrollType, p); - } - scrollType = null; - }, 16) - ); - - // this.on('doubleClick', (p: Point) => {}) - } + private _handlePointMove(e: BoardWatcherEventMap['pointMove']) { + this._activeMiddlewareObjs.forEach((obj) => { + obj?.pointMove?.(e); + }); } - private _doScrollX(dx: number, prevScrollX?: number) { - const { width } = this._opts; - let scrollX = prevScrollX; - if (!(typeof scrollX === 'number' && (scrollX > 0 || scrollX <= 0))) { - scrollX = this._ctx.getTransform().scrollX; - } - const { position } = this._screen.calcScreen(); - const { xSize } = this._scroller.calc(position); - const moveX = this._screen.calcScreenScroll( - position.left, - position.right, - xSize, - width, - dx - ); - this.scrollX(scrollX + moveX); - this.draw(); + private _handleHover(e: BoardWatcherEventMap['hover']) { + this._activeMiddlewareObjs.forEach((obj) => { + obj?.hover?.(e); + }); } - private _doScrollY(dy: number, prevScrollY?: number) { - const { height } = this._opts; - let scrollY = prevScrollY; - if (!(typeof scrollY === 'number' && (scrollY > 0 || scrollY <= 0))) { - scrollY = this._ctx.getTransform().scrollY; - } - const { position } = this._screen.calcScreen(); - const { ySize } = this._scroller.calc(position); - const moveY = this._screen.calcScreenScroll( - position.top, - position.bottom, - ySize, - height, - dy - ); - this.scrollY(scrollY + moveY); - this.draw(); + private _handleBeforeDrawFrame(e: BoardWatcherEventMap['beforeDrawFrame']) { + this._activeMiddlewareObjs.forEach((obj) => { + obj?.beforeDrawFrame?.(e); + }); } - private _doMoveScroll(scrollType: 'x' | 'y', point: Point) { - if (!scrollType) { - return; - } - const { position } = this._screen.calcScreen(); - const { xSize, ySize } = this._scroller.calc(position); - if (scrollType === 'x') { - this._doScrollX(point.x - xSize / 2, 0); - } else if (scrollType === 'y') { - this._doScrollY(point.y - ySize / 2, 0); - } + private _handleAfterDrawFrame(e: BoardWatcherEventMap['afterDrawFrame']) { + this._activeMiddlewareObjs.forEach((obj) => { + obj?.afterDrawFrame?.(e); + }); + } + + private _resetActiveMiddlewareObjs() { + const { _activeMode: activeMode } = this; + const modes: BoardMode[] = [...LOCK_MODES, activeMode]; + const activeMiddlewareObjs: BoardMiddlewareObject[] = []; + this._middlewareObjs.forEach((m) => { + if (modes.includes(m.mode)) { + activeMiddlewareObjs.push(m); + } + }); + this._activeMiddlewareObjs = activeMiddlewareObjs; + } + + setData(data: Data) { + this._sharer.setActiveStorage('data', data); + this._viewer.drawFrame(); + } + + use(middleware: BoardMiddleware) { + const { viewContent } = this._opts; + const { _sharer: sharer, _viewer: viewer, _calculator: calculator } = this; + const obj = middleware({ viewContent, sharer, viewer, calculator }); + this._middlewares.push(middleware); + this._activeMiddlewareObjs.push(obj); + } + + scale(num: number) { + const { _viewer: viewer, _renderer: renderer } = this; + renderer.scale(num); + viewer.drawFrame(); + } + + scrollX(num: number) { + // TODO + } + + scrollY(num: number) { + // TODO } } diff --git a/packages/board/src/lib/calculator.ts b/packages/board/src/lib/calculator.ts new file mode 100644 index 0000000..3e862c9 --- /dev/null +++ b/packages/board/src/lib/calculator.ts @@ -0,0 +1,99 @@ +import type { Data, PointSize, Point, Element, ElementType, ViewCalculator, ViewCalculatorOptions, ViewScaleInfo, ElementSize } from '../types'; + +export class Calculator implements ViewCalculator { + private _opts: ViewCalculatorOptions; + + constructor(opts: ViewCalculatorOptions) { + this._opts = opts; + } + + private _getBoardSize(): { width: number; height: number } { + return { + width: this._opts.viewContent.boardContext.canvas.width, + height: this._opts.viewContent.boardContext.canvas.height + }; + } + + viewScale(num: number, prevScaleInfo?: ViewScaleInfo): ViewScaleInfo { + // TODO + } + + elementSize(size: ElementSize, scaleInfo: ViewScaleInfo): ElementSize { + const { x, y, w, h } = size; + const { scale, offsetTop, offsetLeft } = scaleInfo; + return { + x: x * scale + offsetLeft, + y: y * scale + offsetTop, + w: w * scale, + h: h * scale + }; + } + + isElementInView(elem: Element, scaleInfo: ViewScaleInfo): boolean { + // TODO + const { width, height } = this._getBoardSize(); + const { scale = 1, offsetTop = 0, offsetLeft = 0 } = scaleInfo; + + // Virtual View Point + // const vvp0: PointSize = { x: offsetLeft, y: offsetTop }; + // const vvp1: PointSize = { x: offsetLeft + width, y: offsetTop }; + // const vvp2: PointSize = { x: offsetLeft + width, y: offsetTop + height }; + // const vvp3: PointSize = { x: offsetLeft, y: offsetTop + height }; + const vvpStart: PointSize = { x: offsetLeft, y: offsetTop }; + const vvpEnd: PointSize = { x: offsetLeft + width, y: offsetTop + height }; + + // Virtual Element Point + const vep0: PointSize = { x: elem.x * scale, y: elem.y * scale }; + const vep1: PointSize = { x: (elem.x + elem.w) * scale, y: elem.y * scale }; + const vep2: PointSize = { x: (elem.x + elem.w) * scale, y: (elem.y + elem.h) * scale }; + const vep3: PointSize = { x: elem.x * scale, y: (elem.y + elem.h) * scale }; + // const vepStart: PointSize = { x: elem.x * scale, y: elem.y * scale }; + // const vepEnd: PointSize = { x: (elem.x + elem.w) * scale, y: (elem.y + elem.w) * scale }; + + const isPointInRect = (p: PointSize) => { + return p.x >= vvpStart.x && p.x <= vvpEnd.x && p.y >= vvpStart.y && p.y <= vvpEnd.y; + }; + if (isPointInRect(vep0) || isPointInRect(vep1) || isPointInRect(vep2) || isPointInRect(vep3)) { + return true; + } + return false; + } + + isPointInElement(p: Point, elem: Element, scaleInfo: ViewScaleInfo): boolean { + const { scale = 1, offsetTop = 0, offsetLeft = 0 } = scaleInfo; + // Virtual Point + const vp: PointSize = { + x: p.x + offsetLeft, + y: p.y + offsetTop + }; + + // Virtual Element Point + const vepStart: PointSize = { x: elem.x * scale, y: elem.y * scale }; + const vepEnd: PointSize = { x: (elem.x + elem.w) * scale, y: (elem.y + elem.w) * scale }; + if (vp.x >= vepStart.x && vp.x <= vepEnd.x && vp.y >= vepStart.y && vp.y <= vepEnd.y) { + return true; + } + return false; + } + + getPointElement(p: Point, data: Data, scaleInfo: ViewScaleInfo): { index: number; element: null | Element } { + const result: { index: number; element: null | Element } = { + index: -1, + element: null + }; + for (let i = 0; i < data.elements.length; i++) { + const elem = data.elements[i]; + if (this.isPointInElement(p, elem, scaleInfo)) { + result.index = i; + result.element = elem; + break; + } + } + return result; + } + + pointToViewPoint(p: Point): Point { + // TODO + return {}; + } +} diff --git a/packages/board/src/lib/event.ts b/packages/board/src/lib/event.ts deleted file mode 100644 index abc85bb..0000000 --- a/packages/board/src/lib/event.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { Point } from '@idraw/types'; - -export interface TypeBoardEventArgMap { - doubleClick: Point; - hover: Point; - leave: void; - point: Point; - move: Point; - moveStart: Point; - moveEnd: Point; - wheelX: number; - wheelY: number; -} - -export interface TypeBoardEvent { - on( - key: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ): void; - off( - key: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ): void; - trigger( - key: T, - p: TypeBoardEventArgMap[T] - ): void; -} - -export class BoardEvent implements TypeBoardEvent { - private _listeners: Map void)[]>; - - constructor() { - this._listeners = new Map(); - } - - on( - eventKey: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - callbacks?.push(callback); - this._listeners.set(eventKey, callbacks || []); - } else { - this._listeners.set(eventKey, [callback]); - } - } - - off( - eventKey: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - for (let i = 0; i < callbacks?.length; i++) { - if (callbacks[i] === callback) { - callbacks.splice(i, 1); - break; - } - } - } - this._listeners.set(eventKey, callbacks || []); - } - } - - trigger( - eventKey: T, - arg: TypeBoardEventArgMap[T] - ) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - callbacks.forEach((cb) => { - cb(arg); - }); - return true; - } else { - return false; - } - } - - has(name: string) { - if (this._listeners.has(name)) { - const list: ((p: TypeBoardEventArgMap[T]) => void)[] | undefined = - this._listeners.get(name); - if (Array.isArray(list) && list.length > 0) { - return true; - } - } - return false; - } -} diff --git a/packages/board/src/lib/istype.ts b/packages/board/src/lib/istype.ts deleted file mode 100644 index 71dc7f4..0000000 --- a/packages/board/src/lib/istype.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { istype } from '@idraw/util'; - -export default istype; \ No newline at end of file diff --git a/packages/board/src/lib/screen-watcher.ts b/packages/board/src/lib/screen-watcher.ts deleted file mode 100644 index 513abfa..0000000 --- a/packages/board/src/lib/screen-watcher.ts +++ /dev/null @@ -1,366 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { Point, IDrawContext } from '@idraw/types'; -import { BoardEvent, TypeBoardEventArgMap } from './event'; -import { TempData } from './watcher-temp'; - -// const { throttle } = util.time; - -// const isInIframe = window.self === window.top; - -export class ScreenWatcher { - private _canvas: HTMLCanvasElement; - private _isMoving = false; - // private _onMove?: TypeWatchCallback; - // private _onMoveStart?: TypeWatchCallback; - // private _onMoveEnd?: TypeWatchCallback; - private _event: BoardEvent; - private _temp: TempData = new TempData(); - private _container: HTMLElement | Window = window; - // private _ctx: IDrawContext; - - constructor(canvas: HTMLCanvasElement, ctx: IDrawContext) { - this._canvas = canvas; - this._isMoving = false; - this._initEvent(); - this._event = new BoardEvent(); - // this._ctx = ctx; - } - - setStatusMap(statusMap: { - canScrollYPrev: boolean; - canScrollYNext: boolean; - canScrollXPrev: boolean; - canScrollXNext: boolean; - }) { - this._temp.set('statusMap', statusMap); - } - - on( - name: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ): void { - this._event.on(name, callback); - } - - off( - name: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ): void { - this._event.off(name, callback); - } - - _initEvent(): void { - const canvas = this._canvas; - const container = this._container; - // container.addEventListener('mousemove', this._listenWindowHover.bind(this), false); - // container.addEventListener('mousedown', this._listenWindowMoveStart.bind(this), false); - container.addEventListener( - 'mousemove', - this._listenWindowMove.bind(this), - false - ); - container.addEventListener( - 'mouseup', - this._listenWindowMoveEnd.bind(this), - false - ); - - canvas.addEventListener('mousemove', this._listenHover.bind(this), false); - canvas.addEventListener( - 'mousedown', - this._listenMoveStart.bind(this), - false - ); - canvas.addEventListener('mousemove', this._listenMove.bind(this), false); - canvas.addEventListener('mouseup', this._listenMoveEnd.bind(this), false); - - canvas.addEventListener('click', this._listenCanvasClick.bind(this), false); - canvas.addEventListener('wheel', this._listenCanvasWheel.bind(this), false); - canvas.addEventListener( - 'mousedown', - this._listenCanvasMoveStart.bind(this), - true - ); - canvas.addEventListener( - 'mouseup', - this._listenCanvasMoveEnd.bind(this), - true - ); - canvas.addEventListener( - 'mouseover', - this._listenCanvasMoveOver.bind(this), - true - ); - canvas.addEventListener( - 'mouseleave', - this._listenCanvasMoveLeave.bind(this), - true - ); - this._initParentEvent(); - - // container.addEventListener('touchstart', this._listenMoveStart.bind(this), true); - // container.addEventListener('touchmove', this._listenMove.bind(this), true); - // container.addEventListener('touchend', this._listenMoveEnd.bind(this), true); - } - - _initParentEvent() { - try { - let target = window; - const targetOrigin = target.origin; - while (target.self !== target.top) { - // If in iframe - if (target.self !== target.parent) { - // If in same origin - if (target.origin === targetOrigin) { - // window.parent.window.addEventListener( - // 'mousemove', - // throttle(this._listSameOriginParentWindow.bind(this), 16), - // false); - target.parent.window.addEventListener( - 'mousemove', - this._listSameOriginParentWindow.bind(this), - false - ); - } - } - // @ts-ignore - target = target.parent; - if (!target) { - break; - } - } - } catch (err) { - console.warn(err); - } - } - - _listenHover(e: MouseEvent | TouchEvent): void { - e.preventDefault(); - const p = this._getPosition(e); - if (this._isVaildPoint(p)) { - if (this._event.has('hover')) { - this._event.trigger('hover', p); - } - } - this._isMoving = true; - } - - // _listenLeave(e: MouseEvent|TouchEvent): void { - // e.preventDefault(); - // if (this._event.has('leave')) { - // this._event.trigger('leave', undefined); - // } - // } - - _listenMoveStart(e: MouseEvent | TouchEvent): void { - e.preventDefault(); - const p = this._getPosition(e); - if (this._isVaildPoint(p)) { - if (this._event.has('point')) { - this._event.trigger('point', p); - } - if (this._event.has('moveStart')) { - this._event.trigger('moveStart', p); - } - } - this._isMoving = true; - } - - _listenMove(e: MouseEvent | TouchEvent): void { - e.preventDefault(); - e.stopPropagation(); - if (this._event.has('move') && this._isMoving === true) { - const p = this._getPosition(e); - if (this._isVaildPoint(p)) { - this._event.trigger('move', p); - } - } - } - - _listenMoveEnd(e: MouseEvent | TouchEvent): void { - e.preventDefault(); - if (this._event.has('moveEnd')) { - const p = this._getPosition(e); - if (this._isVaildPoint(p)) { - this._event.trigger('moveEnd', p); - } - } - this._isMoving = false; - } - - _listSameOriginParentWindow() { - if (this._temp.get('isHoverCanvas')) { - if (this._event.has('leave')) { - this._event.trigger('leave', undefined); - } - } - if (this._temp.get('isDragCanvas')) { - if (this._event.has('moveEnd')) { - this._event.trigger('moveEnd', { x: NaN, y: NaN }); - } - } - this._isMoving = false; - this._temp.set('isDragCanvas', false); - this._temp.set('isHoverCanvas', false); - } - - _listenCanvasMoveStart() { - if (this._temp.get('isHoverCanvas')) { - this._temp.set('isDragCanvas', true); - } - } - - _listenCanvasMoveEnd() { - this._temp.set('isDragCanvas', false); - } - - _listenCanvasMoveOver() { - this._temp.set('isHoverCanvas', true); - } - - _listenCanvasMoveLeave() { - this._temp.set('isHoverCanvas', false); - if (this._event.has('leave')) { - this._event.trigger('leave', undefined); - } - } - - // _listenWindowHover(e: MouseEvent|TouchEvent|Event): void { - // if (this._temp.get('isDragCanvas')) { - // return; - // } - // e.preventDefault(); - // const p = this._getPosition(e as MouseEvent|TouchEvent); - // if (this._isVaildPoint(p)) { - // if (this._event.has('hover')) { - // this._event.trigger('hover', p); - // } - // } - // this._isMoving = true; - // } - - // _listenWindowMoveStart(e: MouseEvent|TouchEvent|Event): void { - // if (this._temp.get('isHoverCanvas') !== true) { - // return; - // } - // e.preventDefault(); - // const p = this._getPosition(e as MouseEvent|TouchEvent); - // if (this._isVaildPoint(p)) { - // if (this._event.has('point')) { - // this._event.trigger('point', p); - // } - // if (this._event.has('moveStart')) { - // this._event.trigger('moveStart', p); - // } - // } - // this._isMoving = true; - // } - - _listenWindowMove(e: MouseEvent | TouchEvent | Event): void { - if (this._temp.get('isDragCanvas') !== true) { - return; - } - e.preventDefault(); - e.stopPropagation(); - if (this._event.has('move') && this._isMoving === true) { - const p = this._getPosition(e as MouseEvent | TouchEvent); - if (this._isVaildPoint(p)) { - this._event.trigger('move', p); - } - } - } - - _listenWindowMoveEnd(e: MouseEvent | TouchEvent | Event): void { - if (!this._temp.get('isDragCanvas') === true) { - return; - } - e.preventDefault(); - if (this._event.has('moveEnd')) { - const p = this._getPosition(e as MouseEvent | TouchEvent); - if (this._isVaildPoint(p)) { - this._event.trigger('moveEnd', p); - } - } - this._temp.set('isDragCanvas', false); - this._isMoving = false; - } - - _listenCanvasWheel(e: WheelEvent) { - // e.preventDefault(); - // const { scrollX, scrollY } = this._ctx.getTransform(); - // const { width, height } = this._ctx.getSize(); - if (this._event.has('wheelX') && (e.deltaX > 0 || e.deltaX < 0)) { - this._event.trigger('wheelX', e.deltaX); - } - if (this._event.has('wheelY') && (e.deltaY > 0 || e.deltaY < 0)) { - this._event.trigger('wheelY', e.deltaY); - } - const { canScrollYNext, canScrollYPrev } = this._temp.get('statusMap'); - - if (e.deltaX > 0 && e.deltaX < 0) { - e.preventDefault(); - } else if (e.deltaY > 0 && canScrollYNext === true) { - e.preventDefault(); - } else if (e.deltaY < 0 && canScrollYPrev === true) { - e.preventDefault(); - } - } - - _listenCanvasClick(e: MouseEvent | TouchEvent | Event) { - e.preventDefault(); - const maxLimitTime = 500; - const p = this._getPosition(e as MouseEvent | TouchEvent); - const t = Date.now(); - if (this._isVaildPoint(p)) { - const preClickPoint = this._temp.get('prevClickPoint'); - if ( - preClickPoint && - t - preClickPoint.t <= maxLimitTime && - Math.abs(preClickPoint.x - p.x) <= 5 && - Math.abs(preClickPoint.y - p.y) <= 5 - ) { - if (this._event.has('doubleClick')) { - this._event.trigger('doubleClick', { x: p.x, y: p.y }); - } - } else { - this._temp.set('prevClickPoint', { x: p.x, y: p.y, t }); - } - } - } - - _getPosition(e: MouseEvent | TouchEvent): Point { - const canvas = this._canvas; - let x = 0; - let y = 0; - - // @ts-ignore - if (e && e.touches && e.touches.length > 0) { - // @ts-ignore - const touch: Touch = e.touches[0]; - if (touch) { - x = touch.clientX; - y = touch.clientY; - } - } else { - // @ts-ignore - x = e.clientX; - // @ts-ignore - y = e.clientY; - } - - const p = { - x: x - canvas.getBoundingClientRect().left, - y: y - canvas.getBoundingClientRect().top, - t: Date.now() - }; - return p; - } - - private _isVaildPoint(p: Point): boolean { - return isAvailableNum(p.x) && isAvailableNum(p.y); - } -} - -function isAvailableNum(num: any): boolean { - return num > 0 || num < 0 || num === 0; -} diff --git a/packages/board/src/lib/screen.ts b/packages/board/src/lib/screen.ts deleted file mode 100644 index fd33457..0000000 --- a/packages/board/src/lib/screen.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { - BoardSizeOptions, - ScreenPosition, - IDrawContext, - ScreenSize -} from '@idraw/types'; - -type Options = { - width: number; - height: number; - contextWidth: number; - contextHeight: number; - devicePixelRatio: number; -}; - -const _opts = Symbol('_opts'); -const _ctx = Symbol('_ctx'); - -export class Screen { - private [_opts]: Options; - private [_ctx]: IDrawContext; - - constructor(ctx: IDrawContext, opts: Options) { - this[_opts] = opts; - this[_ctx] = ctx; - } - - resetSize(opts: BoardSizeOptions) { - this[_opts] = { ...this[_opts], ...opts }; - } - - calcScreen(): { - size: ScreenSize; - position: ScreenPosition; - deviceSize: ScreenSize; - width: number; - height: number; - devicePixelRatio: number; - canScrollXPrev: boolean; - canScrollXNext: boolean; - canScrollYPrev: boolean; - canScrollYNext: boolean; - } { - const scaleRatio = this[_ctx].getTransform().scale; - const { - width, - height, - contextWidth, - contextHeight, - devicePixelRatio: pxRatio - } = this[_opts]; - - let canScrollXPrev: boolean = true; - let canScrollXNext: boolean = true; - let canScrollYPrev: boolean = true; - let canScrollYNext: boolean = true; - - // init scroll - if (contextWidth * scaleRatio <= width) { - // make context center - this[_ctx].setTransform({ - scrollX: (width - contextWidth * scaleRatio) / 2 - }); - canScrollXPrev = false; - canScrollXNext = false; - } - - if (contextHeight * scaleRatio <= height) { - // make context center - this[_ctx].setTransform({ - scrollY: (height - contextHeight * scaleRatio) / 2 - }); - canScrollYPrev = false; - canScrollYNext = false; - } - - if ( - contextWidth * scaleRatio >= width && - this[_ctx].getTransform().scrollX > 0 - ) { - this[_ctx].setTransform({ - scrollX: 0 - }); - canScrollXPrev = false; - } - if ( - contextHeight * scaleRatio >= height && - this[_ctx].getTransform().scrollY > 0 - ) { - this[_ctx].setTransform({ - scrollY: 0 - }); - canScrollYPrev = false; - } - - const { scrollX: _scrollX, scrollY: _scrollY } = this[_ctx].getTransform(); - - // reset scroll - if ( - _scrollX < 0 && - Math.abs(_scrollX) > Math.abs(contextWidth * scaleRatio - width) - ) { - this[_ctx].setTransform({ - scrollX: 0 - Math.abs(contextWidth * scaleRatio - width) - }); - canScrollXNext = false; - } - if ( - _scrollY < 0 && - Math.abs(_scrollY) > Math.abs(contextHeight * scaleRatio - height) - ) { - this[_ctx].setTransform({ - scrollY: 0 - Math.abs(contextHeight * scaleRatio - height) - }); - canScrollYNext = false; - } - - // result size - const { scrollX, scrollY } = this[_ctx].getTransform(); - const size = { - x: scrollX * scaleRatio, - y: scrollY * scaleRatio, - w: contextWidth * scaleRatio, - h: contextHeight * scaleRatio - }; - const deviceSize = { - x: scrollX * pxRatio, - y: scrollY * pxRatio, - w: contextWidth * pxRatio * scaleRatio, - h: contextHeight * pxRatio * scaleRatio - }; - const position = { - top: scrollY, - bottom: height - (contextHeight * scaleRatio + scrollY), - left: scrollX, - right: width - (contextWidth * scaleRatio + scrollX) - }; - - return { - size, - position, - deviceSize, - width: this[_opts].width, - height: this[_opts].height, - devicePixelRatio: this[_opts].devicePixelRatio, - canScrollYPrev, - canScrollYNext, - canScrollXPrev, - canScrollXNext - }; - } - - calcScreenScroll( - start: number, - end: number, - sliderSize: number, - limitLen: number, - moveDistance: number - ): number { - let scrollDistance = start; - let scrollLen = limitLen - sliderSize; - if (start <= 0 && end <= 0) { - scrollLen = Math.abs(start) + Math.abs(end); - } - let unit = 1; - if (scrollLen > 0) { - unit = scrollLen / (limitLen - sliderSize); - } - scrollDistance = 0 - unit * moveDistance; - return scrollDistance; - } -} diff --git a/packages/board/src/lib/scroller.ts b/packages/board/src/lib/scroller.ts deleted file mode 100644 index 872fcfa..0000000 --- a/packages/board/src/lib/scroller.ts +++ /dev/null @@ -1,275 +0,0 @@ -import { Point, ScreenPosition, BoardScrollConfig } from '@idraw/types'; -import { isColorStr } from '@idraw/util'; - -type TypeOptions = { - width: number; - height: number; - devicePixelRatio: number; - scrollConfig?: BoardScrollConfig; -}; - -type TypePrivateOptions = Required< - TypeOptions & { scrollConfig: Required } ->; - -const minScrollerWidth = 12; -const scrollerAlpha = 0.12; -const scrollerThumbAlpha = 0.36; - -const defaultScrollConfig: Partial & { - width: number; - color: string; -} = { - width: minScrollerWidth, - color: '#000000', - showBackground: true -}; - -export class Scroller { - private _displayCtx: CanvasRenderingContext2D; - private _opts: TypePrivateOptions; - - constructor(ctx: CanvasRenderingContext2D, opts: TypeOptions) { - this._displayCtx = ctx; - this._opts = this._getOpts(opts); - } - - draw(position: ScreenPosition) { - const { width, height, scrollConfig } = this._opts; - const wrapper = this.calc(position); - const ctx = this._displayCtx; - - if (wrapper.xSize > 0) { - if (scrollConfig.showBackground === true) { - ctx.globalAlpha = scrollerAlpha; - ctx.fillStyle = wrapper.color; - // x-line - ctx.fillRect( - 0, - this._doSize(height - wrapper.lineSize), - this._doSize(width), - this._doSize(wrapper.lineSize) - ); - } - - // ctx.globalAlpha = 1; - // x-slider - drawBoxScrollerThumb(ctx, { - axis: 'X', - x: this._doSize(wrapper.translateX), - y: this._doSize(height - wrapper.lineSize), - w: this._doSize(wrapper.xSize), - h: this._doSize(wrapper.lineSize), - r: this._doSize(wrapper.lineSize / 2), - color: wrapper.color - }); - } - - if (wrapper.ySize > 0) { - if (scrollConfig.showBackground === true) { - ctx.globalAlpha = scrollerAlpha; - ctx.fillStyle = wrapper.color; - // y-line - ctx.fillRect( - this._doSize(width - wrapper.lineSize), - 0, - this._doSize(wrapper.lineSize), - this._doSize(height) - ); - } - - // ctx.globalAlpha = 1; - // y-slider - drawBoxScrollerThumb(ctx, { - axis: 'Y', - x: this._doSize(width - wrapper.lineSize), - y: this._doSize(wrapper.translateY), - w: this._doSize(wrapper.lineSize), - h: this._doSize(wrapper.ySize), - r: this._doSize(wrapper.lineSize / 2), - color: wrapper.color - }); - } - - ctx.globalAlpha = 1; - } - - resetSize(opts: { width: number; height: number; devicePixelRatio: number }) { - this._opts = { ...this._opts, ...opts }; - } - - isPointAtScrollY(p: Point): boolean { - const { width, height, scrollConfig } = this._opts; - const ctx = this._displayCtx; - ctx.beginPath(); - ctx.rect( - this._doSize(width - scrollConfig.width), - 0, - this._doSize(scrollConfig.width), - this._doSize(height) - ); - ctx.closePath(); - if (ctx.isPointInPath(this._doSize(p.x), this._doSize(p.y))) { - return true; - } - return false; - } - - isPointAtScrollX(p: Point): boolean { - const { width, height, scrollConfig } = this._opts; - const ctx = this._displayCtx; - ctx.beginPath(); - ctx.rect( - 0, - this._doSize(height - scrollConfig.width), - this._doSize(width - scrollConfig.width), - this._doSize(scrollConfig.width) - ); - ctx.closePath(); - if (ctx.isPointInPath(this._doSize(p.x), this._doSize(p.y))) { - return true; - } - return false; - } - - getLineWidth(): number { - const lineWidth = this._opts.scrollConfig.width; - return lineWidth; - } - - calc(position: ScreenPosition) { - const { width, height, scrollConfig } = this._opts; - const sliderMinSize = scrollConfig.width * 2.5; - const lineSize = scrollConfig.width; - let xSize = 0; - let ySize = 0; - if (position.left <= 0 && position.right <= 0) { - xSize = Math.max( - sliderMinSize, - width - (Math.abs(position.left) + Math.abs(position.right)) - ); - if (xSize >= width) xSize = 0; - } - if (position.top <= 0 || position.bottom <= 0) { - ySize = Math.max( - sliderMinSize, - height - (Math.abs(position.top) + Math.abs(position.bottom)) - ); - if (ySize >= height) ySize = 0; - } - - let translateX = 0; - if (xSize > 0) { - translateX = - xSize / 2 + - ((width - xSize) * Math.abs(position.left)) / - (Math.abs(position.left) + Math.abs(position.right)); - translateX = Math.min(Math.max(0, translateX - xSize / 2), width - xSize); - // const xUnit = this.calcScreenScrollUnit(position.left, position.right, xSize, width); - // translateX = translateX * xUnit; - } - - let translateY = 0; - if (ySize > 0) { - translateY = - ySize / 2 + - ((height - ySize) * Math.abs(position.top)) / - (Math.abs(position.top) + Math.abs(position.bottom)); - translateY = Math.min( - Math.max(0, translateY - ySize / 2), - height - ySize - ); - // const yUnit = this.calcScreenScrollUnit(position.top, position.bottom, ySize, height); - // translateY = translateY * yUnit; - } - const scrollWrapper = { - lineSize, - xSize, - ySize, - translateY, - translateX, - color: this._opts.scrollConfig.color - }; - return scrollWrapper; - } - - private _doSize(num: number) { - return num * this._opts.devicePixelRatio; - } - - private _getOpts(opts: TypeOptions): TypePrivateOptions { - const options: TypePrivateOptions = { - ...opts, - ...{ - scrollConfig: { ...defaultScrollConfig, ...(opts.scrollConfig || {}) } - } - } as TypePrivateOptions; - if (!options.scrollConfig) { - options.scrollConfig = - defaultScrollConfig as TypePrivateOptions['scrollConfig']; - } - if (!(options?.scrollConfig?.width > 0)) { - options.scrollConfig.width = defaultScrollConfig.width; - } - options.scrollConfig.width = Math.max( - options.scrollConfig.width, - defaultScrollConfig.width - ); - - if (isColorStr(options.scrollConfig.color) !== true) { - options.scrollConfig.color = options.scrollConfig.color; - } - return options; - } -} - -function drawBoxScrollerThumb( - ctx: CanvasRenderingContext2D, - opts: { - axis: 'X' | 'Y'; - x: number; - y: number; - w: number; - h: number; - r: number; - color: string; - } -): void { - let { x, y, h, w } = opts; - const { color, axis } = opts; - if (axis === 'X') { - y = y + h / 4 + 1; - h = h / 2; - } else if (axis === 'Y') { - x = x + w / 4 + 1; - w = w / 2; - } - - let r = opts.r; - r = Math.min(r, w / 2, h / 2); - if (w < r * 2 || h < r * 2) { - r = 0; - } - ctx.globalAlpha = scrollerThumbAlpha; - ctx.beginPath(); - ctx.moveTo(x + r, y); - ctx.arcTo(x + w, y, x + w, y + h, r); - ctx.arcTo(x + w, y + h, x, y + h, r); - ctx.arcTo(x, y + h, x, y, r); - ctx.arcTo(x, y, x + w, y, r); - ctx.closePath(); - ctx.fillStyle = color; - ctx.fill(); - - ctx.globalAlpha = 1; - ctx.beginPath(); - ctx.lineWidth = 1; - ctx.strokeStyle = color; - ctx.moveTo(x + r, y); - ctx.arcTo(x + w, y, x + w, y + h, r); - ctx.arcTo(x + w, y + h, x, y + h, r); - ctx.arcTo(x, y + h, x, y, r); - ctx.arcTo(x, y, x + w, y, r); - ctx.closePath(); - ctx.stroke(); -} diff --git a/packages/board/src/lib/sharer.ts b/packages/board/src/lib/sharer.ts new file mode 100644 index 0000000..1bd31fa --- /dev/null +++ b/packages/board/src/lib/sharer.ts @@ -0,0 +1,61 @@ +import type { ActiveStore, StoreSharer } from '@idraw/types'; +import { Store } from '@idraw/util'; + +const defaultActiveStorage: ActiveStore = { + contextWidth: 0, + contextHeight: 0, + data: null, + selectedUUIDs: [] as string[], + selectedIndexs: [] as number[], + scale: 1, + offsetLeft: 0, + offsetRight: 0, + offsetTop: 0, + offsetBottom: 0 +}; + +export class Sharer implements StoreSharer { + private _activeStore: Store; + private _sharedStore: Store<{ + [string: string]: any; + }>; + + constructor() { + const activeStore = new Store({ + defaultStorage: defaultActiveStorage + }); + const sharedStore = new Store({ + defaultStorage: {} + }); + this._activeStore = activeStore; + this._sharedStore = sharedStore; + } + + drawFrame(): void { + // TODO + } + + getActiveStorage(key: T): ActiveStore[T] { + return this._activeStore.get(key); + } + + setActiveStorage(key: T, storage: ActiveStore[T]) { + return this._activeStore.set(key, storage); + } + + getActiveStoreSnapshot(): ActiveStore { + return this._activeStore.getSnapshot(); + } + + getSharedStorage(key: string): any { + return this._sharedStore.get(key); + } + + setSharedStorage(key: string, storage: any) { + return this._sharedStore.set(key, storage); + } + + getSharedStoreSnapshot(): Record { + return this._sharedStore.getSnapshot(); + } +} diff --git a/packages/board/src/lib/style.ts b/packages/board/src/lib/style.ts deleted file mode 100644 index e232250..0000000 --- a/packages/board/src/lib/style.ts +++ /dev/null @@ -1,95 +0,0 @@ -import istype from './istype'; - -export const mergeCSS2StyleAttr = function( - cssMap: {[key: string]: string} = {} -): string { - const cssList = []; - if (istype.json(cssMap) === true) { - for (const key in cssMap) { - let cssKey = `${key}`; - let cssVal = `${cssMap[key]}`; - cssKey = cssKey.trim(); - cssVal = cssVal.trim(); - cssList.push(`${cssKey}:${cssVal}`); - } - } - const styleAttr = cssList.join('; ') + ';'; - return styleAttr; -}; - - -export function setStyle( - dom: HTMLElement, - style: {[key: string]: string} -): void { - const originStyle = getStyle(dom); - const _style = {...originStyle, ...style}; - const keys: string[] = Object.keys(_style); - let styleStr = ''; - keys.forEach((key: string) => { - styleStr += `${key}:${_style[key] || ''};`; - }); - dom.setAttribute('style', styleStr); -} - -export function getStyle(dom: HTMLElement): {[key: string]: string} { - const styleObj: {[key: string]: string} = {}; - const style = dom.getAttribute('style') || ''; - const styleList = style.split(';'); - styleList.forEach((item: string) => { - const dataList = item.split(':'); - if (dataList[0] && typeof dataList[0] === 'string') { - styleObj[dataList[0]] = dataList[1] || ''; - } - }); - - return styleObj; -} - -export function getDomTransform(dom: HTMLElement): { - scaleX: number; - skewY: number; - skewX: number; - scaleY: number; - translateX: number; - translateY: number; -} { - // transform: matrix( scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY() ) - // matrix(1, 0, 0, 1, 0, 0) - const style = getComputedStyle(dom) || {}; - const { transform } = style; - const matrixStr = transform.replace(/^matrix\(|\)$/ig, ''); - const matrixList = matrixStr.split(',').map((str, i) => { - const val = parseFloat(str); - if ([0, 3].indexOf(i) >= 0) { - return isNaN(val) ? 1 : val; - } else { - return isNaN(val) ? 0 : val; - } - }); - const matrix = { - scaleX: matrixList[0], - skewY: matrixList[1] || 0, - skewX: matrixList[2] || 0, - scaleY: matrixList[3] || 1, - translateX: matrixList[4] || 0, - translateY: matrixList[5] || 0, - }; - return matrix; -} - - -export function setDomTransform(dom: HTMLElement, matrix: { - scaleX: number; - skewY: number; - skewX: number; - scaleY: number; - translateX: number; - translateY: number; -}): void { - // transform: matrix( scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY() ) - // matrix(1, 2, -1, 1, 80, 80) - - const transform = `matrix(${matrix.scaleX}, ${matrix.skewY}, ${matrix.skewX}, ${matrix.scaleY}, ${matrix.translateX}, ${matrix.translateY})`; - dom.style.setProperty('transform', transform); -} diff --git a/packages/board/src/lib/temp.ts b/packages/board/src/lib/temp.ts deleted file mode 100644 index 5d7755b..0000000 --- a/packages/board/src/lib/temp.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { BoardOptions, IDrawContext } from '@idraw/types'; -import { Context } from '@idraw/util'; - -type TempDataDesc = { - ctx: IDrawContext; -}; - -function createDefaultData(opts: BoardOptions) { - const canvas = document.createElement('canvas'); - const ctx2d = canvas.getContext('2d') as CanvasRenderingContext2D; - const ctx = new Context(ctx2d, { - width: opts.width, - height: opts.height, - contextWidth: opts.contextWidth, - contextHeight: opts.contextHeight, - devicePixelRatio: opts.devicePixelRatio || window.devicePixelRatio || 1 - }); - - return { - plugins: [], - ctx: ctx - }; -} - -export class TempData { - private _temp: TempDataDesc; - - constructor(opts: BoardOptions) { - this._temp = createDefaultData(opts); - } - - set(name: T, value: TempDataDesc[T]) { - this._temp[name] = value; - } - - get(name: T): TempDataDesc[T] { - return this._temp[name]; - } - - clear(opts: BoardOptions) { - this._temp = createDefaultData(opts); - } -} diff --git a/packages/board/src/lib/viewer.ts b/packages/board/src/lib/viewer.ts new file mode 100644 index 0000000..7239339 --- /dev/null +++ b/packages/board/src/lib/viewer.ts @@ -0,0 +1,77 @@ +import { EventEmitter } from '@idraw/util'; +import type { BoardViewer, BoardViewerEventMap, BoardViewerOptions, ActiveStore, BoardViewerFrameSnapshot } from '@idraw/types'; + +const { requestAnimationFrame } = window; + +type ViewerDrawFrameStatus = 'DRAWING' | 'FREE' | 'COMPLETE'; + +export class Viewer extends EventEmitter implements BoardViewer { + private _opts: BoardViewerOptions; + private _drawFrameSnapshotQueue: BoardViewerFrameSnapshot[] = []; + private _drawFrameStatus: ViewerDrawFrameStatus = 'FREE'; + + constructor(opts: BoardViewerOptions) { + super(); + this._opts = opts; + this._init(); + } + + private _init() { + const { renderer } = this._opts; + renderer.on('load', () => { + this.drawFrame(); + }); + } + + private _drawAnimationFrame() { + if (this._drawFrameStatus === 'DRAWING' || this._drawFrameSnapshotQueue.length === 0) { + return; + } else { + this._drawFrameStatus = 'DRAWING'; + } + const snapshot = this._drawFrameSnapshotQueue.shift(); + const { renderer, viewContent, beforeDrawFrame, afterDrawFrame } = this._opts; + + if (snapshot) { + const { viewContext, helperContext, boardContext } = viewContent; + if (snapshot?.activeStore.data) { + renderer.drawData(snapshot.activeStore.data, { + scale: snapshot?.activeStore.scale, + offsetTop: snapshot?.activeStore.offsetTop, + offsetBottom: snapshot?.activeStore.offsetBottom, + offsetLeft: snapshot?.activeStore.offsetLeft, + offsetRight: snapshot?.activeStore.offsetRight + }); + } + beforeDrawFrame({ snapshot }); + const { width, height } = boardContext.canvas; + boardContext.clearRect(0, 0, width, height); + boardContext.drawImage(viewContext.canvas, 0, 0, width, height); + boardContext.drawImage(helperContext.canvas, 0, 0, width, height); + viewContext.clearRect(0, 0, width, height); + helperContext.clearRect(0, 0, width, height); + afterDrawFrame({ snapshot }); + } + + if (this._drawFrameSnapshotQueue.length === 0) { + this._drawFrameStatus = 'COMPLETE'; + return; + } + if ((this._drawFrameStatus = 'DRAWING')) { + requestAnimationFrame(() => { + this._drawAnimationFrame(); + }); + } + } + + drawFrame(): void { + const { sharer } = this._opts; + const activeStore: ActiveStore = sharer.getActiveStoreSnapshot(); + const sharedStore: Record = sharer.getSharedStoreSnapshot(); + this._drawFrameSnapshotQueue.push({ + activeStore, + sharedStore + }); + this._drawAnimationFrame(); + } +} diff --git a/packages/board/src/lib/watcher-temp.ts b/packages/board/src/lib/watcher-temp.ts deleted file mode 100644 index b9dca12..0000000 --- a/packages/board/src/lib/watcher-temp.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Point } from '@idraw/types'; - -type TempDataDesc = { - prevClickPoint: (Point & { t: number }) | null; - isHoverCanvas: boolean; - isDragCanvas: boolean; - statusMap: { - canScrollYPrev: boolean; - canScrollYNext: boolean; - canScrollXPrev: boolean; - canScrollXNext: boolean; - }; -}; - -function createTempData() { - return { - prevClickPoint: null, - isHoverCanvas: false, - isDragCanvas: false, - statusMap: { - canScrollYPrev: true, - canScrollYNext: true, - canScrollXPrev: true, - canScrollXNext: true - } - }; -} - -export class TempData { - private _temp: TempDataDesc; - - constructor() { - this._temp = createTempData(); - } - - set(name: T, value: TempDataDesc[T]) { - this._temp[name] = value; - } - - get(name: T): TempDataDesc[T] { - return this._temp[name]; - } - - clear() { - this._temp = createTempData(); - } -} diff --git a/packages/board/src/lib/watcher.ts b/packages/board/src/lib/watcher.ts index fc1f7b9..127d721 100644 --- a/packages/board/src/lib/watcher.ts +++ b/packages/board/src/lib/watcher.ts @@ -1,177 +1,69 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { Point } from '@idraw/types'; -import { BoardEvent, TypeBoardEventArgMap } from './event'; -import { TempData } from './watcher-temp'; +import type { Point, BoardWatcherEventMap, ViewContent, Data, Element, ElementType } from '@idraw/types'; +import { EventEmitter } from '@idraw/util'; -export class Watcher { - private _canvas: HTMLCanvasElement; - private _isMoving = false; - // private _onMove?: TypeWatchCallback; - // private _onMoveStart?: TypeWatchCallback; - // private _onMoveEnd?: TypeWatchCallback; - private _event: BoardEvent; - private _temp: TempData = new TempData(); +type WatcherOptions = { viewContent: ViewContent }; - constructor(canvas: HTMLCanvasElement) { - this._canvas = canvas; - this._isMoving = false; - this._initEvent(); - this._event = new BoardEvent(); +export class BoardWatcher extends EventEmitter { + private _opts: WatcherOptions; + constructor(opts: WatcherOptions) { + super(); + this._opts = opts; + this._init(); } - on( - name: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ): void { - this._event.on(name, callback); + private _init() { + const boardCanvas = this._opts.viewContent.boardContext.canvas; + boardCanvas.addEventListener('mousemove', (e: MouseEvent) => { + const point = this._getPoint(e); + this.trigger('hover', { point }); + }); + boardCanvas.addEventListener('mousedown', (e: MouseEvent) => { + const point = this._getPoint(e); + this.trigger('pointStart', { point }); + }); + boardCanvas.addEventListener('mousemove', (e: MouseEvent) => { + const point = this._getPoint(e); + this.trigger('pointMove', { point }); + }); + boardCanvas.addEventListener('mouseup', (e: MouseEvent) => { + const point = this._getPoint(e); + this.trigger('pointEnd', { point }); + }); + boardCanvas.addEventListener('mouseleave', (e: MouseEvent) => { + const point = this._getPoint(e); + this.trigger('pointLeave', { point }); + }); } - off( - name: T, - callback: (p: TypeBoardEventArgMap[T]) => void - ): void { - this._event.off(name, callback); - } - - _initEvent(): void { - const canvas = this._canvas; - canvas.addEventListener('mousemove', this._listenHover.bind(this), true); - canvas.addEventListener( - 'mousedown', - this._listenMoveStart.bind(this), - true - ); - canvas.addEventListener('mousemove', this._listenMove.bind(this), true); - canvas.addEventListener('mouseup', this._listenMoveEnd.bind(this), true); - canvas.addEventListener('mouseleave', this._listenMoveEnd.bind(this), true); - canvas.addEventListener('mouseleave', this._listenLeave.bind(this), true); - canvas.addEventListener('click', this._listenClick.bind(this), true); - canvas.addEventListener('wheel', this._listenWheel.bind(this), true); - - canvas.addEventListener( - 'touchstart', - this._listenMoveStart.bind(this), - true - ); - canvas.addEventListener('touchmove', this._listenMove.bind(this), true); - canvas.addEventListener('touchend', this._listenMoveEnd.bind(this), true); - } - - _listenHover(e: MouseEvent | TouchEvent): void { - e.preventDefault(); - const p = this._getPosition(e); - if (this._isVaildPoint(p)) { - if (this._event.has('hover')) { - this._event.trigger('hover', p); - } - } - this._isMoving = true; - } - - _listenLeave(e: MouseEvent | TouchEvent): void { - e.preventDefault(); - if (this._event.has('leave')) { - this._event.trigger('leave', undefined); - } - } - - _listenMoveStart(e: MouseEvent | TouchEvent): void { - e.preventDefault(); - const p = this._getPosition(e); - if (this._isVaildPoint(p)) { - if (this._event.has('point')) { - this._event.trigger('point', p); - } - if (this._event.has('moveStart')) { - this._event.trigger('moveStart', p); - } - } - this._isMoving = true; - } - - _listenMove(e: MouseEvent | TouchEvent): void { - e.preventDefault(); - e.stopPropagation(); - if (this._event.has('move') && this._isMoving === true) { - const p = this._getPosition(e); - if (this._isVaildPoint(p)) { - this._event.trigger('move', p); - } - } - } - - _listenMoveEnd(e: MouseEvent | TouchEvent): void { - e.preventDefault(); - if (this._event.has('moveEnd')) { - const p = this._getPosition(e); - if (this._isVaildPoint(p)) { - this._event.trigger('moveEnd', p); - } - } - this._isMoving = false; - } - - _listenWheel(e: WheelEvent) { - e.preventDefault(); - if (this._event.has('wheelX') && (e.deltaX > 0 || e.deltaX < 0)) { - this._event.trigger('wheelX', e.deltaX); - } - if (this._event.has('wheelY') && (e.deltaY > 0 || e.deltaY < 0)) { - this._event.trigger('wheelY', e.deltaY); - } - } - - _listenClick(e: MouseEvent | TouchEvent) { - e.preventDefault(); - const maxLimitTime = 500; - const p = this._getPosition(e); - const t = Date.now(); - if (this._isVaildPoint(p)) { - const preClickPoint = this._temp.get('prevClickPoint'); - if ( - preClickPoint && - t - preClickPoint.t <= maxLimitTime && - Math.abs(preClickPoint.x - p.x) <= 5 && - Math.abs(preClickPoint.y - p.y) <= 5 - ) { - if (this._event.has('doubleClick')) { - this._event.trigger('doubleClick', { x: p.x, y: p.y }); - } - } else { - this._temp.set('prevClickPoint', { x: p.x, y: p.y, t }); - } - } - } - - _getPosition(e: MouseEvent | TouchEvent): Point { - const canvas = this._canvas; - let x = 0; - let y = 0; - - // @ts-ignore - if (e && e.touches && e.touches.length > 0) { - // @ts-ignore - const touch: Touch = e.touches[0]; - if (touch) { - x = touch.clientX; - y = touch.clientY; - } - } else { - // @ts-ignore - x = e.clientX; - // @ts-ignore - y = e.clientY; - } - - const p = { - x: x - canvas.getBoundingClientRect().left, - y: y - canvas.getBoundingClientRect().top, + private _getPoint(e: MouseEvent): Point { + const boardCanvas = this._opts.viewContent.boardContext.canvas; + const rect = boardCanvas.getBoundingClientRect(); + const p: Point = { + x: e.clientX - rect.left, + y: e.clientY - rect.top, t: Date.now() }; return p; } - - private _isVaildPoint(p: Point): boolean { - return p.x > 0 && p.y > 0; - } +} + +interface PointResult { + index: number; + element: Element | null; +} + +export function getPointResult(p: Point, data: Data): PointResult { + const result: PointResult = { + index: -1, + element: null + }; + for (let i = 0; i < data.elements.length; i++) { + const elem = data.elements[i]; + if (p.x >= elem.x && p.x <= elem.x + elem.w && p.y >= elem.y && p.y <= elem.y + elem.h) { + result.index = i; + result.element = elem; + break; + } + } + return result; } diff --git a/packages/core/src/constant/element.ts b/packages/core/src/constant/element.ts deleted file mode 100644 index b2bbcdb..0000000 --- a/packages/core/src/constant/element.ts +++ /dev/null @@ -1,15 +0,0 @@ - -const elementTypes = { - 'text': {}, // TODO - 'rect': {}, // TODO - 'image': {}, // TODO - 'svg': {}, // TODO - 'circle': {}, // TODO - 'html': {}, // TODO -}; - -export const elementNames = Object.keys(elementTypes); - - -// limitQbliqueAngle -export const LIMIT_QBLIQUE_ANGLE = 15; \ No newline at end of file diff --git a/packages/core/src/constant/static.ts b/packages/core/src/constant/static.ts deleted file mode 100644 index 80815e8..0000000 --- a/packages/core/src/constant/static.ts +++ /dev/null @@ -1,12 +0,0 @@ -export enum Mode { - NULL = 'null', - SELECT_ELEMENT = 'select-element', - SELECT_ELEMENT_LIST = 'select-element-list', - SELECT_ELEMENT_WRAPPER_CONTROLLER = 'select-element-wrapper-controller', - SELECT_AREA = 'select-area', -} - -export enum CursorStatus { - DRAGGING = 'dragging', - NULL = 'null', -} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 92f6495..6233b15 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,327 +1,32 @@ -import { - IDrawData, - Point, - BoardSizeOptions, - IDrawConfig, - IDrawConfigStrict, - DataElementBase, - DataElement, - DataElemDesc, - IDrawContext, - CoreOptions, - ScreenContext, - ScreenData -} from '@idraw/types'; -import Board from '@idraw/board'; -import { deepClone } from '@idraw/util'; -import Renderer from '@idraw/renderer'; -import is, { IsTypeUtil } from './lib/is'; -import check, { CheckTypeUtil } from './lib/check'; -import { - Element, - mergeConfig, - CoreEvent, - TypeCoreEventArgMap, - parseData, - TempData, - diffElementResourceChangeList -} from './lib'; -import { - getSelectedElements, - updateElement, - selectElementByIndex, - selectElement, - cancelElementByIndex, - cancelElement, - getElement, - getElementByIndex, - moveUpElement, - moveDownElement, - addElement, - deleteElement, - insertElementBefore, - insertElementBeforeIndex, - insertElementAfter, - insertElementAfterIndex -} from './mixins/element'; -// import { initEvent } from './mixins/event'; -import { Engine } from './lib/engine'; -import { - drawElementWrapper, - drawAreaWrapper, - drawElementListWrappers -} from './lib/draw/wrapper'; +import type { Data, BoardOptions, CoreOptions, BoardMiddleware } from '@idraw/types'; +import { Board } from '@idraw/board'; +import { createBoardContexts } from '@idraw/util'; -export default class Core { - $data: IDrawData; +export { MiddlewareSelector } from './middleware/select'; + +export class Core { private _board: Board; private _opts: CoreOptions; - private _config: IDrawConfigStrict; - private _renderer: Renderer; - private _elementHandler: Element; - private _coreEvent: CoreEvent = new CoreEvent(); - private _tempData: TempData = new TempData(); - private _engine: Engine; - - static is: IsTypeUtil = is; - static check: CheckTypeUtil = check; - - constructor(mount: HTMLDivElement, opts: CoreOptions, config?: IDrawConfig) { - this.$data = { elements: [] }; + private _mount: HTMLDivElement; + constructor(mount: HTMLDivElement, opts: CoreOptions) { this._opts = opts; - this._config = mergeConfig(config || {}); - this._board = new Board(mount, { - ...this._opts, - canScroll: config?.scrollWrapper?.use, - scrollConfig: { - color: config?.scrollWrapper?.color || '#000000', - width: config?.scrollWrapper?.width || 12, - ...(config?.scrollWrapper || {}) - } - }); - this._renderer = new Renderer(); - const drawFrame = () => { - const helperCtx = this._board.getHelperContext(); - const helperConfig = this._engine.getHelperConfig(); - this._board.clear(); - const { contextWidth, contextHeight, devicePixelRatio } = this._opts; - helperCtx.clearRect( - 0, - 0, - contextWidth * devicePixelRatio, - contextHeight * devicePixelRatio - ); - drawElementWrapper(helperCtx, helperConfig); - drawAreaWrapper(helperCtx, helperConfig); - drawElementListWrappers(helperCtx, helperConfig); - this._board.draw(); - }; - this._renderer.on('drawFrame', () => { - drawFrame(); - }); - this._renderer.on('drawFrameComplete', () => { - drawFrame(); - }); - this._elementHandler = new Element(this._board.getContext()); - this._engine = new Engine({ - coreEvent: this._coreEvent, - board: this._board, - element: this._elementHandler, - config: this._config, - drawFeekback: this.$draw.bind(this), - getDataFeekback: () => this.$data, - selectElementByIndex: this.selectElementByIndex.bind(this), - emitChangeScreen: this._emitChangeScreen.bind(this), - emitChangeData: this.$emitChangeData.bind(this) - }); - this._engine.init(); + this._mount = mount; + const canvas = document.createElement('canvas'); + canvas.width = opts.width; + canvas.height = opts.height; + mount.appendChild(canvas); - this._renderer.on('drawFrame', () => { - this._coreEvent.trigger('drawFrame', undefined); - }); - this._renderer.on('drawFrameComplete', () => { - this._coreEvent.trigger('drawFrameComplete', undefined); - }); - - this._tempData.set('hasInited', true); + const ctx = canvas.getContext('2d') as CanvasRenderingContext2D; + const viewContent = createBoardContexts(ctx); + const board = new Board({ viewContent }); + this._board = board; } - private _emitChangeScreen() { - if (this._coreEvent.has('changeScreen')) { - this._coreEvent.trigger('changeScreen', { - ...this.getScreenTransform() - }); - } + use(middleware: BoardMiddleware) { + this._board.use(middleware); } - $draw(opts?: { resourceChangeUUIDs?: string[] }): void { - this._engine.updateHelperConfig({ - width: this._opts.width, - height: this._opts.height, - devicePixelRatio: this._opts.devicePixelRatio - }); - - this._renderer.thaw(); - this._renderer.render(this._board.getContext(), this.$data, { - changeResourceUUIDs: opts?.resourceChangeUUIDs || [] - }); - } - - getElement(uuid: string) { - return getElement(this, uuid); - } - - getElementByIndex(index: number) { - return getElementByIndex(this, index); - } - - selectElementByIndex(index: number): void { - return selectElementByIndex(this, index); - } - - selectElement(uuid: string): void { - return selectElement(this, uuid); - } - - cancelElementByIndex(index: number): void { - return cancelElementByIndex(this, index); - } - - cancelElement(uuid: string): void { - return cancelElement(this, uuid); - } - - moveUpElement(uuid: string): void { - return moveUpElement(this, uuid); - } - - moveDownElement(uuid: string): void { - return moveDownElement(this, uuid); - } - - updateElement(elem: DataElement) { - return updateElement(this, elem); - } - - addElement(elem: DataElementBase): string | null { - return addElement(this, elem); - } - - deleteElement(uuid: string) { - return deleteElement(this, uuid); - } - - insertElementBefore( - elem: DataElementBase, - beforeUUID: string - ) { - return insertElementBefore(this, elem, beforeUUID); - } - - insertElementBeforeIndex( - elem: DataElementBase, - index: number - ) { - return insertElementBeforeIndex(this, elem, index); - } - - getSelectedElements() { - return getSelectedElements(this); - } - - insertElementAfter( - elem: DataElementBase, - beforeUUID: string - ) { - return insertElementAfter(this, elem, beforeUUID); - } - - insertElementAfterIndex( - elem: DataElementBase, - index: number - ) { - return insertElementAfterIndex(this, elem, index); - } - - resetSize(opts: BoardSizeOptions) { - this._opts = { ...this._opts, ...opts }; - this._board.resetSize(opts); - this.$draw(); - } - - scale(ratio: number): ScreenContext { - const screen = this._board.scale(ratio); - this.$draw(); - this._emitChangeScreen(); - return screen; - } - - scrollLeft(left: number): ScreenContext { - const screen = this._board.scrollX(0 - left); - this.$draw(); - this._emitChangeScreen(); - return screen; - } - - scrollTop(top: number): ScreenContext { - const screen = this._board.scrollY(0 - top); - this.$draw(); - this._emitChangeScreen(); - return screen; - } - - getScreenTransform(): ScreenData { - const transform = this._board.getTransform(); - return { - scale: transform.scale, - scrollTop: Math.max(0, 0 - transform.scrollY), - scrollLeft: Math.max(0, 0 - transform.scrollX) - }; - } - - getData(): IDrawData { - return deepClone(this.$data); - } - - setData(data: any | IDrawData, opts?: { triggerChangeEvent: boolean }): void { - const resourceChangeUUIDs = diffElementResourceChangeList(this.$data, data); - this.$data = this._elementHandler.initData(deepClone(parseData(data))); - if (opts && opts.triggerChangeEvent === true) { - this.$emitChangeData(); - } - this.$draw({ resourceChangeUUIDs }); - } - - clearOperation() { - this._tempData.clear(); - this.$draw(); - } - - on( - key: T, - callback: (p: TypeCoreEventArgMap[T]) => void - ) { - this._coreEvent.on(key, callback); - } - - off( - key: T, - callback: (p: TypeCoreEventArgMap[T]) => void - ) { - this._coreEvent.off(key, callback); - } - - getEngine() { - return this._engine; - } - - pointScreenToContext(p: Point) { - return this._board.pointScreenToContext(p); - } - - pointContextToScreen(p: Point) { - return this._board.pointContextToScreen(p); - } - - $getBoardContext(): IDrawContext { - return this._board.getContext(); - } - - $getDisplayContext2D(): CanvasRenderingContext2D { - return this._board.getDisplayContext2D(); - } - - $getOriginContext2D(): CanvasRenderingContext2D { - return this._board.getOriginContext2D(); - } - - $emitChangeData() { - if (this._coreEvent.has('changeData')) { - this._coreEvent.trigger('changeData', deepClone(this.$data)); - } - } - - $getElementHandler() { - return this._elementHandler; + setData(data: Data) { + this._board.setData(data); } } diff --git a/packages/core/src/lib/calculate.ts b/packages/core/src/lib/calculate.ts deleted file mode 100644 index 14c8bc4..0000000 --- a/packages/core/src/lib/calculate.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { DataElement, DataElemDesc, Point } from '@idraw/types'; - -export function parseRadianToAngle(radian: number): number { - return (radian / Math.PI) * 180; -} - -export function parseAngleToRadian(angle: number): number { - return (angle / 180) * Math.PI; -} - -export function calcElementCenter( - elem: DataElement -): Point { - const p = { - x: elem.x + elem.w / 2, - y: elem.y + elem.h / 2 - }; - return p; -} - -export function calcRadian(center: Point, start: Point, end: Point): number { - const startAngle = calcLineAngle(center, start); - const endAngle = calcLineAngle(center, end); - if (endAngle !== null && startAngle !== null) { - if (startAngle > (Math.PI * 3) / 2 && endAngle < Math.PI / 2) { - return endAngle + (Math.PI * 2 - startAngle); - } else if (endAngle > (Math.PI * 3) / 2 && startAngle < Math.PI / 2) { - return startAngle + (Math.PI * 2 - endAngle); - } else { - return endAngle - startAngle; - } - } else { - return 0; - } -} - -function calcLineAngle(center: Point, p: Point): number | null { - const x = p.x - center.x; - const y = center.y - p.y; - if (x === 0) { - if (y < 0) { - return Math.PI / 2; - } else if (y > 0) { - return Math.PI * (3 / 2); - } - } else if (y === 0) { - if (x < 0) { - return Math.PI; - } else if (x > 0) { - return 0; - } - } - if (x > 0 && y < 0) { - return Math.atan(Math.abs(y) / Math.abs(x)); - } else if (x < 0 && y < 0) { - return Math.PI - Math.atan(Math.abs(y) / Math.abs(x)); - } else if (x < 0 && y > 0) { - return Math.PI + Math.atan(Math.abs(y) / Math.abs(x)); - } else if (x > 0 && y > 0) { - return Math.PI * 2 - Math.atan(Math.abs(y) / Math.abs(x)); - } - return null; -} diff --git a/packages/core/src/lib/check.ts b/packages/core/src/lib/check.ts deleted file mode 100644 index 7a4adb4..0000000 --- a/packages/core/src/lib/check.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { DataElementAttrs } from '@idraw/types'; -import is from './is'; - -function attrs(attrs: DataElementAttrs): boolean { - const { x, y, w, h, angle } = attrs; - if (!(is.x(x) && is.y(y) && is.w(w) && is.h(h) && is.angle(angle))) { - return false; - } - if (!(angle >= -360 && angle <= 360)) { - return false; - } - return true; -} - -function box(desc: any = {}): boolean { - const { borderColor, borderRadius, borderWidth } = desc; - if (desc.hasOwnProperty('borderColor') && !is.color(borderColor)) { - return false; - } - if (desc.hasOwnProperty('borderRadius') && !is.number(borderRadius)) { - return false; - } - if (desc.hasOwnProperty('borderWidth') && !is.number(borderWidth)) { - return false; - } - return true; -} - -function rectDesc(desc: any): boolean { - const { bgColor } = desc; - if (desc.hasOwnProperty('bgColor') && !is.color(bgColor)) { - return false; - } - if (!box(desc)) { - return false; - } - return true; -} - -function circleDesc(desc: any): boolean { - const { bgColor, borderColor, borderWidth } = desc; - if (desc.hasOwnProperty('bgColor') && !is.color(bgColor)) { - return false; - } - if (desc.hasOwnProperty('borderColor') && !is.color(borderColor)) { - return false; - } - if (desc.hasOwnProperty('borderWidth') && !is.number(borderWidth)) { - return false; - } - return true; -} - -function imageDesc(desc: any): boolean { - const { src } = desc; - if (!is.imageSrc(src)) { - return false; - } - return true; -} - -function svgDesc(desc: any): boolean { - const { svg } = desc; - if (!is.svg(svg)) { - return false; - } - return true; -} - -function htmlDesc(desc: any): boolean { - const { html } = desc; - if (!is.html(html)) { - return false; - } - return true; -} - -function textDesc(desc: any): boolean { - const { - text, - color, - fontSize, - lineHeight, - fontFamily, - textAlign, - fontWeight, - bgColor, - strokeWidth, - strokeColor - } = desc; - if (!is.text(text)) { - return false; - } - if (!is.color(color)) { - return false; - } - if (!is.fontSize(fontSize)) { - return false; - } - if (desc.hasOwnProperty('bgColor') && !is.color(bgColor)) { - return false; - } - if (desc.hasOwnProperty('fontWeight') && !is.fontWeight(fontWeight)) { - return false; - } - if (desc.hasOwnProperty('lineHeight') && !is.lineHeight(lineHeight)) { - return false; - } - if (desc.hasOwnProperty('fontFamily') && !is.fontFamily(fontFamily)) { - return false; - } - if (desc.hasOwnProperty('textAlign') && !is.textAlign(textAlign)) { - return false; - } - if (desc.hasOwnProperty('strokeWidth') && !is.strokeWidth(strokeWidth)) { - return false; - } - if (desc.hasOwnProperty('strokeColor') && !is.color(strokeColor)) { - return false; - } - - if (!box(desc)) { - return false; - } - return true; -} - -const check = { - attrs, - textDesc, - rectDesc, - circleDesc, - imageDesc, - svgDesc, - htmlDesc -}; - -type CheckTypeUtil = { - attrs: (value: any) => boolean; - rectDesc: (value: any) => boolean; - circleDesc: (value: any) => boolean; - imageDesc: (value: any) => boolean; - svgDesc: (value: any) => boolean; - htmlDesc: (value: any) => boolean; - textDesc: (value: any) => boolean; -}; - -export { CheckTypeUtil }; - -export default check; diff --git a/packages/core/src/lib/config.ts b/packages/core/src/lib/config.ts deleted file mode 100644 index db1ce07..0000000 --- a/packages/core/src/lib/config.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { IDrawConfig, IDrawConfigStrict } from '@idraw/types'; -import { deepClone } from '@idraw/util'; - -const defaultConfig: IDrawConfigStrict = { - elementWrapper: { - color: '#0d85da', - lockColor: '#aaaaaa', - controllerSize: 6, - lineWidth: 1, - lineDash: [4, 3] - } -}; - -function mergeConfig(config?: IDrawConfig): IDrawConfigStrict { - const result = deepClone(defaultConfig); - if (config) { - if (config.elementWrapper) { - result.elementWrapper = { - ...result.elementWrapper, - ...config.elementWrapper - }; - } - } - return result; -} - -export { mergeConfig }; diff --git a/packages/core/src/lib/core-event.ts b/packages/core/src/lib/core-event.ts deleted file mode 100644 index fe16e5a..0000000 --- a/packages/core/src/lib/core-event.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { - DataElement, - DataElemDesc, - Point, - IDrawData, - ScreenData -} from '@idraw/types'; - -export type TypeCoreEventSelectBaseArg = { - index: number | null; - uuid: string | null; -}; - -export type TypeCoreEventArgMap = { - error: any; - mouseOverScreen: Point; - mouseLeaveScreen: void; - mouseOverElement: TypeCoreEventSelectBaseArg & { - element: DataElement; - }; - mouseLeaveElement: TypeCoreEventSelectBaseArg & { - element: DataElement; - }; - screenClickElement: TypeCoreEventSelectBaseArg & { - element: DataElement; - }; - screenDoubleClickElement: TypeCoreEventSelectBaseArg & { - element: DataElement; - }; - screenSelectElement: TypeCoreEventSelectBaseArg & { - element: DataElement; - }; - screenMoveElementStart: TypeCoreEventSelectBaseArg & Point; - screenMoveElementEnd: TypeCoreEventSelectBaseArg & Point; - screenChangeElement: TypeCoreEventSelectBaseArg & { - width: number; - height: number; - angle: number; - }; - changeData: IDrawData; - changeScreen: ScreenData; - drawFrameComplete: void; - drawFrame: void; -}; - -export interface TypeCoreEvent { - on( - key: T, - callback: (p: TypeCoreEventArgMap[T]) => void - ): void; - off( - key: T, - callback: (p: TypeCoreEventArgMap[T]) => void - ): void; - trigger( - key: T, - p: TypeCoreEventArgMap[T] - ): void; -} - -export class CoreEvent implements TypeCoreEvent { - private _listeners: Map void)[]>; - - constructor() { - this._listeners = new Map(); - } - - on( - eventKey: T, - callback: (p: TypeCoreEventArgMap[T]) => void - ) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - callbacks?.push(callback); - this._listeners.set(eventKey, callbacks || []); - } else { - this._listeners.set(eventKey, [callback]); - } - } - - off( - eventKey: T, - callback: (p: TypeCoreEventArgMap[T]) => void - ) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - for (let i = 0; i < callbacks?.length; i++) { - if (callbacks[i] === callback) { - callbacks.splice(i, 1); - break; - } - } - } - this._listeners.set(eventKey, callbacks || []); - } - } - - trigger( - eventKey: T, - arg: TypeCoreEventArgMap[T] - ) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - callbacks.forEach((cb) => { - cb(arg); - }); - return true; - } else { - return false; - } - } - - has(name: string) { - if (this._listeners.has(name)) { - const list: ((p: TypeCoreEventArgMap[T]) => void)[] | undefined = - this._listeners.get(name); - if (Array.isArray(list) && list.length > 0) { - return true; - } - } - return false; - } -} diff --git a/packages/core/src/lib/diff.ts b/packages/core/src/lib/diff.ts deleted file mode 100644 index c84ced1..0000000 --- a/packages/core/src/lib/diff.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { DataElement, IDrawData, DataElemDesc } from '@idraw/types'; - -type DataElementMap = { - [uuid: string]: DataElement; -}; - -export function isChangeImageElementResource( - before: DataElement<'image'>, - after: DataElement<'image'> -): boolean { - return before?.desc?.src !== after?.desc?.src; -} - -export function isChangeSVGElementResource( - before: DataElement<'svg'>, - after: DataElement<'svg'> -): boolean { - return before?.desc?.svg !== after?.desc?.svg; -} - -export function isChangeHTMLElementResource( - before: DataElement<'html'>, - after: DataElement<'html'> -): boolean { - return ( - before?.desc?.html !== after?.desc?.html || - before?.desc?.width !== after?.desc?.width || - before?.desc?.height !== after?.desc?.height - ); -} - -export function diffElementResourceChange( - before: DataElement, - after: DataElement -): string | null { - let result = null; - let isChange = false; - switch (after.type) { - case 'image': { - isChange = isChangeImageElementResource( - before as DataElement<'image'>, - after as DataElement<'image'> - ); - break; - } - case 'svg': { - isChange = isChangeSVGElementResource( - before as DataElement<'svg'>, - after as DataElement<'svg'> - ); - break; - } - case 'html': { - isChange = isChangeHTMLElementResource( - before as DataElement<'html'>, - after as DataElement<'html'> - ); - break; - } - default: - break; - } - if (isChange === true) { - result = after.uuid; - } - return result; -} - -export function diffElementResourceChangeList( - before: IDrawData, - after: IDrawData -): string[] { - const uuids: string[] = []; - const beforeMap = parseDataElementMap(before); - const afterMap = parseDataElementMap(after); - for (const uuid in afterMap) { - if (['image', 'svg', 'html'].includes(afterMap[uuid]?.type) !== true) { - continue; - } - if (beforeMap[uuid]) { - let isChange = false; - switch (beforeMap[uuid].type) { - case 'image': { - isChange = isChangeImageElementResource( - beforeMap[uuid] as DataElement<'image'>, - afterMap[uuid] as DataElement<'image'> - ); - break; - } - case 'svg': { - isChange = isChangeSVGElementResource( - beforeMap[uuid] as DataElement<'svg'>, - afterMap[uuid] as DataElement<'svg'> - ); - break; - } - case 'html': { - isChange = isChangeHTMLElementResource( - beforeMap[uuid] as DataElement<'html'>, - afterMap[uuid] as DataElement<'html'> - ); - break; - } - default: - break; - } - if (isChange === true) { - uuids.push(uuid); - } - } else { - uuids.push(uuid); - } - } - return uuids; -} - -function parseDataElementMap(data: IDrawData): DataElementMap { - const elemMap: DataElementMap = {}; - data.elements.forEach((elem) => { - elemMap[elem.uuid] = elem; - }); - return elemMap; -} diff --git a/packages/core/src/lib/draw/base.ts b/packages/core/src/lib/draw/base.ts deleted file mode 100644 index 06bec20..0000000 --- a/packages/core/src/lib/draw/base.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - IDrawContext, - // DataElemDesc, - DataElement -} from '@idraw/types'; -import { istype, isColorStr } from '@idraw/util'; -import { rotateElement } from './../transform'; -import is from './../is'; - -export function clearContext(ctx: IDrawContext) { - // ctx.setFillStyle('rgb(0 0 0 / 100%)'); - // ctx.setStrokeStyle('rgb(0 0 0 / 100%)'); - ctx.setFillStyle('#000000'); - ctx.setStrokeStyle('#000000'); - ctx.setLineDash([]); - ctx.setGlobalAlpha(1); - ctx.setShadowColor('#00000000'); - ctx.setShadowOffsetX(0); - ctx.setShadowOffsetY(0); - ctx.setShadowBlur(0); -} - -export function drawBgColor(ctx: IDrawContext, color: string) { - const size = ctx.getSize(); - ctx.setFillStyle(color); - ctx.fillRect(0, 0, size.contextWidth, size.contextHeight); -} - -export function drawBox( - ctx: IDrawContext, - elem: DataElement<'text' | 'rect'>, - pattern: string | CanvasPattern | null -): void { - clearContext(ctx); - drawBoxBorder(ctx, elem); - clearContext(ctx); - rotateElement(ctx, elem, () => { - const { x, y, w, h } = elem; - let r: number = elem.desc.borderRadius || 0; - r = Math.min(r, w / 2, h / 2); - if (w < r * 2 || h < r * 2) { - r = 0; - } - ctx.beginPath(); - ctx.moveTo(x + r, y); - ctx.arcTo(x + w, y, x + w, y + h, r); - ctx.arcTo(x + w, y + h, x, y + h, r); - ctx.arcTo(x, y + h, x, y, r); - ctx.arcTo(x, y, x + w, y, r); - ctx.closePath(); - if (typeof pattern === 'string') { - ctx.setFillStyle(pattern); - } else if (['CanvasPattern'].includes(istype.type(pattern))) { - ctx.setFillStyle(pattern as CanvasPattern); - } - ctx.fill(); - }); -} - -export function drawBoxBorder( - ctx: IDrawContext, - elem: DataElement<'text' | 'rect'> -): void { - clearContext(ctx); - rotateElement(ctx, elem, () => { - if (!(elem.desc.borderWidth && elem.desc.borderWidth > 0)) { - return; - } - const bw = elem.desc.borderWidth; - let borderColor = '#000000'; - if (isColorStr(elem.desc.borderColor) === true) { - borderColor = elem.desc.borderColor as string; - } - const x = elem.x - bw / 2; - const y = elem.y - bw / 2; - const w = elem.w + bw; - const h = elem.h + bw; - - let r: number = elem.desc.borderRadius || 0; - r = Math.min(r, w / 2, h / 2); - if (r < w / 2 && r < h / 2) { - r = r + bw / 2; - } - const { desc } = elem; - if (desc.shadowColor !== undefined && isColorStr(desc.shadowColor)) { - ctx.setShadowColor(desc.shadowColor); - } - if (desc.shadowOffsetX !== undefined && is.number(desc.shadowOffsetX)) { - ctx.setShadowOffsetX(desc.shadowOffsetX); - } - if (desc.shadowOffsetY !== undefined && is.number(desc.shadowOffsetY)) { - ctx.setShadowOffsetY(desc.shadowOffsetY); - } - if (desc.shadowBlur !== undefined && is.number(desc.shadowBlur)) { - ctx.setShadowBlur(desc.shadowBlur); - } - ctx.beginPath(); - ctx.setLineWidth(bw); - ctx.setStrokeStyle(borderColor); - ctx.moveTo(x + r, y); - ctx.arcTo(x + w, y, x + w, y + h, r); - ctx.arcTo(x + w, y + h, x, y + h, r); - ctx.arcTo(x, y + h, x, y, r); - ctx.arcTo(x, y, x + w, y, r); - ctx.closePath(); - ctx.stroke(); - }); -} diff --git a/packages/core/src/lib/draw/wrapper.ts b/packages/core/src/lib/draw/wrapper.ts deleted file mode 100644 index feef6a1..0000000 --- a/packages/core/src/lib/draw/wrapper.ts +++ /dev/null @@ -1,269 +0,0 @@ -import { IDrawContext, HelperConfig } from '@idraw/types'; -import { rotateContext } from './../transform'; -import { clearContext } from './base'; - -export function drawElementWrapper(ctx: IDrawContext, config: HelperConfig) { - if (!config?.selectedElementWrapper) { - return; - } - const wrapper = config.selectedElementWrapper; - clearContext(ctx); - rotateContext(ctx, wrapper.translate, wrapper.radian || 0, () => { - // draw wrapper's box - ctx.beginPath(); - ctx.setLineDash(wrapper.lineDash); - ctx.setLineWidth(wrapper.lineWidth); - ctx.setStrokeStyle(wrapper.color); - ctx.moveTo(wrapper.controllers.topLeft.x, wrapper.controllers.topLeft.y); - ctx.lineTo(wrapper.controllers.topRight.x, wrapper.controllers.topRight.y); - ctx.lineTo( - wrapper.controllers.bottomRight.x, - wrapper.controllers.bottomRight.y - ); - ctx.lineTo( - wrapper.controllers.bottomLeft.x, - wrapper.controllers.bottomLeft.y - ); - ctx.lineTo( - wrapper.controllers.topLeft.x, - wrapper.controllers.topLeft.y - wrapper.lineWidth / 2 - ); - ctx.stroke(); - ctx.closePath(); - - if (wrapper.lock !== true) { - if (wrapper.controllers.rotate.invisible !== true) { - // draw wrapper's rotate line - ctx.beginPath(); - ctx.moveTo(wrapper.controllers.top.x, wrapper.controllers.top.y); - ctx.lineTo( - wrapper.controllers.rotate.x, - wrapper.controllers.rotate.y + wrapper.controllerSize - ); - ctx.stroke(); - ctx.closePath(); - - // draw wrapper's rotate - ctx.beginPath(); - ctx.setLineDash([]); - ctx.setLineWidth(wrapper.controllerSize / 1.2); - ctx.arc( - wrapper.controllers.rotate.x, - wrapper.controllers.rotate.y, - wrapper.controllerSize * 0.8, - 0, - Math.PI * 2 - ); - ctx.stroke(); - ctx.closePath(); - - ctx.setStrokeStyle('#FFFFFF'); - ctx.beginPath(); - ctx.setLineDash([]); - ctx.setLineWidth(wrapper.controllerSize / 2.1); - ctx.arc( - wrapper.controllers.rotate.x, - wrapper.controllers.rotate.y, - wrapper.controllerSize * 0.8, - 0, - Math.PI * 2 - ); - ctx.stroke(); - ctx.closePath(); - } - - // draw wrapper's controllers - [ - wrapper.controllers.topLeft, - wrapper.controllers.top, - wrapper.controllers.topRight, - wrapper.controllers.right, - wrapper.controllers.bottomRight, - wrapper.controllers.bottom, - wrapper.controllers.bottomLeft, - wrapper.controllers.left - ].forEach((controller) => { - if (controller.invisible !== true) { - ctx.setFillStyle(wrapper.color); - ctx.beginPath(); - ctx.arc( - controller.x, - controller.y, - wrapper.controllerSize, - 0, - Math.PI * 2 - ); - ctx.fill(); - ctx.closePath(); - - ctx.setFillStyle('#FFFFFF'); - ctx.beginPath(); - ctx.arc( - controller.x, - controller.y, - wrapper.controllerSize - 1, - 0, - Math.PI * 2 - ); - ctx.fill(); - ctx.closePath(); - } - }); - } else { - // draw wrapper's lock controllers, - clearContext(ctx); - ctx.setStrokeStyle(wrapper.color); - [ - wrapper.controllers.topLeft, - wrapper.controllers.top, - wrapper.controllers.topRight, - wrapper.controllers.right, - wrapper.controllers.bottomRight, - wrapper.controllers.bottom, - wrapper.controllers.bottomLeft, - wrapper.controllers.left - ].forEach((controller) => { - ctx.beginPath(); - ctx.moveTo( - controller.x - wrapper.controllerSize / 2, - controller.y - wrapper.controllerSize / 2 - ); - ctx.lineTo( - controller.x + wrapper.controllerSize / 2, - controller.y + wrapper.controllerSize / 2 - ); - ctx.stroke(); - ctx.closePath(); - - ctx.beginPath(); - ctx.moveTo( - controller.x + wrapper.controllerSize / 2, - controller.y - wrapper.controllerSize / 2 - ); - ctx.lineTo( - controller.x - wrapper.controllerSize / 2, - controller.y + wrapper.controllerSize / 2 - ); - ctx.stroke(); - ctx.closePath(); - }); - } - }); -} - -export function drawAreaWrapper(ctx: IDrawContext, config: HelperConfig) { - if (!config?.selectedAreaWrapper) { - return; - } - const wrapper = config.selectedAreaWrapper; - if (wrapper && wrapper.w > 0 && wrapper.h > 0) { - clearContext(ctx); - ctx.setGlobalAlpha(0.3); - ctx.setFillStyle(wrapper.color); - ctx.fillRect(wrapper.x, wrapper.y, wrapper.w, wrapper.h); - - clearContext(ctx); - ctx.beginPath(); - ctx.setLineDash(wrapper.lineDash); - ctx.setLineWidth(wrapper.lineWidth); - ctx.setStrokeStyle(wrapper.color); - ctx.moveTo(wrapper.x, wrapper.y); - ctx.lineTo(wrapper.x + wrapper.w, wrapper.y); - ctx.lineTo(wrapper.x + wrapper.w, wrapper.y + wrapper.h); - ctx.lineTo(wrapper.x, wrapper.y + wrapper.h); - ctx.lineTo(wrapper.x, wrapper.y); - ctx.stroke(); - ctx.closePath(); - } -} - -export function drawElementListWrappers( - ctx: IDrawContext, - config: HelperConfig -) { - if (!Array.isArray(config?.selectedElementListWrappers)) { - return; - } - const wrapperList = config.selectedElementListWrappers; - - wrapperList?.forEach((wrapper) => { - clearContext(ctx); - rotateContext(ctx, wrapper.translate, wrapper.radian || 0, () => { - clearContext(ctx); - ctx.setGlobalAlpha(0.05); - ctx.setFillStyle(wrapper.color); - ctx.fillRect( - wrapper.controllers.topLeft.x, - wrapper.controllers.topLeft.y, - wrapper.controllers.bottomRight.x - wrapper.controllers.topLeft.x, - wrapper.controllers.bottomRight.y - wrapper.controllers.topLeft.y - ); - - clearContext(ctx); - ctx.beginPath(); - ctx.setLineDash(wrapper.lineDash); - ctx.setLineWidth(wrapper.lineWidth); - ctx.setStrokeStyle(wrapper.color); - ctx.moveTo(wrapper.controllers.topLeft.x, wrapper.controllers.topLeft.y); - ctx.lineTo( - wrapper.controllers.topRight.x, - wrapper.controllers.topRight.y - ); - ctx.lineTo( - wrapper.controllers.bottomRight.x, - wrapper.controllers.bottomRight.y - ); - ctx.lineTo( - wrapper.controllers.bottomLeft.x, - wrapper.controllers.bottomLeft.y - ); - ctx.lineTo( - wrapper.controllers.topLeft.x, - wrapper.controllers.topLeft.y - wrapper.lineWidth / 2 - ); - ctx.stroke(); - ctx.closePath(); - - if (wrapper.lock === true) { - // draw wrapper's lock controllers, - clearContext(ctx); - // ctx.setFillStyle(wrapper.color); - ctx.setStrokeStyle(wrapper.color); - [ - wrapper.controllers.topLeft, - wrapper.controllers.top, - wrapper.controllers.topRight, - wrapper.controllers.right, - wrapper.controllers.bottomRight, - wrapper.controllers.bottom, - wrapper.controllers.bottomLeft, - wrapper.controllers.left - ].forEach((controller) => { - ctx.beginPath(); - ctx.moveTo( - controller.x - wrapper.controllerSize / 2, - controller.y - wrapper.controllerSize / 2 - ); - ctx.lineTo( - controller.x + wrapper.controllerSize / 2, - controller.y + wrapper.controllerSize / 2 - ); - ctx.stroke(); - ctx.closePath(); - - ctx.beginPath(); - ctx.moveTo( - controller.x + wrapper.controllerSize / 2, - controller.y - wrapper.controllerSize / 2 - ); - ctx.lineTo( - controller.x - wrapper.controllerSize / 2, - controller.y + wrapper.controllerSize / 2 - ); - ctx.stroke(); - ctx.closePath(); - }); - } - }); - }); -} diff --git a/packages/core/src/lib/element.ts b/packages/core/src/lib/element.ts deleted file mode 100644 index aab6508..0000000 --- a/packages/core/src/lib/element.ts +++ /dev/null @@ -1,622 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { - IDrawContext, - Point, - IDrawData, - HelperWrapperControllerDirection, - DataElement, - DataElemDesc -} from '@idraw/types'; -import { createUUID } from '@idraw/util'; -import { rotateElement } from './transform'; -import { calcRadian, calcElementCenter, parseRadianToAngle } from './calculate'; -import { limitAngle, limitNum } from './value'; -import { LIMIT_QBLIQUE_ANGLE } from './../constant/element'; - -const limitQbliqueAngle = LIMIT_QBLIQUE_ANGLE; - -export class Element { - private _ctx: IDrawContext; - - constructor(ctx: IDrawContext) { - this._ctx = ctx; - } - - initData(data: IDrawData): IDrawData { - data.elements.forEach((elem) => { - if (!(elem.uuid && typeof elem.uuid === 'string')) { - elem.uuid = createUUID(); - } - }); - return data; - } - - isPointInElement(p: Point, data: IDrawData): [number, string | null] { - const ctx = this._ctx; - let idx = -1; - let uuid = null; - for (let i = data.elements.length - 1; i >= 0; i--) { - const ele = data.elements[i]; - if (ele.operation?.invisible === true) continue; - let bw = 0; - // @ts-ignore - if (ele.desc?.borderWidth > 0) { - // @ts-ignore - bw = ele.desc.borderWidth; - } - - rotateElement(ctx, ele, () => { - ctx.beginPath(); - ctx.moveTo(ele.x - bw, ele.y - bw); - ctx.lineTo(ele.x + ele.w + bw, ele.y - bw); - ctx.lineTo(ele.x + ele.w + bw, ele.y + ele.h + bw); - ctx.lineTo(ele.x - bw, ele.y + ele.h + bw); - ctx.lineTo(ele.x - bw, ele.y - bw); - ctx.closePath(); - if (ctx.isPointInPath(p.x, p.y)) { - idx = i; - uuid = ele.uuid; - } - }); - - if (idx >= 0) { - break; - } - } - return [idx, uuid]; - } - - dragElement( - data: IDrawData, - uuid: string, - point: Point, - prevPoint: Point, - scale: number - ): void { - const index = this.getElementIndex(data, uuid); - if (!data.elements[index]) { - return; - } - const moveX = point.x - prevPoint.x; - const moveY = point.y - prevPoint.y; - data.elements[index].x += moveX / scale; - data.elements[index].y += moveY / scale; - this.limitElementAttrs(data.elements[index]); - } - - transformElement( - data: IDrawData, - uuid: string, - point: Point, - prevPoint: Point, - scale: number, - direction: HelperWrapperControllerDirection - ): null | { - width: number; - height: number; - angle: number; - } { - const index = this.getElementIndex(data, uuid); - if (!data.elements[index]) { - return null; - } - if (data.elements[index]?.operation?.lock === true) { - return null; - } - const moveX = (point.x - prevPoint.x) / scale; - const moveY = (point.y - prevPoint.y) / scale; - const elem = data.elements[index]; - // const { devicePixelRatio } = this._ctx.getSize(); - - // if (typeof elem.angle === 'number' && (elem.angle > 0 || elem.angle < 0)) { - // moveY = (point.y - prevPoint.y) / scale; - // } - - if ( - [ - 'top-left', - 'top', - 'top-right', - 'right', - 'bottom-right', - 'bottom', - 'bottom-left', - 'left' - ].includes(direction) - ) { - const p = calcuScaleElemPosition(elem, moveX, moveY, direction); - elem.x = p.x; - elem.y = p.y; - elem.w = p.w; - elem.h = p.h; - } else if (direction === 'rotate') { - const center = calcElementCenter(elem); - const radian = calcRadian(center, prevPoint, point); - elem.angle = (elem.angle || 0) + parseRadianToAngle(radian); - } - - this.limitElementAttrs(elem); - - return { - width: limitNum(elem.w), - height: limitNum(elem.h), - angle: limitAngle(elem.angle || 0) - }; - } - - getElementIndex(data: IDrawData, uuid: string): number { - let idx = -1; - for (let i = 0; i < data.elements.length; i++) { - if (data.elements[i].uuid === uuid) { - idx = i; - break; - } - } - return idx; - } - - limitElementAttrs(elem: DataElement) { - elem.x = limitNum(elem.x); - elem.y = limitNum(elem.y); - elem.w = limitNum(elem.w); - elem.h = limitNum(elem.h); - elem.angle = limitAngle(elem.angle || 0); - } -} - -function calcuScaleElemPosition( - elem: DataElement, - moveX: number, - moveY: number, - direction: HelperWrapperControllerDirection - // scale: number -): Point & { w: number; h: number } { - const p = { x: elem.x, y: elem.y, w: elem.w, h: elem.h }; - let angle = elem.angle || 0; - if (angle < 0) { - angle = Math.max(0, 360 + angle); - } - if (elem.operation?.limitRatio === true) { - if ( - ['top-left', 'top-right', 'bottom-right', 'bottom-left'].includes( - direction - ) - ) { - const maxDist = Math.max(Math.abs(moveX), Math.abs(moveY)); - moveX = (moveX >= 0 ? 1 : -1) * maxDist; - moveY = (((moveY >= 0 ? 1 : -1) * maxDist) / elem.w) * elem.h; - } - } - - switch (direction) { - case 'top-left': { - // TODO - - // if (elem.angle === 0) { - // // TODO - // } else if (elem.angle > 0 || elem.angle < 0) { - // // const angle = elem.angle > 0 ? elem.angle : Math.max(0, elem.angle + 360); - // if (angle < 90) { - // // TODO - // } else if (angle < 180) { - // // TODO - // } else if (angle < 270) { - // // TODO - // } else if (angle < 360) { - // // TODO - // } - // } else { - // // TODO - // } - - if (elem.w - moveX > 0 && elem.h - moveY > 0) { - p.x += moveX; - p.y += moveY; - p.w -= moveX; - p.h -= moveY; - } - - break; - } - case 'top': { - if (elem.angle === 0 || Math.abs(elem.angle || 0) < limitQbliqueAngle) { - if (p.h - moveY > 0) { - p.y += moveY; - p.h -= moveY; - if (elem.operation?.limitRatio === true) { - p.x += ((moveY / elem.h) * elem.w) / 2; - p.w -= (moveY / elem.h) * elem.w; - } - } - } else if ( - elem.angle !== undefined && - (elem.angle > 0 || elem.angle < 0) - ) { - const angle = - elem.angle > 0 ? elem.angle : Math.max(0, elem.angle + 360); - let moveDist = calcMoveDist(moveX, moveY); - let centerX = p.x + elem.w / 2; - let centerY = p.y + elem.h / 2; - if (angle < 90) { - moveDist = 0 - changeMoveDistDirect(moveDist, moveY); - const radian = parseRadian(angle); - const centerMoveDist = moveDist / 2; - centerX = centerX + centerMoveDist * Math.sin(radian); - centerY = centerY - centerMoveDist * Math.cos(radian); - } else if (angle < 180) { - moveDist = changeMoveDistDirect(moveDist, moveX); - const radian = parseRadian(angle - 90); - const centerMoveDist = moveDist / 2; - centerX = centerX + centerMoveDist * Math.cos(radian); - centerY = centerY + centerMoveDist * Math.sin(radian); - } else if (angle < 270) { - moveDist = changeMoveDistDirect(moveDist, moveY); - const radian = parseRadian(angle - 180); - const centerMoveDist = moveDist / 2; - centerX = centerX - centerMoveDist * Math.sin(radian); - centerY = centerY + centerMoveDist * Math.cos(radian); - } else if (angle < 360) { - moveDist = 0 - changeMoveDistDirect(moveDist, moveX); - const radian = parseRadian(angle - 270); - const centerMoveDist = moveDist / 2; - centerX = centerX - centerMoveDist * Math.cos(radian); - centerY = centerY - centerMoveDist * Math.sin(radian); - } - if (p.h + moveDist > 0) { - if (elem.operation?.limitRatio === true) { - p.w = p.w + (moveDist / elem.h) * elem.w; - } - p.h = p.h + moveDist; - p.x = centerX - p.w / 2; - p.y = centerY - p.h / 2; - } - } else { - if (p.h - moveY > 0) { - p.y += moveY; - p.h -= moveY; - if (elem.operation?.limitRatio === true) { - p.x -= moveX / 2; - p.w += moveX; - } - } - } - break; - } - case 'top-right': { - if (p.h - moveY > 0 && p.w + moveX > 0) { - p.y += moveY; - p.w += moveX; - p.h -= moveY; - } - // // TODO - // if (elem.angle === 0) { - // if (p.h - moveY > 0) { - // p.y += moveY; - // p.h -= moveY; - // } - // } else if (elem.angle > 0 || elem.angle < 0) { - // const angle = elem.angle > 0 ? elem.angle : Math.max(0, elem.angle + 360); - // let moveDist = calcMoveDist(moveX, moveY); - // let centerX = p.x + elem.w / 2; - // let centerY = p.y + elem.h / 2; - // let moveDistW: number = 0; - // let moveDistH: number = 0; - // if (angle < 90) { - // const radianDist = Math.atan(Math.tan(Math.abs(moveY)/Math.abs(moveX))) - // const radian = parseRadian(angle); - // const radianResult = radianDist + radian; - // moveDistH = moveDist * Math.sin(radianResult); - // moveDistW = moveDist * Math.cos(radianResult); - // moveDistH = 0 - changeMoveDistDirect(moveDistH, moveY); - // moveDistW = changeMoveDistDirect(moveDistW, moveX); - // { - // // top direct - // const radian = parseRadian(angle); - // const centerMoveDist = moveDistH / 2; - // centerX = centerX + centerMoveDist * Math.sin(radian); - // centerY = centerY - centerMoveDist * Math.cos(radian); - // } - // { - // // right direct - // const radian = parseRadian(angle); - // const centerMoveDist = moveDistW / 2; - // centerX = centerX + centerMoveDist * Math.cos(radian); - // centerY = centerY + centerMoveDist * Math.sin(radian); - // } - - // } else if (angle < 180) { - // const radianDist = Math.atan(Math.tan(Math.abs(moveX)/Math.abs(moveY))) - // const radian = parseRadian(angle); - // const radianResult = radianDist + radian; - // moveDistH = moveDist * Math.sin(radianResult); - // moveDistW = moveDist * Math.cos(radianResult); - // moveDistH = changeMoveDistDirect(moveDistH, moveY); - // moveDistW = changeMoveDistDirect(moveDistW, moveX); - // { - // // top direct - // const radian = parseRadian(angle - 90); - // const centerMoveDist = moveDistH / 2; - // centerX = centerX + centerMoveDist * Math.cos(radian); - // centerY = centerY + centerMoveDist * Math.sin(radian); - // } - // { - // // right direct TODO - // const radian = parseRadian(angle - 90); - // const centerMoveDist = moveDistW / 2; - // centerX = centerX - centerMoveDist * Math.sin(radian); - // centerY = centerY + centerMoveDist * Math.cos(radian); - // } - - // } else if (angle < 270) { - // // TODO - // } else if (angle < 360) { - // // TODO - // } - // if (p.h + moveDistH > 0 && p.w + moveDistW > 0) { - // p.h = p.h + moveDistH; - // // p.w = p.w + moveDistW; - // p.x = centerX - p.w / 2; - // p.y = centerY - p.h / 2; - // } - // } else { - // if (p.h - moveY > 0) { - // p.y += moveY; - // p.h -= moveY; - // } - // } - break; - } - case 'right': { - if (elem.angle === 0 || Math.abs(elem.angle || 0) < limitQbliqueAngle) { - if (elem.w + moveX > 0) { - p.w += moveX; - if (elem.operation?.limitRatio === true) { - p.y -= (moveX * elem.h) / elem.w / 2; - p.h += (moveX * elem.h) / elem.w; - } - } - } else if ( - elem.angle !== undefined && - (elem.angle > 0 || elem.angle < 0) - ) { - const angle = - elem.angle > 0 ? elem.angle : Math.max(0, elem.angle + 360); - let moveDist = calcMoveDist(moveX, moveY); - let centerX = p.x + elem.w / 2; - let centerY = p.y + elem.h / 2; - if (angle < 90) { - moveDist = changeMoveDistDirect(moveDist, moveY); - const radian = parseRadian(angle); - const centerMoveDist = moveDist / 2; - centerX = centerX + centerMoveDist * Math.cos(radian); - centerY = centerY + centerMoveDist * Math.sin(radian); - } else if (angle < 180) { - moveDist = changeMoveDistDirect(moveDist, moveY); - const radian = parseRadian(angle - 90); - const centerMoveDist = moveDist / 2; - centerX = centerX - centerMoveDist * Math.sin(radian); - centerY = centerY + centerMoveDist * Math.cos(radian); - } else if (angle < 270) { - moveDist = changeMoveDistDirect(moveDist, moveY); - const radian = parseRadian(angle - 180); - const centerMoveDist = moveDist / 2; - centerX = centerX + centerMoveDist * Math.cos(radian); - centerY = centerY + centerMoveDist * Math.sin(radian); - moveDist = 0 - moveDist; - } else if (angle < 360) { - moveDist = changeMoveDistDirect(moveDist, moveX); - const radian = parseRadian(angle - 270); - const centerMoveDist = moveDist / 2; - centerX = centerX + centerMoveDist * Math.sin(radian); - centerY = centerY - centerMoveDist * Math.cos(radian); - } - if (p.w + moveDist > 0) { - if (elem.operation?.limitRatio === true) { - p.h = p.h + (moveDist / elem.w) * elem.h; - } - p.w = p.w + moveDist; - p.x = centerX - p.w / 2; - p.y = centerY - p.h / 2; - } - } else { - if (elem.w + moveX > 0) { - p.w += moveX; - if (elem.operation?.limitRatio === true) { - p.h += (moveX * elem.h) / elem.w; - p.y -= (moveX * elem.h) / elem.w / 2; - } - } - } - break; - } - case 'bottom-right': { - // if (elem.angle === 0) { - // // TODO - // } else if (elem.angle > 0 || elem.angle < 0) { - // // const angle = elem.angle > 0 ? elem.angle : Math.max(0, elem.angle + 360); - // if (angle < 90) { - // // TODO - // } else if (angle < 180) { - // // TODO - // } else if (angle < 270) { - // // TODO - // } else if (angle < 360) { - // // TODO - // } - // } else { - // // TODO - // } - if (elem.w + moveX > 0 && elem.h + moveY > 0) { - p.w += moveX; - p.h += moveY; - } - break; - } - case 'bottom': { - if (elem.angle === 0 || Math.abs(elem.angle || 0) < limitQbliqueAngle) { - if (elem.h + moveY > 0) { - p.h += moveY; - if (elem.operation?.limitRatio === true) { - p.x -= ((moveY / elem.h) * elem.w) / 2; - p.w += (moveY / elem.h) * elem.w; - } - } - } else if ( - elem.angle !== undefined && - (elem.angle > 0 || elem.angle < 0) - ) { - const angle = - elem.angle > 0 ? elem.angle : Math.max(0, elem.angle + 360); - let moveDist = calcMoveDist(moveX, moveY); - let centerX = p.x + elem.w / 2; - let centerY = p.y + elem.h / 2; - if (angle < 90) { - moveDist = changeMoveDistDirect(moveDist, moveY); - const radian = parseRadian(angle); - const centerMoveDist = moveDist / 2; - centerX = centerX - centerMoveDist * Math.sin(radian); - centerY = centerY + centerMoveDist * Math.cos(radian); - } else if (angle < 180) { - moveDist = 0 - changeMoveDistDirect(moveDist, moveX); - const radian = parseRadian(angle - 90); - const centerMoveDist = moveDist / 2; - centerX = centerX - centerMoveDist * Math.cos(radian); - centerY = centerY - centerMoveDist * Math.sin(radian); - } else if (angle < 270) { - moveDist = changeMoveDistDirect(moveDist, moveX); - const radian = parseRadian(angle - 180); - const centerMoveDist = moveDist / 2; - centerX = centerX + centerMoveDist * Math.sin(radian); - centerY = centerY - centerMoveDist * Math.cos(radian); - } else if (angle < 360) { - moveDist = changeMoveDistDirect(moveDist, moveX); - const radian = parseRadian(angle - 270); - const centerMoveDist = moveDist / 2; - centerX = centerX + centerMoveDist * Math.cos(radian); - centerY = centerY + centerMoveDist * Math.sin(radian); - } - if (p.h + moveDist > 0) { - if (elem.operation?.limitRatio === true) { - p.w = p.w + (moveDist / elem.h) * elem.w; - } - p.h = p.h + moveDist; - p.x = centerX - p.w / 2; - p.y = centerY - p.h / 2; - } - } else { - if (elem.h + moveY > 0) { - p.h += moveY; - if (elem.operation?.limitRatio === true) { - p.x -= ((moveY / elem.h) * elem.w) / 2; - p.w += (moveY / elem.h) * elem.w; - } - } - } - break; - } - case 'bottom-left': { - // if (elem.angle === 0) { - // // TODO - // } else if (elem.angle > 0 || elem.angle < 0) { - // // const angle = elem.angle > 0 ? elem.angle : Math.max(0, elem.angle + 360); - // if (angle < 90) { - // // TODO - // } else if (angle < 180) { - // // TODO - // } else if (angle < 270) { - // // TODO - // } else if (angle < 360) { - // // TODO - // } - // } else { - // // TODO - // } - if (elem.w - moveX > 0 && elem.h + moveY > 0) { - p.x += moveX; - p.w -= moveX; - p.h += moveY; - } - break; - } - case 'left': { - if (elem.angle === 0 || Math.abs(elem.angle || 0) < limitQbliqueAngle) { - if (elem.w - moveX > 0) { - p.x += moveX; - p.w -= moveX; - if (elem.operation?.limitRatio === true) { - p.h -= (moveX / elem.w) * elem.h; - p.y += ((moveX / elem.w) * elem.h) / 2; - } - } - } else if ( - elem.angle !== undefined && - (elem.angle > 0 || elem.angle < 0) - ) { - const angle = - elem.angle > 0 ? elem.angle : Math.max(0, elem.angle + 360); - let moveDist = calcMoveDist(moveX, moveY); - let centerX = p.x + elem.w / 2; - let centerY = p.y + elem.h / 2; - if (angle < 90) { - moveDist = 0 - changeMoveDistDirect(moveDist, moveX); - const radian = parseRadian(angle); - const centerMoveDist = moveDist / 2; - centerX = centerX - centerMoveDist * Math.cos(radian); - centerY = centerY - centerMoveDist * Math.sin(radian); - } else if (angle < 180) { - moveDist = changeMoveDistDirect(moveDist, moveX); - const radian = parseRadian(angle - 90); - const centerMoveDist = moveDist / 2; - centerX = centerX + centerMoveDist * Math.sin(radian); - centerY = centerY - centerMoveDist * Math.cos(radian); - } else if (angle < 270) { - moveDist = changeMoveDistDirect(moveDist, moveY); - const radian = parseRadian(angle - 180); - const centerMoveDist = moveDist / 2; - centerX = centerX + centerMoveDist * Math.cos(radian); - centerY = centerY + centerMoveDist * Math.sin(radian); - } else if (angle < 360) { - moveDist = changeMoveDistDirect(moveDist, moveY); - const radian = parseRadian(angle - 270); - const centerMoveDist = moveDist / 2; - centerX = centerX - centerMoveDist * Math.sin(radian); - centerY = centerY + centerMoveDist * Math.cos(radian); - } - if (p.w + moveDist > 0) { - if (elem.operation?.limitRatio === true) { - p.h = p.h + (moveDist / elem.w) * elem.h; - } - p.w = p.w + moveDist; - p.x = centerX - p.w / 2; - p.y = centerY - p.h / 2; - } - } else { - if (elem.w - moveX > 0) { - p.x += moveX; - p.w -= moveX; - if (elem.operation?.limitRatio === true) { - p.h -= (moveX / elem.w) * elem.h; - p.y += ((moveX / elem.w) * elem.h) / 2; - } - } - } - break; - } - default: { - break; - } - } - return p; -} - -function parseRadian(angle: number) { - return (angle * Math.PI) / 180; -} - -function calcMoveDist(moveX: number, moveY: number) { - return Math.sqrt(moveX * moveX + moveY * moveY); -} - -function changeMoveDistDirect(moveDist: number, moveDirect: number) { - return moveDirect > 0 ? Math.abs(moveDist) : 0 - Math.abs(moveDist); -} diff --git a/packages/core/src/lib/engine-temp.ts b/packages/core/src/lib/engine-temp.ts deleted file mode 100644 index 26b2609..0000000 --- a/packages/core/src/lib/engine-temp.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { HelperWrapperControllerDirection, Point } from '@idraw/types'; -import { Mode, CursorStatus } from '../constant/static'; - -type TempDataDesc = { - hasInited: boolean; - mode: Mode; - cursorStatus: CursorStatus; - selectedUUID: string | null; - selectedUUIDList: string[]; - hoverUUID: string | null; - selectedControllerDirection: HelperWrapperControllerDirection | null; - hoverControllerDirection: HelperWrapperControllerDirection | null; - prevPoint: Point | null; - hasChangedElement: boolean; -}; - -function createData(): TempDataDesc { - return { - hasInited: false, - mode: Mode.NULL, - cursorStatus: CursorStatus.NULL, - selectedUUID: null, - selectedUUIDList: [], - hoverUUID: null, - selectedControllerDirection: null, - hoverControllerDirection: null, - prevPoint: null, - hasChangedElement: false - }; -} - -export class TempData { - private _temp: TempDataDesc; - - constructor() { - this._temp = createData(); - } - - set(name: T, value: TempDataDesc[T]) { - this._temp[name] = value; - } - - get(name: T): TempDataDesc[T] { - return this._temp[name]; - } - - clear() { - this._temp = createData(); - } -} diff --git a/packages/core/src/lib/engine.ts b/packages/core/src/lib/engine.ts deleted file mode 100644 index 5da64ef..0000000 --- a/packages/core/src/lib/engine.ts +++ /dev/null @@ -1,430 +0,0 @@ -import { - Point, - HelperWrapperControllerDirection, - InterfaceHelperPlugin, - IDrawConfigStrict, - IDrawData, - HelperConfig -} from '@idraw/types'; -import { deepClone, throttle } from '@idraw/util'; -import Board from '@idraw/board'; -import { Mode, CursorStatus } from './../constant/static'; -import { TempData } from './engine-temp'; -import { Helper } from './helper'; -import { Mapper } from './mapper'; -import { Element } from './element'; -import { CoreEvent } from './core-event'; - -type Options = { - coreEvent: CoreEvent; - board: Board; - element: Element; - config: IDrawConfigStrict; - drawFeekback: () => void; - getDataFeekback: () => IDrawData; - selectElementByIndex: (index: number, opts?: { useMode?: boolean }) => void; - emitChangeScreen: () => void; - emitChangeData: () => void; -}; - -export class Engine { - private _plugins: InterfaceHelperPlugin[] = []; - private _opts: Options; - private _mapper: Mapper; - - public temp: TempData; - public helper: Helper; - - constructor(opts: Options) { - const { board, config, element } = opts; - const helper = new Helper(board, config); - this._opts = opts; - this.temp = new TempData(); - this.helper = helper; - this._mapper = new Mapper({ board, helper, element }); - } - - addPlugin(plugin: InterfaceHelperPlugin) { - this._plugins.push(plugin); - } - - getHelperConfig(): HelperConfig { - return this.helper.getConfig(); - } - - updateHelperConfig(opts: { - width: number; - height: number; - devicePixelRatio: number; - }) { - const { board, getDataFeekback, config } = this._opts; - const data = getDataFeekback(); - const transform = board.getTransform(); - this.helper.updateConfig(data, { - width: opts.width, - height: opts.height, - devicePixelRatio: opts.devicePixelRatio, - canScroll: config?.scrollWrapper?.use === true, - selectedUUID: this.temp.get('selectedUUID'), - selectedUUIDList: this.temp.get('selectedUUIDList'), - scale: transform.scale, - scrollX: transform.scrollX, - scrollY: transform.scrollY - }); - } - - init() { - this._initEvent(); - } - - private _initEvent(): void { - if (this.temp.get('hasInited') === true) { - return; - } - const { board } = this._opts; - - board.on('hover', throttle(this._handleHover.bind(this), 32)); - board.on('leave', throttle(this._handleLeave.bind(this), 32)); - board.on('point', throttle(this._handleClick.bind(this), 16)); - board.on('doubleClick', this._handleDoubleClick.bind(this)); - board.on('point', this._handlePoint.bind(this)); - board.on('moveStart', this._handleMoveStart.bind(this)); - board.on('move', throttle(this._handleMove.bind(this), 16)); - board.on('moveEnd', this._handleMoveEnd.bind(this)); - } - - private _handleDoubleClick(point: Point) { - const { element, getDataFeekback, drawFeekback, coreEvent } = this._opts; - const data = getDataFeekback(); - const [index, uuid] = element.isPointInElement(point, data); - if (index >= 0 && uuid) { - const elem = deepClone(data.elements?.[index]); - if (elem?.operation?.invisible !== true) { - coreEvent.trigger('screenDoubleClickElement', { - index, - uuid, - element: deepClone(data.elements?.[index]) - }); - } - } - drawFeekback(); - } - - _handlePoint(point: Point): void { - if (!this._mapper.isEffectivePoint(point)) { - return; - } - const { - element, - getDataFeekback, - selectElementByIndex, - coreEvent, - emitChangeScreen, - drawFeekback - } = this._opts; - const helper = this.helper; - const data = getDataFeekback(); - if (helper.isPointInElementList(point, data)) { - // Coontroll Element-List - this.temp.set('mode', Mode.SELECT_ELEMENT_LIST); - } else { - const { uuid, selectedControllerDirection } = - helper.isPointInElementWrapperController(point, data); - if (uuid && selectedControllerDirection) { - // Controll Element-Wrapper - this.temp.set('mode', Mode.SELECT_ELEMENT_WRAPPER_CONTROLLER); - this.temp.set( - 'selectedControllerDirection', - selectedControllerDirection - ); - this.temp.set('selectedUUID', uuid); - } else { - const [index, uuid] = element.isPointInElement(point, data); - if (index >= 0 && data.elements[index]?.operation?.invisible !== true) { - // Controll Element - selectElementByIndex(index, { useMode: true }); - if ( - typeof uuid === 'string' && - coreEvent.has('screenSelectElement') - ) { - coreEvent.trigger('screenSelectElement', { - index, - uuid, - element: deepClone(data.elements?.[index]) - }); - emitChangeScreen(); - } - this.temp.set('mode', Mode.SELECT_ELEMENT); - } else { - // Controll Area - this.temp.set('selectedUUIDList', []); - this.temp.set('selectedUUID', null); - this.temp.set('mode', Mode.SELECT_AREA); - } - } - } - drawFeekback(); - } - - private _handleClick(point: Point): void { - const { element, getDataFeekback, coreEvent, drawFeekback } = this._opts; - const data = getDataFeekback(); - const [index, uuid] = element.isPointInElement(point, data); - if (index >= 0 && uuid) { - coreEvent.trigger('screenClickElement', { - index, - uuid, - element: deepClone(data.elements?.[index]) - }); - } - drawFeekback(); - } - - private _handleMoveStart(point: Point): void { - const { element, getDataFeekback, coreEvent } = this._opts; - const data = getDataFeekback(); - const helper = this.helper; - - this.temp.set('prevPoint', point); - const uuid = this.temp.get('selectedUUID'); - - if (this.temp.get('mode') === Mode.SELECT_ELEMENT_LIST) { - // TODO - } else if (this.temp.get('mode') === Mode.SELECT_ELEMENT) { - if (typeof uuid === 'string' && coreEvent.has('screenMoveElementStart')) { - coreEvent.trigger('screenMoveElementStart', { - index: element.getElementIndex(data, uuid), - uuid, - x: point.x, - y: point.y - }); - } - } else if (this.temp.get('mode') === Mode.SELECT_AREA) { - helper.startSelectArea(point); - } - } - - private _handleMove(point: Point): void { - const { drawFeekback } = this._opts; - const helper = this.helper; - if (this.temp.get('mode') === Mode.SELECT_ELEMENT_LIST) { - this.temp.set('hasChangedElement', true); - this._dragElements( - this.temp.get('selectedUUIDList'), - point, - this.temp.get('prevPoint') - ); - drawFeekback(); - this.temp.set('cursorStatus', CursorStatus.DRAGGING); - } else if (typeof this.temp.get('selectedUUID') === 'string') { - if (this.temp.get('mode') === Mode.SELECT_ELEMENT) { - this.temp.set('hasChangedElement', true); - this._dragElements( - [this.temp.get('selectedUUID') as string], - point, - this.temp.get('prevPoint') - ); - drawFeekback(); - this.temp.set('cursorStatus', CursorStatus.DRAGGING); - } else if ( - this.temp.get('mode') === Mode.SELECT_ELEMENT_WRAPPER_CONTROLLER && - this.temp.get('selectedControllerDirection') - ) { - this._transfromElement( - this.temp.get('selectedUUID') as string, - point, - this.temp.get('prevPoint'), - this.temp.get( - 'selectedControllerDirection' - ) as HelperWrapperControllerDirection - ); - this.temp.set('cursorStatus', CursorStatus.DRAGGING); - } - } else if (this.temp.get('mode') === Mode.SELECT_AREA) { - helper.changeSelectArea(point); - drawFeekback(); - } - this.temp.set('prevPoint', point); - } - - private _dragElements( - uuids: string[], - point: Point, - prevPoint: Point | null - ): void { - if (!prevPoint) { - return; - } - const { board, element, getDataFeekback, drawFeekback } = this._opts; - const data = getDataFeekback(); - const helper = this.helper; - uuids.forEach((uuid) => { - const idx = helper.getElementIndexByUUID(uuid); - if (idx === null) return; - const elem = data.elements[idx]; - if ( - elem?.operation?.lock !== true && - elem?.operation?.invisible !== true - ) { - element.dragElement( - data, - uuid, - point, - prevPoint, - board.getContext().getTransform().scale - ); - } - }); - drawFeekback(); - } - - private _transfromElement( - uuid: string, - point: Point, - prevPoint: Point | null, - direction: HelperWrapperControllerDirection - ): null | { width: number; height: number; angle: number } { - if (!prevPoint) { - return null; - } - const { board, element, getDataFeekback, drawFeekback } = this._opts; - const data = getDataFeekback(); - const result = element.transformElement( - data, - uuid, - point, - prevPoint, - board.getContext().getTransform().scale, - direction - ); - drawFeekback(); - return result; - } - - private _handleMoveEnd(point: Point): void { - const { - element, - getDataFeekback, - coreEvent, - drawFeekback, - emitChangeData - } = this._opts; - const data = getDataFeekback(); - const helper = this.helper; - - const uuid = this.temp.get('selectedUUID'); - if (typeof uuid === 'string') { - const index = element.getElementIndex(data, uuid); - const elem = data.elements[index]; - if (elem) { - if (coreEvent.has('screenMoveElementEnd')) { - coreEvent.trigger('screenMoveElementEnd', { - index, - uuid, - x: point.x, - y: point.y - }); - } - if (coreEvent.has('screenChangeElement')) { - coreEvent.trigger('screenChangeElement', { - index, - uuid, - width: elem.w, - height: elem.h, - angle: elem.angle || 0 - }); - } - } - } else if (this.temp.get('mode') === Mode.SELECT_AREA) { - const uuids = helper.calcSelectedElements(data); - if (uuids.length > 0) { - this.temp.set('selectedUUIDList', uuids); - this.temp.set('selectedUUID', null); - } else { - this.temp.set('mode', Mode.NULL); - } - helper.clearSelectedArea(); - drawFeekback(); - } - - if (this.temp.get('mode') !== Mode.SELECT_ELEMENT) { - this.temp.set('selectedUUID', null); - } - this.temp.set('cursorStatus', CursorStatus.NULL); - this.temp.set('mode', Mode.NULL); - - if (this.temp.get('hasChangedElement') === true) { - emitChangeData(); - this.temp.set('hasChangedElement', false); - } - } - - private _handleHover(point: Point): void { - let isMouseOverElement = false; - const { board, getDataFeekback, coreEvent } = this._opts; - const data = getDataFeekback(); - const helper = this.helper; - const mapper = this._mapper; - - if (this.temp.get('mode') === Mode.SELECT_AREA) { - board.resetCursor(); - } else if (this.temp.get('cursorStatus') === CursorStatus.NULL) { - const { cursor, elementUUID } = mapper.judgePointCursor(point, data); - board.setCursor(cursor); - if (elementUUID) { - const index: number | null = helper.getElementIndexByUUID(elementUUID); - if (index !== null && index >= 0) { - const elem = data.elements[index]; - if ( - elem?.operation?.lock === true || - elem?.operation?.invisible === true - ) { - board.resetCursor(); - return; - } - if (this.temp.get('hoverUUID') !== elem.uuid) { - const preIndex = helper.getElementIndexByUUID( - this.temp.get('hoverUUID') || '' - ); - if (preIndex !== null && data.elements[preIndex]) { - coreEvent.trigger('mouseLeaveElement', { - uuid: this.temp.get('hoverUUID'), - index: preIndex, - element: data.elements[preIndex] - }); - } - } - if (elem) { - coreEvent.trigger('mouseOverElement', { - uuid: elem.uuid, - index, - element: elem - }); - this.temp.set('hoverUUID', elem.uuid); - isMouseOverElement = true; - } - } - } - } - if (isMouseOverElement !== true && this.temp.get('hoverUUID') !== null) { - const uuid = this.temp.get('hoverUUID'); - const index: number | null = helper.getElementIndexByUUID(uuid || ''); - if (index !== null) - coreEvent.trigger('mouseLeaveElement', { - uuid, - index, - element: data.elements[index] - }); - this.temp.set('hoverUUID', null); - } - if (coreEvent.has('mouseOverScreen')) - coreEvent.trigger('mouseOverScreen', point); - } - - private _handleLeave(): void { - const { coreEvent } = this._opts; - if (coreEvent.has('mouseLeaveScreen')) { - coreEvent.trigger('mouseLeaveScreen', undefined); - } - } -} diff --git a/packages/core/src/lib/helper.ts b/packages/core/src/lib/helper.ts deleted file mode 100644 index cf152a0..0000000 --- a/packages/core/src/lib/helper.ts +++ /dev/null @@ -1,445 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { - IDrawData, - HelperConfig, - HelperUpdateOpts, - HelperWrapperControllerDirection, - DataElement, - DataElemDesc, - IDrawContext, - Point, - IDrawConfigStrict, - HeplerSelectedElementWrapper -} from '@idraw/types'; -import Board from '@idraw/board'; -import { deepClone } from '@idraw/util'; -import { parseAngleToRadian, calcElementCenter } from './calculate'; -import { rotateContext, rotateElement } from './transform'; -import { LIMIT_QBLIQUE_ANGLE } from './../constant/element'; - -const limitQbliqueAngle = LIMIT_QBLIQUE_ANGLE; - -export class Helper { - private _helperConfig: HelperConfig; - private _coreConfig: IDrawConfigStrict; - private _ctx: IDrawContext; - private _board: Board; - private _areaStart: Point = { x: 0, y: 0 }; - private _areaEnd: Point = { x: 0, y: 0 }; - - constructor(board: Board, config: IDrawConfigStrict) { - this._board = board; - this._ctx = this._board.getContext(); - this._coreConfig = config; - this._helperConfig = { - elementIndexMap: {} - }; - } - - updateConfig(data: IDrawData, opts: HelperUpdateOpts): void { - this._updateElementIndex(data); - this._updateSelectedElementWrapper(data, opts); - this._updateSelectedElementListWrapper(data, opts); - } - - getConfig(): HelperConfig { - return deepClone(this._helperConfig); - } - - getElementIndexByUUID(uuid: string): number | null { - const index = this._helperConfig.elementIndexMap[uuid]; - if (index >= 0) { - return index; - } - return null; - } - - isPointInElementWrapperController( - p: Point, - data?: IDrawData - ): { - uuid: string | null | undefined; - selectedControllerDirection: HelperWrapperControllerDirection | null; - hoverControllerDirection: HelperWrapperControllerDirection | null; - directIndex: number | null; - } { - const ctx = this._ctx; - const uuid = this._helperConfig?.selectedElementWrapper?.uuid || null; - let directIndex = null; - let selectedControllerDirection: HelperWrapperControllerDirection | null = - null; - let hoverControllerDirection: HelperWrapperControllerDirection | null = - null; - if (!this._helperConfig.selectedElementWrapper) { - return { - uuid, - selectedControllerDirection, - directIndex, - hoverControllerDirection - }; - } - const wrapper = this._helperConfig.selectedElementWrapper; - const controllers = [ - wrapper.controllers.right, - wrapper.controllers.topRight, - wrapper.controllers.top, - wrapper.controllers.topLeft, - wrapper.controllers.left, - wrapper.controllers.bottomLeft, - wrapper.controllers.bottom, - wrapper.controllers.bottomRight - ]; - const directionNames: HelperWrapperControllerDirection[] = [ - 'right', - 'top-right', - 'top', - 'top-left', - 'left', - 'bottom-left', - 'bottom', - 'bottom-right' - ]; - let hoverDirectionNames = deepClone(directionNames); - - let angleMoveNum = 0; - if (data && uuid) { - const elemIdx = this.getElementIndexByUUID(uuid); - if (elemIdx !== null && elemIdx >= 0) { - const elem = data.elements[elemIdx]; - let angle = elem.angle || 0; - if (angle < 0) { - angle += 360; - } - if (angle < 45) { - angleMoveNum = 0; - } else if (angle < 90) { - angleMoveNum = 1; - } else if (angle < 135) { - angleMoveNum = 2; - } else if (angle < 180) { - angleMoveNum = 3; - } else if (angle < 225) { - angleMoveNum = 4; - } else if (angle < 270) { - angleMoveNum = 5; - } else if (angle < 315) { - angleMoveNum = 6; - } - } - } - if (angleMoveNum > 0) { - hoverDirectionNames = hoverDirectionNames - .slice(-angleMoveNum) - .concat(hoverDirectionNames.slice(0, -angleMoveNum)); - } - - rotateContext(ctx, wrapper.translate, wrapper.radian || 0, () => { - for (let i = 0; i < controllers.length; i++) { - const controller = controllers[i]; - if (controller.invisible === true) { - continue; - } - - ctx.beginPath(); - ctx.arc( - controller.x, - controller.y, - wrapper.controllerSize, - 0, - Math.PI * 2 - ); - ctx.closePath(); - - if (ctx.isPointInPath(p.x, p.y)) { - selectedControllerDirection = directionNames[i]; - hoverControllerDirection = hoverDirectionNames[i]; - } - if (selectedControllerDirection) { - directIndex = i; - break; - } - } - }); - - if (selectedControllerDirection === null) { - const controller = wrapper.controllers.rotate; - if (controller.invisible !== true) { - rotateContext(ctx, wrapper.translate, wrapper.radian || 0, () => { - ctx.beginPath(); - ctx.arc( - controller.x, - controller.y, - wrapper.controllerSize, - 0, - Math.PI * 2 - ); - ctx.closePath(); - if (ctx.isPointInPath(p.x, p.y)) { - selectedControllerDirection = 'rotate'; - hoverControllerDirection = 'rotate'; - } - }); - } - } - - return { - uuid, - selectedControllerDirection, - hoverControllerDirection, - directIndex - }; - } - - isPointInElementList(p: Point, data: IDrawData): boolean { - const ctx = this._ctx; - let idx = -1; - let uuid = null; - const wrapperList = this._helperConfig?.selectedElementListWrappers || []; - for (let i = 0; i < wrapperList.length; i++) { - const wrapper = wrapperList[i]; - const elemIdx = this._helperConfig.elementIndexMap[wrapper.uuid]; - const ele = data.elements[elemIdx]; - if (!ele) continue; - if (ele.operation?.invisible === true) continue; - let bw = 0; - // @ts-ignore - if (ele.desc?.borderWidth > 0) { - // @ts-ignore - bw = ele.desc.borderWidth; - } - rotateElement(ctx, ele, () => { - ctx.beginPath(); - ctx.moveTo(ele.x - bw, ele.y - bw); - ctx.lineTo(ele.x + ele.w + bw, ele.y - bw); - ctx.lineTo(ele.x + ele.w + bw, ele.y + ele.h + bw); - ctx.lineTo(ele.x - bw, ele.y + ele.h + bw); - ctx.lineTo(ele.x - bw, ele.y - bw); - ctx.closePath(); - if (ctx.isPointInPath(p.x, p.y)) { - idx = i; - uuid = ele.uuid; - } - }); - if (idx >= 0) { - break; - } - } - if (uuid && idx >= 0) { - return true; - } else { - return false; - } - } - - startSelectArea(p: Point) { - this._areaStart = p; - this._areaEnd = p; - } - - changeSelectArea(p: Point) { - this._areaEnd = p; - this._calcSelectedArea(); - } - - clearSelectedArea() { - this._areaStart = { x: 0, y: 0 }; - this._areaEnd = { x: 0, y: 0 }; - this._calcSelectedArea(); - } - - calcSelectedElements(data: IDrawData) { - const transform = this._ctx.getTransform(); - const { scale = 1, scrollX = 0, scrollY = 0 } = transform; - const start = this._areaStart; - const end = this._areaEnd; - const x = (Math.min(start.x, end.x) - scrollX) / scale; - const y = (Math.min(start.y, end.y) - scrollY) / scale; - const w = Math.abs(end.x - start.x) / scale; - const h = Math.abs(end.y - start.y) / scale; - const uuids: string[] = []; - const ctx = this._ctx; - - ctx.beginPath(); - ctx.moveTo(x, y); - ctx.lineTo(x + w, y); - ctx.lineTo(x + w, y + h); - ctx.lineTo(x, y + h); - ctx.lineTo(x, y); - // ctx.rect(x, y, w, h); - ctx.closePath(); - data.elements.forEach((elem) => { - if (elem?.operation?.invisible !== true) { - const centerX = elem.x + elem.w / 2; - const centerY = elem.y + elem.h / 2; - if (ctx.isPointInPathWithoutScroll(centerX, centerY)) { - uuids.push(elem.uuid); - } - } - }); - return uuids; - } - - private _calcSelectedArea() { - const start = this._areaStart; - const end = this._areaEnd; - - const transform = this._ctx.getTransform(); - const { scale = 1, scrollX = 0, scrollY = 0 } = transform; - const elemWrapper = this._coreConfig.elementWrapper; - const lineWidth = elemWrapper.lineWidth / scale; - const lineDash = elemWrapper.lineDash.map((n) => n / scale); - - this._helperConfig.selectedAreaWrapper = { - x: (Math.min(start.x, end.x) - scrollX) / scale, - y: (Math.min(start.y, end.y) - scrollY) / scale, - w: Math.abs(end.x - start.x) / scale, - h: Math.abs(end.y - start.y) / scale, - startPoint: { x: start.x, y: start.y }, - endPoint: { x: end.x, y: end.y }, - lineWidth: lineWidth, - lineDash: lineDash, - color: elemWrapper.color - }; - } - - private _updateElementIndex(data: IDrawData) { - this._helperConfig.elementIndexMap = {}; - data.elements.forEach((elem: DataElement, i) => { - this._helperConfig.elementIndexMap[elem.uuid] = i; - }); - } - - private _updateSelectedElementWrapper( - data: IDrawData, - opts: HelperUpdateOpts - ) { - const { selectedUUID: uuid } = opts; - if ( - !( - typeof uuid === 'string' && - this._helperConfig.elementIndexMap[uuid] >= 0 - ) - ) { - delete this._helperConfig.selectedElementWrapper; - return; - } - const index: number = this._helperConfig.elementIndexMap[uuid]; - const elem = data.elements[index]; - if (elem?.operation?.invisible === true) { - return; - } - const wrapper = this._createSelectedElementWrapper(elem, opts); - this._helperConfig.selectedElementWrapper = wrapper; - } - - private _updateSelectedElementListWrapper( - data: IDrawData, - opts: HelperUpdateOpts - ) { - const { selectedUUIDList } = opts; - const wrapperList: HeplerSelectedElementWrapper[] = []; - data.elements.forEach((elem) => { - if (selectedUUIDList?.includes(elem.uuid)) { - const wrapper = this._createSelectedElementWrapper(elem, opts); - wrapperList.push(wrapper); - } - }); - this._helperConfig.selectedElementListWrappers = wrapperList; - } - - private _createSelectedElementWrapper( - elem: DataElement, - opts: HelperUpdateOpts - ): HeplerSelectedElementWrapper { - const { scale } = opts; - const elemWrapper = this._coreConfig.elementWrapper; - const controllerSize = elemWrapper.controllerSize / scale; - const lineWidth = elemWrapper.lineWidth / scale; - const lineDash = elemWrapper.lineDash.map((n) => n / scale); - - const rotateLimit = 12; - // @ts-ignore - const bw = elem.desc?.borderWidth || 0; - let hideObliqueDirection = false; - if ( - typeof elem.angle === 'number' && - Math.abs(elem.angle) > limitQbliqueAngle - ) { - hideObliqueDirection = true; - } - // TODO - // const controllerOffset = controllerSize; - const controllerOffset = lineWidth; - - const wrapper: HeplerSelectedElementWrapper = { - uuid: elem.uuid, - controllerSize: controllerSize, - controllerOffset: controllerOffset, - lock: elem?.operation?.lock === true, - controllers: { - topLeft: { - x: elem.x - controllerOffset - bw, - y: elem.y - controllerOffset - bw, - invisible: - hideObliqueDirection || elem?.operation?.disableScale === true - }, - top: { - x: elem.x + elem.w / 2, - y: elem.y - controllerOffset - bw, - invisible: elem?.operation?.disableScale === true - }, - topRight: { - x: elem.x + elem.w + controllerOffset + bw, - y: elem.y - controllerOffset - bw, - invisible: - hideObliqueDirection || elem?.operation?.disableScale === true - }, - right: { - x: elem.x + elem.w + controllerOffset + bw, - y: elem.y + elem.h / 2, - invisible: elem?.operation?.disableScale === true - }, - bottomRight: { - x: elem.x + elem.w + controllerOffset + bw, - y: elem.y + elem.h + controllerOffset + bw, - invisible: - hideObliqueDirection || elem?.operation?.disableScale === true - }, - bottom: { - x: elem.x + elem.w / 2, - y: elem.y + elem.h + controllerOffset + bw, - invisible: elem?.operation?.disableScale === true - }, - bottomLeft: { - x: elem.x - controllerOffset - bw, - y: elem.y + elem.h + controllerOffset + bw, - invisible: - hideObliqueDirection || elem?.operation?.disableScale === true - }, - left: { - x: elem.x - controllerOffset - bw, - y: elem.y + elem.h / 2, - invisible: elem?.operation?.disableScale === true - }, - rotate: { - x: elem.x + elem.w / 2, - y: elem.y - controllerSize - (controllerSize * 2 + rotateLimit) - bw, - invisible: elem?.operation?.disableRotate === true - } - }, - lineWidth: lineWidth, - lineDash: lineDash, - color: - elem?.operation?.lock === true - ? elemWrapper.lockColor - : elemWrapper.color - }; - - if (typeof elem.angle === 'number' && (elem.angle > 0 || elem.angle < 0)) { - wrapper.radian = parseAngleToRadian(elem.angle); - wrapper.translate = calcElementCenter(elem); - } - - return wrapper; - } -} diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts deleted file mode 100644 index d722226..0000000 --- a/packages/core/src/lib/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from './calculate'; -export * from './check'; -export * from './config'; -export * from './core-event'; -export * from './diff'; -export * from './element'; -export * from './helper'; -export * from './is'; -export * from './mapper'; -export * from './parse'; -export * from './temp'; -export * from './transform'; -export * from './value'; diff --git a/packages/core/src/lib/is.ts b/packages/core/src/lib/is.ts deleted file mode 100644 index 578f798..0000000 --- a/packages/core/src/lib/is.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { isColorStr } from '@idraw/util'; - -function number(value: any) { - return typeof value === 'number' && (value > 0 || value <= 0); -} - -function x(value: any) { - return number(value); -} - -function y(value: any) { - return number(value); -} - -function w(value: any) { - return typeof value === 'number' && value >= 0; -} - -function h(value: any) { - return typeof value === 'number' && value >= 0; -} - -function angle(value: any) { - return typeof value === 'number' && value >= -360 && value <= 360; -} - -function borderWidth(value: any) { - return w(value); -} - -function borderRadius(value: any) { - return number(value) && value >= 0; -} - -function color(value: any) { - return isColorStr(value); -} - -function imageURL(value: any) { - return ( - typeof value === 'string' && - /^(http:\/\/|https:\/\/|\.\/|\/)/.test(`${value}`) - ); -} - -function imageBase64(value: any) { - return typeof value === 'string' && /^(data:image\/)/.test(`${value}`); -} - -function imageSrc(value: any) { - return imageBase64(value) || imageURL(value); -} - -function svg(value: any) { - return ( - typeof value === 'string' && - /^()/i.test(`${value}`.trim()) && - /<\/[\s]{0,}svg>$/i.test(`${value}`.trim()) - ); -} - -function html(value: any) { - let result = false; - if (typeof value === 'string') { - let div: null | HTMLDivElement = document.createElement('div'); - div.innerHTML = value; - if (div.children.length > 0) { - result = true; - } - div = null; - } - return result; -} - -function text(value: any) { - return typeof value === 'string'; -} - -function fontSize(value: any) { - return number(value) && value > 0; -} - -function lineHeight(value: any) { - return number(value) && value > 0; -} - -function strokeWidth(value: any) { - return number(value) && value > 0; -} - -function textAlign(value: any) { - return ['center', 'left', 'right'].includes(value); -} - -function fontFamily(value: any) { - return typeof value === 'string' && value.length > 0; -} - -function fontWeight(value: any) { - return ['bold'].includes(value); -} - -const is: IsTypeUtil = { - x, - y, - w, - h, - angle, - number, - borderWidth, - borderRadius, - color, - imageSrc, - imageURL, - imageBase64, - svg, - html, - text, - fontSize, - lineHeight, - textAlign, - fontFamily, - fontWeight, - strokeWidth -}; - -type IsTypeUtil = { - x: (value: any) => boolean; - y: (value: any) => boolean; - w: (value: any) => boolean; - h: (value: any) => boolean; - angle: (value: any) => boolean; - number: (value: any) => boolean; - borderWidth: (value: any) => boolean; - borderRadius: (value: any) => boolean; - color: (value: any) => boolean; - imageSrc: (value: any) => boolean; - imageURL: (value: any) => boolean; - imageBase64: (value: any) => boolean; - svg: (value: any) => boolean; - html: (value: any) => boolean; - text: (value: any) => boolean; - fontSize: (value: any) => boolean; - fontWeight: (value: any) => boolean; - lineHeight: (value: any) => boolean; - textAlign: (value: any) => boolean; - fontFamily: (value: any) => boolean; - strokeWidth: (value: any) => boolean; -}; - -export default is; - -export { IsTypeUtil }; diff --git a/packages/core/src/lib/mapper.ts b/packages/core/src/lib/mapper.ts deleted file mode 100644 index 812b450..0000000 --- a/packages/core/src/lib/mapper.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { IDrawData, Point, PointCursor } from '@idraw/types'; -import Board from '@idraw/board'; -import { Helper } from './helper'; -import { Element } from './element'; - -const _board = Symbol('_displayCtx'); -const _helper = Symbol('_helper'); -const _element = Symbol('_element'); -const _opts = Symbol('_opts'); - -type Options = { - board: Board; - element: Element; - helper: Helper; -}; - -export class Mapper { - private [_opts]: Options; - private [_board]: Board; - private [_helper]: Helper; - private [_element]: Element; - - constructor(opts: Options) { - this[_opts] = opts; - this[_board] = this[_opts].board; - this[_element] = this[_opts].element; - this[_helper] = this[_opts].helper; - } - - isEffectivePoint(p: Point): boolean { - const scrollLineWidth = this[_board].getScrollLineWidth(); - const screenInfo = this[_board].getScreenInfo(); - if ( - p.x <= screenInfo.width - scrollLineWidth && - p.y <= screenInfo.height - scrollLineWidth - ) { - return true; - } - return false; - } - - judgePointCursor( - p: Point, - data: IDrawData - ): { - cursor: PointCursor; - elementUUID: string | null; - } { - let cursor: PointCursor = 'auto'; - let elementUUID: string | null = null; - if (!this.isEffectivePoint(p)) { - return { cursor, elementUUID }; - } - const { uuid, hoverControllerDirection } = this[ - _helper - ].isPointInElementWrapperController(p, data); - const direction = hoverControllerDirection; - if (uuid && direction) { - switch (direction) { - case 'top-right': { - cursor = 'ne-resize'; - break; - } - - case 'top-left': { - cursor = 'nw-resize'; - break; - } - case 'top': { - cursor = 'n-resize'; - break; - } - - case 'right': { - cursor = 'e-resize'; - break; - } - case 'bottom-right': { - cursor = 'se-resize'; - break; - } - case 'bottom': { - cursor = 's-resize'; - break; - } - case 'bottom-left': { - cursor = 'sw-resize'; - break; - } - case 'left': { - cursor = 'w-resize'; - break; - } - case 'rotate': { - cursor = 'grab'; - break; - } - default: { - break; - } - } - if (uuid) { - elementUUID = uuid; - } - } else { - const [index, uuid] = this[_element].isPointInElement(p, data); - if (index >= 0) { - cursor = 'move'; - } - if (uuid) { - elementUUID = uuid; - } - } - return { - cursor, - elementUUID - }; - } -} diff --git a/packages/core/src/lib/parse.ts b/packages/core/src/lib/parse.ts deleted file mode 100644 index 3cdcbae..0000000 --- a/packages/core/src/lib/parse.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IDrawData, DataElement, DataElemDesc } from '@idraw/types'; -import { elementNames } from './../constant/element'; - -export function parseData(data: any): IDrawData { - const result: IDrawData = { - elements: [] - }; - if (Array.isArray(data?.elements)) { - data?.elements.forEach((elem: any = {}) => { - if (isElement(elem)) { - result.elements.push(elem); - } - }); - } - if (typeof data.bgColor === 'string') { - result.bgColor = data.bgColor; - } - return result; -} - -function isElement(elem: DataElement): boolean { - if ( - !( - isNumber(elem.x) && - isNumber(elem.y) && - isNumber(elem.w) && - isNumber(elem.h) - ) - ) { - return false; - } - if (!(typeof elem.type === 'string' && elementNames.includes(elem.type))) { - return false; - } - return true; -} - -function isNumber(num: any) { - return num >= 0 || num < 0; -} diff --git a/packages/core/src/lib/temp.ts b/packages/core/src/lib/temp.ts deleted file mode 100644 index 9da158b..0000000 --- a/packages/core/src/lib/temp.ts +++ /dev/null @@ -1,31 +0,0 @@ -type TempDataDesc = { - hasInited: boolean; -} - -function createData(): TempDataDesc { - return { - hasInited: false, - } -} - - -export class TempData { - - private _temp: TempDataDesc - - constructor() { - this._temp = createData(); - } - - set(name: T, value: TempDataDesc[T]) { - this._temp[name] = value; - } - - get(name: T): TempDataDesc[T] { - return this._temp[name]; - } - - clear() { - this._temp = createData(); - } -} \ No newline at end of file diff --git a/packages/core/src/lib/transform.ts b/packages/core/src/lib/transform.ts deleted file mode 100644 index 7cfdfbd..0000000 --- a/packages/core/src/lib/transform.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { IDrawContext, Point, DataElement, DataElemDesc } from '@idraw/types'; -import { calcElementCenter, parseAngleToRadian } from './calculate'; - -function rotateElement( - ctx: IDrawContext, - elem: DataElement, - callback: (ctx: IDrawContext) => void -): void { - const center: Point = calcElementCenter(elem); - const radian = parseAngleToRadian(elem.angle || 0); - return rotateContext(ctx, center, radian || 0, callback); -} - -function rotateContext( - ctx: IDrawContext, - center: Point | undefined, - radian: number, - callback: (ctx: IDrawContext) => void -): void { - if (center && (radian > 0 || radian < 0)) { - ctx.translate(center.x, center.y); - ctx.rotate(radian); - ctx.translate(-center.x, -center.y); - } - - callback(ctx); - - if (center && (radian > 0 || radian < 0)) { - ctx.translate(center.x, center.y); - ctx.rotate(-radian); - ctx.translate(-center.x, -center.y); - } -} - -export { rotateContext, rotateElement }; diff --git a/packages/core/src/lib/value.ts b/packages/core/src/lib/value.ts deleted file mode 100644 index c224a9b..0000000 --- a/packages/core/src/lib/value.ts +++ /dev/null @@ -1,9 +0,0 @@ - -export function limitNum(num: number): number { - const numStr: string = num.toFixed(2); - return parseFloat(numStr); -} - -export function limitAngle(angle: number): number { - return limitNum(angle % 360); -} diff --git a/packages/core/src/middleware/select/draw-wrapper.ts b/packages/core/src/middleware/select/draw-wrapper.ts new file mode 100644 index 0000000..b470b41 --- /dev/null +++ b/packages/core/src/middleware/select/draw-wrapper.ts @@ -0,0 +1,52 @@ +import type { Element, ElementType, RendererDrawElementOptions } from '@idraw/types'; + +export function drawPointWrapper(ctx: CanvasRenderingContext2D, elem: Element, opts?: Omit) { + const bw = 2; + let { x, y, w, h } = elem; + + if (opts?.calculator) { + const { calculator } = opts; + const size = calculator.elementSize({ x, y, w, h }, opts); + x = size.x; + y = size.y; + w = size.w; + h = size.h; + } + + ctx.setLineDash([4, 4]); + ctx.lineWidth = 2; + ctx.strokeStyle = '#e91e2f'; + + ctx.beginPath(); + ctx.moveTo(x - bw, y - bw); + ctx.lineTo(x + w + bw, y - bw); + ctx.lineTo(x + w + bw, y + h + bw); + ctx.lineTo(x - bw, y + h + bw); + ctx.lineTo(x - bw, y - bw); + ctx.closePath(); + ctx.stroke(); +} + +export function drawHoverWrapper(ctx: CanvasRenderingContext2D, elem: Element, opts?: Omit) { + const bw = 2; + let { x, y, w, h } = elem; + if (opts?.calculator) { + const { calculator } = opts; + const size = calculator.elementSize({ x, y, w, h }, opts); + x = size.x; + y = size.y; + w = size.w; + h = size.h; + } + ctx.setLineDash([]); + ctx.lineWidth = 2; + ctx.strokeStyle = '#e91e2f'; + ctx.beginPath(); + ctx.moveTo(x - bw, y - bw); + ctx.lineTo(x + w + bw, y - bw); + ctx.lineTo(x + w + bw, y + h + bw); + ctx.lineTo(x - bw, y + h + bw); + ctx.lineTo(x - bw, y - bw); + ctx.closePath(); + ctx.stroke(); +} diff --git a/packages/core/src/middleware/select/index.ts b/packages/core/src/middleware/select/index.ts new file mode 100644 index 0000000..ed41aef --- /dev/null +++ b/packages/core/src/middleware/select/index.ts @@ -0,0 +1,112 @@ +import type { Point, PointWatcherEvent, BoardMiddleware } from '@idraw/types'; +import { createBoardContexts } from '@idraw/util'; +import { drawPointWrapper, drawHoverWrapper } from './draw-wrapper'; + +export const MiddlewareSelector: BoardMiddleware = (opts) => { + const { viewer, sharer, viewContent, calculator } = opts; + const { helperContext } = viewContent; + + const key = 'SELECT'; + const keyHoverElementSize = `${key}_hoverElementSize`; + const keySelectType = `${key}_type`; // 'default' | 'hover' | 'drag' + + const getIndex = () => { + const idx = sharer.getActiveStorage('selectedIndexs')[0]; + return idx >= 0 ? idx : -1; + }; + + const getScaleInfo = () => { + return { + scale: sharer.getActiveStorage('scale'), + offsetLeft: sharer.getActiveStorage('offsetLeft'), + offsetRight: sharer.getActiveStorage('offsetRight'), + offsetTop: sharer.getActiveStorage('offsetTop'), + offsetBottom: sharer.getActiveStorage('offsetBottom') + }; + }; + + const getActiveElem = () => { + const index = getIndex(); + const storeData = sharer.getActiveStorage('data'); + return storeData?.elements?.[index] || null; + }; + + let prevPoint: Point | null = null; + let isDrag = false; + + viewer.drawFrame(); + + return { + mode: key, + hover: (e: PointWatcherEvent) => { + if (!isDrag) { + const data = sharer.getActiveStorage('data'); + if (data) { + const result = calculator.getPointElement(e.point, data, getScaleInfo()); + if (result.element) { + const { x, y, w, h } = result.element; + sharer.setSharedStorage(keySelectType, 'hover'); + sharer.setSharedStorage(keyHoverElementSize, { x, y, w, h }); + viewer.drawFrame(); + return; + } + } + if (sharer.getSharedStorage(keySelectType) === 'hover') { + sharer.setSharedStorage(keySelectType, 'default'); + sharer.setSharedStorage(keyHoverElementSize, null); + viewer.drawFrame(); + } + } + }, + pointStart: (e: PointWatcherEvent) => { + const data = sharer.getActiveStorage('data'); + if (data) { + const result = calculator.getPointElement(e.point, data, getScaleInfo()); + sharer.setActiveStorage('selectedIndexs', result.index >= 0 ? [result.index] : []); + } + if (getIndex() >= 0) { + sharer.setSharedStorage(keySelectType, 'drag'); + isDrag = true; + prevPoint = e.point; + } + }, + pointMove: (e: PointWatcherEvent) => { + if (!isDrag) { + return; + } + const data = sharer.getActiveStorage('data'); + + const index = getIndex(); + const elem = getActiveElem(); + const scale = sharer.getActiveStorage('scale') || 1; + const startPoint = prevPoint; + const endPoint = e.point; + if (data && elem && index >= 0 && startPoint && endPoint) { + data.elements[index].x += (endPoint.x - startPoint.x) / scale; + data.elements[index].y += (endPoint.y - startPoint.y) / scale; + sharer.setActiveStorage('data', data); + prevPoint = e.point; + } else { + prevPoint = null; + } + viewer.drawFrame(); + }, + pointEnd: (e: PointWatcherEvent) => { + sharer.setActiveStorage('selectedIndexs', []); + isDrag = false; + }, + + beforeDrawFrame({ snapshot }) { + const { activeStore, sharedStore } = snapshot; + const { data, selectedIndexs, scale, offsetLeft, offsetTop, offsetRight, offsetBottom } = activeStore; + const selectType = sharedStore[keySelectType]; + const hoverElement = sharedStore[keyHoverElementSize]; + const drawOpts = { calculator, scale, offsetLeft, offsetTop, offsetRight, offsetBottom }; + if (selectType === 'hover' && hoverElement) { + drawHoverWrapper(helperContext, hoverElement, drawOpts); + } else if (selectType === 'drag' && data?.elements?.[selectedIndexs?.[0]]) { + drawPointWrapper(helperContext, data?.elements?.[selectedIndexs?.[0]], drawOpts); + } + } + }; +}; diff --git a/packages/core/src/mixins/element.ts b/packages/core/src/mixins/element.ts deleted file mode 100644 index 5f8b010..0000000 --- a/packages/core/src/mixins/element.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { DataElement, DataElemDesc, DataElementBase } from '@idraw/types'; -import { deepClone, createUUID } from '@idraw/util'; -import { diffElementResourceChange } from '../lib/diff'; -import Core from '../index'; -import { Mode } from '../constant/static'; - -export function getSelectedElements( - core: Core -): DataElement[] { - const elems: DataElement[] = []; - let list: string[] = []; - const uuid = core.getEngine().temp.get('selectedUUID'); - if (typeof uuid === 'string' && uuid) { - list.push(uuid); - } else { - list = core.getEngine().temp.get('selectedUUIDList'); - } - list.forEach((uuid) => { - const index = core.getEngine().helper.getElementIndexByUUID(uuid); - if (index !== null && index >= 0) { - const elem = core.$data.elements[index]; - if (elem) elems.push(elem); - } - }); - return deepClone(elems); -} - -export function getElement( - core: Core, - uuid: string -): DataElement | null { - let elem: DataElement | null = null; - const index = core.getEngine().helper.getElementIndexByUUID(uuid); - if (index !== null && core.$data.elements[index]) { - elem = deepClone(core.$data.elements[index]); - } - return elem; -} - -export function getElementByIndex( - core: Core, - index: number -): DataElement | null { - let elem: DataElement | null = null; - if (index >= 0 && core.$data.elements[index]) { - elem = deepClone(core.$data.elements[index]); - } - return elem; -} - -export function updateElement( - core: Core, - elem: DataElement -) { - const _elem = deepClone(elem) as DataElement; - const data = core.getData(); - const resourceChangeUUIDs: string[] = []; - for (let i = 0; i < data.elements.length; i++) { - if (_elem.uuid === data.elements[i]?.uuid) { - const result = diffElementResourceChange(data.elements[i], _elem); - if (typeof result === 'string') { - resourceChangeUUIDs.push(result); - } - data.elements[i] = _elem; - break; - } - } - core.$emitChangeData(); - core.$draw({ resourceChangeUUIDs }); -} - -export function selectElementByIndex(core: Core, index: number): void { - if (core.$data.elements[index]) { - const uuid = core.$data.elements[index].uuid; - core.getEngine().temp.set('mode', Mode.NULL); - if (typeof uuid === 'string') { - core.getEngine().temp.set('selectedUUID', uuid); - core.getEngine().temp.set('selectedUUIDList', []); - } - core.$draw(); - } -} - -export function selectElement(core: Core, uuid: string): void { - const index = core.getEngine().helper.getElementIndexByUUID(uuid); - if (typeof index === 'number' && index >= 0) { - core.selectElementByIndex(index); - } -} - -export function cancelElementByIndex(core: Core, index: number): void { - if (core.$data.elements[index]) { - const uuid = core.$data.elements[index].uuid; - const selectedUUID = core.getEngine().temp.get('selectedUUID'); - if (typeof uuid === 'string' && uuid === selectedUUID) { - core.getEngine().temp.set('mode', Mode.NULL); - core.getEngine().temp.set('selectedUUID', null); - core.getEngine().temp.set('selectedUUIDList', []); - } - core.$draw(); - } -} - -export function cancelElement(core: Core, uuid: string): void { - const index = core.getEngine().helper.getElementIndexByUUID(uuid); - if (typeof index === 'number' && index >= 0) { - core.cancelElementByIndex(index); - } -} - -export function moveUpElement(core: Core, uuid: string): void { - const index = core.getEngine().helper.getElementIndexByUUID(uuid); - if ( - typeof index === 'number' && - index >= 0 && - index < core.$data.elements.length - 1 - ) { - const temp = core.$data.elements[index]; - core.$data.elements[index] = core.$data.elements[index + 1]; - core.$data.elements[index + 1] = temp; - } - core.$emitChangeData(); - core.$draw(); -} - -export function moveDownElement(core: Core, uuid: string): void { - const index = core.getEngine().helper.getElementIndexByUUID(uuid); - if ( - typeof index === 'number' && - index > 0 && - index < core.$data.elements.length - ) { - const temp = core.$data.elements[index]; - core.$data.elements[index] = core.$data.elements[index - 1]; - core.$data.elements[index - 1] = temp; - } - core.$emitChangeData(); - core.$draw(); -} - -export function addElement( - core: Core, - elem: DataElementBase -): string | null { - const _elem = deepClone(elem); - _elem.uuid = createUUID(); - core.$data.elements.push(_elem); - core.$emitChangeData(); - core.$draw(); - return _elem.uuid; -} - -export function deleteElement(core: Core, uuid: string) { - const index = core.$getElementHandler().getElementIndex(core.getData(), uuid); - if (index >= 0) { - core.$data.elements.splice(index, 1); - core.$emitChangeData(); - core.$draw(); - } -} - -export function insertElementBefore( - core: Core, - elem: DataElementBase, - beforeUUID: string -) { - const index = core.getEngine().helper.getElementIndexByUUID(beforeUUID); - if (index !== null) { - return core.insertElementBeforeIndex(elem, index); - } - return null; -} - -export function insertElementBeforeIndex( - core: Core, - elem: DataElementBase, - index: number -) { - const _elem = deepClone(elem); - _elem.uuid = createUUID(); - if (index >= 0) { - core.$data.elements.splice(index, 0, _elem); - core.$emitChangeData(); - core.$draw(); - return _elem.uuid; - } - return null; -} - -export function insertElementAfter( - core: Core, - elem: DataElementBase, - beforeUUID: string -) { - const index = core.getEngine().helper.getElementIndexByUUID(beforeUUID); - if (index !== null) { - return core.insertElementAfterIndex(elem, index); - } - return null; -} - -export function insertElementAfterIndex( - core: Core, - elem: DataElementBase, - index: number -) { - const _elem = deepClone(elem); - _elem.uuid = createUUID(); - if (index >= 0) { - core.$data.elements.splice(index + 1, 0, _elem); - core.$emitChangeData(); - core.$draw(); - return _elem.uuid; - } - return null; -} diff --git a/packages/core/src/plugins/helper.ts b/packages/core/src/plugins/helper.ts deleted file mode 100644 index d5f7354..0000000 --- a/packages/core/src/plugins/helper.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { - InterfaceHelperPlugin, - HelperPluginEventDetail, - HelperPluginEventResult -} from '@idraw/types'; -import { createUUID } from '@idraw/util'; - -export class HelperPlugin implements Required { - readonly name: string = 'helper-plugin'; - - readonly uuid: string; - - constructor() { - // TODO - this.uuid = createUUID(); - } - - onHover(detail: HelperPluginEventDetail): void | HelperPluginEventResult { - if (detail.controller === null) { - } - } - - onPoint(detail: HelperPluginEventDetail): void | HelperPluginEventResult {} - - onClick(detail: HelperPluginEventDetail): void | HelperPluginEventResult {} - - onMoveStart( - detail: HelperPluginEventDetail - ): void | HelperPluginEventResult {} - - onMove(detail: HelperPluginEventDetail): void | HelperPluginEventResult {} - - onMoveEnd(detail: HelperPluginEventDetail): void | HelperPluginEventResult {} -} diff --git a/packages/core/src/util/filter.ts b/packages/core/src/util/filter.ts deleted file mode 100644 index df84741..0000000 --- a/packages/core/src/util/filter.ts +++ /dev/null @@ -1,4 +0,0 @@ - -export function filterScript(html: string) { - return html.replace(//ig, ''); -} \ No newline at end of file diff --git a/packages/idraw/dev/data.ts b/packages/idraw/dev/data.ts index 62a0a34..2de6732 100644 --- a/packages/idraw/dev/data.ts +++ b/packages/idraw/dev/data.ts @@ -1,90 +1,183 @@ -import type { IDrawDataBase } from '@idraw/types'; +import type { Data } from '@idraw/types'; -const data: IDrawDataBase = { - bgColor: '#ffffff', +// const data: Data = { +// bgColor: '#ffffff', +// elements: [ +// { +// name: 'rect-001', +// x: 5, +// y: 5, +// w: 100, +// h: 50, +// type: 'rect', +// desc: { +// bgColor: '#ffeb3b', +// borderRadius: 10, +// borderWidth: 5, +// borderColor: '#ffc107' +// } +// }, +// { +// name: 'text-002', +// x: 40, +// y: 40, +// w: 100, +// h: 60, +// // angle: 30, +// type: 'text', +// desc: { +// fontSize: 16, +// text: 'Hello Text', +// fontWeight: 'bold', +// color: '#666666', +// borderRadius: 30, +// borderWidth: 4, +// borderColor: '#ff5722' +// } +// }, +// { +// name: 'image-003', +// x: 80, +// y: 80, +// w: 160, +// h: 80, +// type: 'image', +// desc: { +// src: './images/computer.png' +// }, +// operation: { +// // disableRotate: true, +// limitRatio: true +// } +// }, +// { +// name: 'svg-004', +// x: 200 - 5, +// y: 150 - 50, +// w: 100, +// h: 100, +// type: 'svg', +// angle: 135, +// desc: { +// svg: '' +// }, +// operation: { +// // disableRotate: true, +// limitRatio: true +// } +// }, +// { +// name: 'text-002', +// x: 200, +// y: 200, +// w: 300, +// h: 100, +// // angle: 30, +// type: 'text', +// desc: { +// fontSize: 16, +// // text: 'Hello Text Hello Text Hello Text Hello Text Hello Text Hello Text', +// text: 'Hello Text', +// fontWeight: 'bold', +// color: '#666666', +// borderRadius: 30, +// borderWidth: 2, +// borderColor: '#ff5722', +// textAlign: 'center', +// verticalAlign: 'middle' +// } +// } +// ] +// }; + +const data: Data = { elements: [ { - name: 'rect-001', - x: 5, - y: 5, - w: 100, - h: 50, - type: 'rect', - desc: { - bgColor: '#ffeb3b', - borderRadius: 10, - borderWidth: 5, - borderColor: '#ffc107' - } - }, - { - name: 'text-002', - x: 40, - y: 40, - w: 100, - h: 60, - // angle: 30, - type: 'text', - desc: { - fontSize: 16, - text: 'Hello Text', - fontWeight: 'bold', - color: '#666666', - borderRadius: 30, - borderWidth: 4, - borderColor: '#ff5722' - } - }, - { - name: 'image-003', - x: 80, - y: 80, - w: 160, - h: 80, + uuid: 'xxx-0003', type: 'image', - desc: { - src: './images/computer.png' - }, - operation: { - // disableRotate: true, - limitRatio: true - } - }, - { - name: 'svg-004', - x: 200 - 5, - y: 150 - 50, + x: 100, + y: 100, w: 100, h: 100, - type: 'svg', - angle: 135, desc: { - svg: '' - }, - operation: { - // disableRotate: true, - limitRatio: true + src: './images/lena.png' } }, { - name: 'text-002', - x: 200, - y: 200, - w: 300, + uuid: 'xxxx-0001', + x: 2, + y: 2, + w: 100, h: 100, - // angle: 30, - type: 'text', + type: 'circle', desc: { - fontSize: 16, - // text: 'Hello Text Hello Text Hello Text Hello Text Hello Text Hello Text', - text: 'Hello Text', - fontWeight: 'bold', - color: '#666666', - borderRadius: 30, - borderWidth: 2, - borderColor: '#ff5722', - textAlign: 'center', - verticalAlign: 'middle' + bgColor: '#f44336' + } + }, + { + uuid: 'xxx-0002', + type: 'rect', + x: 50, + y: 50, + w: 100, + h: 100, + desc: { + bgColor: '#2196f3' + } + }, + { + uuid: 'xxx-0004', + type: 'image', + x: 250, + y: 250, + w: 100, + h: 100, + desc: { + src: './images/github.png?t=003' + } + }, + { + uuid: 'xxxx-0005', + x: 0, + y: 300, + w: 100, + h: 100, + type: 'circle', + desc: { + bgColor: '#009688' + } + }, + { + uuid: 'xxxx-0006', + x: 300, + y: 300, + w: 100, + h: 100, + type: 'circle', + desc: { + bgColor: '#673ab7' + } + }, + { + uuid: 'xxxx-0007', + x: 300, + y: 0, + w: 100, + h: 100, + type: 'circle', + desc: { + bgColor: '#ffc107' + } + }, + { + uuid: 'xxxx-0008', + x: 150, + y: 150, + w: 100, + h: 100, + type: 'circle', + desc: { + bgColor: '#4caf50' } } ] diff --git a/packages/idraw/dev/images/github.png b/packages/idraw/dev/images/github.png new file mode 100644 index 0000000000000000000000000000000000000000..3d645928a6dbc889adcad2d59372c7a8e6146ea3 GIT binary patch literal 201891 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
  • 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

    @#PR-Z9m^i<~0XO{y6iQSZ)7m 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໏-wI);?u^93%MzZofkfq~qI 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

    @#x|vyuND2OApai;mnx>$*48Ut(DWe{>Y4 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 TCu?*8@JI8e&W#c^blCp`P9nd0 literal 0 HcmV?d00001 diff --git a/packages/idraw/dev/images/lena.png b/packages/idraw/dev/images/lena.png new file mode 100644 index 0000000000000000000000000000000000000000..08e54c55a4e424b212019aaf341eb9238e668548 GIT binary patch literal 146364 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 { - console.log('changeData ======', d); -}); +// idraw.on('changeData', (d) => { +// console.log('changeData ======', d); +// }); -idraw.scale(1.5); +// idraw.scale(1.5); +// idraw.selectElementByIndex(1); -idraw.selectElementByIndex(1); +// setTimeout(() => { +// // idraw.cancelElementByIndex(1); +// // idraw.cancelElement(parseData.elements[1].uuid); +// }, 2000); -setTimeout(() => { - // idraw.cancelElementByIndex(1); - // idraw.cancelElement(parseData.elements[1].uuid); -}, 2000); - -const btn = document.querySelector('#btn') as HTMLButtonElement; -btn.addEventListener('click', () => { - idraw - .exportDataURL({ type: 'image/png' }) - .then((dataURL) => { - const preview = document.querySelector('#preview') as HTMLDivElement; - preview.innerHTML = ``; - }) - .catch((err) => { - console.log(err); - }); -}); +// const btn = document.querySelector('#btn') as HTMLButtonElement; +// btn.addEventListener('click', () => { +// idraw +// .exportDataURL({ type: 'image/png' }) +// .then((dataURL) => { +// const preview = document.querySelector('#preview') as HTMLDivElement; +// preview.innerHTML = ``; +// }) +// .catch((err) => { +// console.log(err); +// }); +// }); diff --git a/packages/idraw/src/config.ts b/packages/idraw/src/config.ts deleted file mode 100644 index 300fbf0..0000000 --- a/packages/idraw/src/config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PrivateOptions } from './types'; - -export const defaultOptions: PrivateOptions = { - width: 400, - height: 300, - contextWidth: 400, - contextHeight: 300, - devicePixelRatio: 1, - onlyRender: false, - maxRecords: 10, - disableKeyboard: true -}; diff --git a/packages/idraw/src/index.ts b/packages/idraw/src/index.ts index 20f7b9a..4e9f389 100644 --- a/packages/idraw/src/index.ts +++ b/packages/idraw/src/index.ts @@ -1,113 +1,18 @@ -import Core from '@idraw/core'; -import { IDrawData, IDrawConfig } from '@idraw/types'; -import { Options, PrivateOptions } from './types'; -import { defaultOptions } from './config'; -import { TempData } from './lib/temp'; -import { KeyboardWatcher } from './lib/keyboard-watcher'; +import { Core, MiddlewareSelector } from '@idraw/core'; +import type { IDrawOptions, Data } from '@idraw/types'; -import { redo, undo } from './mixins/record'; -import { exportDataURL, toDataURL } from './mixins/file'; -import { - copyElements, - pasteElements, - cutElements, - deleteElements, - keyArrowUp, - keyArrowDown, - keyArrowLeft, - keyArrowRight, - keyUndo -} from './mixins/keyboard'; -// import { version } from './../package.json'; +export class iDraw { + private _core: Core; + private _opts: IDrawOptions; -export default class iDraw extends Core { - private _opts: PrivateOptions; - private _hasInited = false; - private _tempData = new TempData(); - private _keyboardWatcher = new KeyboardWatcher(); - - // static version = version; - - constructor(mount: HTMLDivElement, opts: Options, config?: IDrawConfig) { - super( - mount, - { - width: opts.width || defaultOptions.width, - height: opts.height || defaultOptions.height, - contextWidth: opts.contextWidth || defaultOptions.contextWidth, - contextHeight: opts.contextHeight || defaultOptions.contextHeight, - devicePixelRatio: - opts.devicePixelRatio || defaultOptions.devicePixelRatio, - onlyRender: opts.onlyRender || defaultOptions.onlyRender - }, - config || {} - ); - this._opts = this._createOpts(opts); - this._initEvent(); + constructor(mount: HTMLDivElement, opts: IDrawOptions) { + const core = new Core(mount, opts); + this._core = core; + this._opts = opts; + core.use(MiddlewareSelector); } - undo(): { doRecordCount: number; data: IDrawData | null } { - return undo(this); - } - - redo(): { undoRecordCount: number; data: IDrawData | null } { - return redo(this); - } - - toDataURL(type: 'image/png' | 'image/jpeg', quality?: number): string { - return toDataURL(this, type, quality); - } - - getTempData() { - return this._tempData; - } - - async exportDataURL( - type: 'image/png' | 'image/jpeg', - quality?: number - ): Promise { - return exportDataURL(this, type, quality); - } - - private _initEvent() { - if (this._hasInited === true) { - return; - } - this.on('changeData', (data: IDrawData) => { - this._pushRecord(data); - }); - this.on('mouseLeaveScreen', () => { - this._tempData.set('isFocus', false); - }); - this.on('mouseOverScreen', () => { - this._tempData.set('isFocus', true); - }); - if (this._opts.disableKeyboard === false) { - this._keyboardWatcher - .on('keyboardCopy', () => copyElements(this)) - .on('keyboardPaste', () => pasteElements(this)) - .on('keyboardCut', () => cutElements(this)) - .on('keyboardDelete', () => deleteElements(this)) - .on('keyboardArrowUp', () => keyArrowUp(this)) - .on('keyboardArrowDown', () => keyArrowDown(this)) - .on('keyboardArrowLeft', () => keyArrowLeft(this)) - .on('keyboardArrowRight', () => keyArrowRight(this)) - .on('keyboardUndo', () => keyUndo(this)); - } - this._hasInited = true; - } - - private _pushRecord(data: IDrawData) { - const doRecords = this._tempData.get('doRecords'); - if (doRecords.length >= this._opts.maxRecords) { - doRecords.shift(); - } - doRecords.push({ data, time: Date.now() }); - this._tempData.set('doRecords', doRecords); - this._tempData.set('unDoRecords', []); - } - - private _createOpts(opts: Options): PrivateOptions { - return { ...{}, ...defaultOptions, ...opts }; + setData(data: Data) { + this._core.setData(data); } } diff --git a/packages/idraw/src/lib/keyboard-watcher.ts b/packages/idraw/src/lib/keyboard-watcher.ts deleted file mode 100644 index 2ea8c84..0000000 --- a/packages/idraw/src/lib/keyboard-watcher.ts +++ /dev/null @@ -1,104 +0,0 @@ - - -export type TypeKeyboardEventArgMap = { - 'keyboardCopy': void; - 'keyboardPaste': void; - 'keyboardCut': void; - 'keyboardDelete': void; - 'keyboardArrowRight': void; - 'keyboardArrowLeft': void; - 'keyboardArrowUp': void; - 'keyboardArrowDown': void; - 'keyboardUndo': void; -} - -export interface TypeKeyboardEvent { - on(key: T, callback: (p: TypeKeyboardEventArgMap[T]) => void): void - off(key: T, callback: (p: TypeKeyboardEventArgMap[T]) => void): void - // trigger(key: T, p: TypeKeyboardEventArgMap[T]): void -} - - -export class KeyboardWatcher implements TypeKeyboardEvent { - - private _listeners: Map void)[]>; - - constructor() { - this._listeners = new Map(); - this._initEvent(); - } - - private _initEvent() { - document.addEventListener('keydown', (e) => { - if ((e.metaKey === true || e.ctrlKey === true) && e.key === 'c') { - this.trigger('keyboardCopy', undefined); - } else if ((e.metaKey === true || e.ctrlKey === true) && e.key === 'v') { - this.trigger('keyboardPaste', undefined); - } else if ((e.metaKey === true || e.ctrlKey === true) && e.key === 'x') { - this.trigger('keyboardCut', undefined); - } else if ((e.metaKey === true || e.ctrlKey === true) && e.key === 'z') { - this.trigger('keyboardUndo', undefined); - } else if (e.key === 'Backspace') { - this.trigger('keyboardDelete', undefined); - } else if (e.key === 'ArrowUp') { - this.trigger('keyboardArrowUp', undefined); - } else if (e.key === 'ArrowDown') { - this.trigger('keyboardArrowDown', undefined); - } else if (e.key === 'ArrowLeft') { - this.trigger('keyboardArrowLeft', undefined); - } else if (e.key === 'ArrowRight') { - this.trigger('keyboardArrowRight', undefined); - } - }); - } - - on(eventKey: T, callback: (p: TypeKeyboardEventArgMap[T]) => void) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - callbacks?.push(callback); - this._listeners.set(eventKey, callbacks || []); - } else { - this._listeners.set(eventKey, [callback]); - } - return this; - } - - off(eventKey: T, callback: (p: TypeKeyboardEventArgMap[T]) => void) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - for (let i = 0; i < callbacks?.length; i++) { - if (callbacks[i] === callback) { - callbacks.splice(i, 1); - break; - } - } - } - this._listeners.set(eventKey, callbacks || []); - } - return this; - } - - trigger(eventKey: T, arg: TypeKeyboardEventArgMap[T]) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - callbacks.forEach((cb) => { - cb(arg); - }); - return true; - } else { - return false; - } - } - - has (name: string) { - if (this._listeners.has(name)) { - const list: ((p: TypeKeyboardEventArgMap[T]) => void)[] | undefined = this._listeners.get(name); - if (Array.isArray(list) && list.length > 0) { - return true; - } - } - return false; - } - -} diff --git a/packages/idraw/src/lib/keyboard.ts b/packages/idraw/src/lib/keyboard.ts deleted file mode 100644 index eb2ed88..0000000 --- a/packages/idraw/src/lib/keyboard.ts +++ /dev/null @@ -1,6 +0,0 @@ -import Core from '@idraw/core'; - -export function copySelectedElement(core: Core) { - console.log('core ====', core); - // console.log(core.getSelectedElements()); -} \ No newline at end of file diff --git a/packages/idraw/src/lib/temp.ts b/packages/idraw/src/lib/temp.ts deleted file mode 100644 index f3d2475..0000000 --- a/packages/idraw/src/lib/temp.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { DataElemDesc, DataElement } from '@idraw/types'; -import { Record } from './../types'; - -type TempDataDesc = { - isDownloading: boolean; - isFocus: boolean; - doRecords: Record[]; - unDoRecords: Record[]; - clipboardElements: DataElement[]; -}; - -function createDefaultData() { - return { - isFocus: false, - doRecords: [], - unDoRecords: [], - clipboardElements: [], - isDownloading: false - }; -} - -export class TempData { - private _temp: TempDataDesc; - - constructor() { - this._temp = createDefaultData(); - } - - set(name: T, value: TempDataDesc[T]) { - this._temp[name] = value; - } - - get(name: T): TempDataDesc[T] { - return this._temp[name]; - } - - clear() { - this._temp = createDefaultData(); - } -} diff --git a/packages/idraw/src/mixins/file.ts b/packages/idraw/src/mixins/file.ts deleted file mode 100644 index b748f2d..0000000 --- a/packages/idraw/src/mixins/file.ts +++ /dev/null @@ -1,41 +0,0 @@ -import iDraw from './../index'; - -export async function exportDataURL( - idraw: iDraw, - type: 'image/png' | 'image/jpeg', - quality?: number -): Promise { - if (idraw.getTempData().get('isDownloading') === true) { - return Promise.reject('Busy!'); - } - - idraw.getTempData().set('isDownloading', true); - return new Promise((resolve, reject) => { - let dataURL = ''; - function listenRenderFrameComplete() { - idraw.off('drawFrameComplete', listenRenderFrameComplete); - idraw.getTempData().set('isDownloading', false); - const ctx = idraw.$getOriginContext2D(); - const canvas = ctx.canvas; - dataURL = canvas.toDataURL(type, quality); - resolve(dataURL); - } - try { - idraw.on('drawFrameComplete', listenRenderFrameComplete); - idraw.clearOperation(); - } catch (err) { - reject(err); - } - }); -} - -export function toDataURL( - idraw: iDraw, - type: 'image/png' | 'image/jpeg', - quality?: number -): string { - const ctx = idraw.$getOriginContext2D(); - const canvas = ctx.canvas; - const dataURL: string = canvas.toDataURL(type, quality); - return dataURL; -} diff --git a/packages/idraw/src/mixins/keyboard.ts b/packages/idraw/src/mixins/keyboard.ts deleted file mode 100644 index a7f2c3c..0000000 --- a/packages/idraw/src/mixins/keyboard.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { deepClone } from '@idraw/util'; -import { DataElement, DataElemDesc } from '@idraw/types'; -import iDraw from './../index'; - -export function copyElements(idraw: iDraw) { - if (idraw.getTempData().get('isFocus') !== true) { - return; - } - const elems = deepClone(idraw.getSelectedElements()); - idraw.getTempData().set('clipboardElements', elems); -} - -export function pasteElements(idraw: iDraw) { - if (idraw.getTempData().get('isFocus') !== true) { - return; - } - const elems = idraw.getTempData().get('clipboardElements'); - const moveRate = 0.1; - elems.forEach((elem) => { - elem.x += elem.w * moveRate; - elem.y += elem.w * moveRate; - idraw.addElement(elem); - }); - idraw.getTempData().set('clipboardElements', []); -} - -export function cutElements(idraw: iDraw) { - if (idraw.getTempData().get('isFocus') !== true) { - return; - } - const elems = deepClone(idraw.getSelectedElements()); - elems.forEach((elem: DataElement) => { - idraw.deleteElement(elem.uuid); - }); - idraw.getTempData().set('clipboardElements', elems); -} - -export function deleteElements(idraw: iDraw) { - if (idraw.getTempData().get('isFocus') !== true) { - return; - } - const elems = deepClone(idraw.getSelectedElements()); - elems.forEach((elem: DataElement) => { - idraw.deleteElement(elem.uuid); - }); -} - -const keyArrowMoveDistance = 4; - -export function keyArrowUp(idraw: iDraw) { - const elems = deepClone(idraw.getSelectedElements()); - if (elems.length > 0) { - elems.forEach((elem: DataElement) => { - elem.y -= keyArrowMoveDistance; - idraw.updateElement(elem); - }); - } else { - const { scrollTop } = idraw.getScreenTransform(); - idraw.scrollTop(scrollTop - keyArrowMoveDistance); - } -} - -export function keyArrowDown(idraw: iDraw) { - const elems = deepClone(idraw.getSelectedElements()); - if (elems.length > 0) { - elems.forEach((elem: DataElement) => { - elem.y += keyArrowMoveDistance; - idraw.updateElement(elem); - }); - } else { - const { scrollTop } = idraw.getScreenTransform(); - idraw.scrollTop(scrollTop + keyArrowMoveDistance); - } -} - -export function keyArrowLeft(idraw: iDraw) { - const elems = deepClone(idraw.getSelectedElements()); - if (elems.length > 0) { - elems.forEach((elem: DataElement) => { - elem.x -= keyArrowMoveDistance; - idraw.updateElement(elem); - }); - } else { - const { scrollLeft } = idraw.getScreenTransform(); - idraw.scrollLeft(scrollLeft - keyArrowMoveDistance); - } -} - -export function keyArrowRight(idraw: iDraw) { - const elems = deepClone(idraw.getSelectedElements()); - if (elems.length > 0) { - elems.forEach((elem: DataElement) => { - elem.x += keyArrowMoveDistance; - idraw.updateElement(elem); - }); - } else { - const { scrollLeft } = idraw.getScreenTransform(); - idraw.scrollLeft(scrollLeft + keyArrowMoveDistance); - } -} - -export function keyUndo(idraw: iDraw) { - idraw.undo(); -} diff --git a/packages/idraw/src/mixins/record.ts b/packages/idraw/src/mixins/record.ts deleted file mode 100644 index 926a8bb..0000000 --- a/packages/idraw/src/mixins/record.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { IDrawData } from '@idraw/types'; -import iDraw from './../index'; - -export function undo(idraw: iDraw): { - doRecordCount: number; - data: IDrawData | null; -} { - const doRecords = idraw.getTempData().get('doRecords'); - const unDoRecords = idraw.getTempData().get('unDoRecords'); - if (!(doRecords.length > 1)) { - return { - doRecordCount: doRecords.length, - data: null - }; - } - const popRecord = doRecords.pop(); - if (popRecord) { - unDoRecords.push(popRecord); - } - const record = doRecords[doRecords.length - 1]; - if (record?.data) { - idraw.setData(record.data); - } - idraw.getTempData().set('doRecords', doRecords); - idraw.getTempData().set('unDoRecords', unDoRecords); - return { - doRecordCount: doRecords.length, - data: record?.data || null - }; -} - -export function redo(idraw: iDraw): { - undoRecordCount: number; - data: IDrawData | null; -} { - const unDoRecords = idraw.getTempData().get('unDoRecords'); - if (!(unDoRecords.length > 0)) { - return { - undoRecordCount: unDoRecords.length, - data: null - }; - } - const record = unDoRecords.pop(); - if (record?.data) { - idraw.setData(record.data); - } - idraw.getTempData().set('unDoRecords', unDoRecords); - return { - undoRecordCount: unDoRecords.length, - data: record?.data || null - }; -} diff --git a/packages/idraw/src/types.ts b/packages/idraw/src/types.ts deleted file mode 100644 index 4105e6f..0000000 --- a/packages/idraw/src/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { IDrawData, CoreOptions } from '@idraw/types'; - -export type Options = { - maxRecords?: number; - disableKeyboard?: boolean; -} & CoreOptions; - -export type PrivateOptions = { - maxRecords: number; - disableKeyboard: boolean; -} & Options; - -export type Record = { - data: IDrawData; - time: number; -}; diff --git a/packages/renderer/src/constant/element.ts b/packages/renderer/src/constant/element.ts deleted file mode 100644 index b2bbcdb..0000000 --- a/packages/renderer/src/constant/element.ts +++ /dev/null @@ -1,15 +0,0 @@ - -const elementTypes = { - 'text': {}, // TODO - 'rect': {}, // TODO - 'image': {}, // TODO - 'svg': {}, // TODO - 'circle': {}, // TODO - 'html': {}, // TODO -}; - -export const elementNames = Object.keys(elementTypes); - - -// limitQbliqueAngle -export const LIMIT_QBLIQUE_ANGLE = 15; \ No newline at end of file diff --git a/packages/renderer/src/constant/static.ts b/packages/renderer/src/constant/static.ts deleted file mode 100644 index 80815e8..0000000 --- a/packages/renderer/src/constant/static.ts +++ /dev/null @@ -1,12 +0,0 @@ -export enum Mode { - NULL = 'null', - SELECT_ELEMENT = 'select-element', - SELECT_ELEMENT_LIST = 'select-element-list', - SELECT_ELEMENT_WRAPPER_CONTROLLER = 'select-element-wrapper-controller', - SELECT_AREA = 'select-area', -} - -export enum CursorStatus { - DRAGGING = 'dragging', - NULL = 'null', -} diff --git a/packages/renderer/src/draw/circle.ts b/packages/renderer/src/draw/circle.ts new file mode 100644 index 0000000..da87f2a --- /dev/null +++ b/packages/renderer/src/draw/circle.ts @@ -0,0 +1,31 @@ +import type { Element, RendererDrawElementOptions } from '@idraw/types'; + +export function drawCircle(ctx: CanvasRenderingContext2D, elem: Element<'circle'>, opts: RendererDrawElementOptions) { + const { desc } = elem; + const { bgColor = '#000000', borderColor = '#000000', borderWidth = 0 } = desc; + const { calculator, scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = opts; + const { x, y, w, h } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h }, { scale, offsetTop, offsetBottom, offsetLeft, offsetRight }); + const a = w / 2; + const b = h / 2; + const centerX = x + a; + const centerY = y + b; + + // draw border + if (borderWidth && borderWidth > 0) { + const ba = borderWidth / 2 + a; + const bb = borderWidth / 2 + b; + ctx.beginPath(); + ctx.strokeStyle = borderColor; + ctx.lineWidth = borderWidth; + ctx.ellipse(centerX, centerY, ba, bb, 0, 0, 2 * Math.PI); + ctx.closePath(); + ctx.stroke(); + } + + // draw content + ctx.beginPath(); + ctx.fillStyle = bgColor; + ctx.ellipse(centerX, centerY, a, b, 0, 0, 2 * Math.PI); + ctx.closePath(); + ctx.fill(); +} diff --git a/packages/renderer/src/draw/elements.ts b/packages/renderer/src/draw/elements.ts new file mode 100644 index 0000000..a1427d1 --- /dev/null +++ b/packages/renderer/src/draw/elements.ts @@ -0,0 +1,42 @@ +import type { Element, ElementType, Data, RendererDrawElementOptions } from '@idraw/types'; +import { drawCircle } from './circle'; +import { drawRect } from './rect'; +import { drawImage } from './image'; + +export function drawElement(ctx: CanvasRenderingContext2D, elem: Element, opts: RendererDrawElementOptions) { + try { + switch (elem.type) { + case 'rect': { + drawRect(ctx, elem as Element<'rect'>, opts); + break; + } + case 'circle': { + drawCircle(ctx, elem as Element<'circle'>, opts); + break; + } + case 'image': { + drawImage(ctx, elem as Element<'image'>, opts); + break; + } + default: { + break; + } + } + } catch (err) { + console.error(err); + } +} + +export function drawElementList(ctx: CanvasRenderingContext2D, elements: Data['elements'], opts: RendererDrawElementOptions) { + for (let i = elements.length - 1; i >= 0; i--) { + const elem = elements[i]; + if (!opts.calculator.isElementInView(elem, opts)) { + continue; + } + try { + drawElement(ctx, elem, opts); + } catch (err) { + console.error(err); + } + } +} diff --git a/packages/renderer/src/draw/image.ts b/packages/renderer/src/draw/image.ts new file mode 100644 index 0000000..26b2ae0 --- /dev/null +++ b/packages/renderer/src/draw/image.ts @@ -0,0 +1,14 @@ +import type { Element, RendererDrawElementOptions } from '@idraw/types'; + +export function drawImage(ctx: CanvasRenderingContext2D, elem: Element<'image'>, opts: RendererDrawElementOptions) { + const content = opts.loader.getContent(elem.uuid); + const { calculator, scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = opts; + const { x, y, w, h } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h }, { scale, offsetTop, offsetBottom, offsetLeft, offsetRight }); + + if (!content) { + opts.loader.load(elem as Element<'image'>); + } + if (elem.type === 'image' && content) { + ctx.drawImage(content, x, y, w, h); + } +} diff --git a/packages/renderer/src/draw/index.ts b/packages/renderer/src/draw/index.ts new file mode 100644 index 0000000..db3b81b --- /dev/null +++ b/packages/renderer/src/draw/index.ts @@ -0,0 +1,4 @@ +export { drawCircle } from './circle'; +export { drawRect } from './rect'; +export { drawImage } from './image'; +export { drawElementList, drawElement } from './elements'; diff --git a/packages/renderer/src/draw/rect.ts b/packages/renderer/src/draw/rect.ts new file mode 100644 index 0000000..ef30825 --- /dev/null +++ b/packages/renderer/src/draw/rect.ts @@ -0,0 +1,22 @@ +import type { Element, RendererDrawElementOptions } from '@idraw/types'; + +export function drawRect(ctx: CanvasRenderingContext2D, elem: Element<'rect'>, opts: RendererDrawElementOptions) { + // const { desc } = elem; + const { calculator, scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = opts; + const { x, y, w, h } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h }, { scale, offsetTop, offsetBottom, offsetLeft, offsetRight }); + + let r: number = (elem.desc.borderRadius || 0) * scale; + r = Math.min(r, w / 2, h / 2); + if (w < r * 2 || h < r * 2) { + r = 0; + } + ctx.beginPath(); + ctx.moveTo(x + r, y); + ctx.arcTo(x + w, y, x + w, y + h, r); + ctx.arcTo(x + w, y + h, x, y + h, r); + ctx.arcTo(x, y + h, x, y, r); + ctx.arcTo(x, y, x + w, y, r); + ctx.closePath(); + ctx.fillStyle = elem.desc.bgColor || '#000000'; + ctx.fill(); +} diff --git a/packages/renderer/src/index.ts b/packages/renderer/src/index.ts index fcea7d2..f8c7f6d 100644 --- a/packages/renderer/src/index.ts +++ b/packages/renderer/src/index.ts @@ -1,192 +1,77 @@ -import { - IDrawData, - IDrawContext, - DataElement, - DataElemDesc -} from '@idraw/types'; -import { createUUID, deepClone, Context } from '@idraw/util'; -import { drawContext } from './lib/draw'; -import { TypeLoadDataItem } from './lib/loader-event'; -import Loader from './lib/loader'; -import { RendererEvent } from './lib/renderer-event'; +import { EventEmitter, createOffscreenContext2D } from '@idraw/util'; +import { drawElementList } from './draw'; +import { Loader } from './loader'; +import type { Data, BoardRenderer, RendererOptions, RendererEventMap, RendererDrawOptions } from '@idraw/types'; -const { requestAnimationFrame } = window; +export class Renderer extends EventEmitter implements BoardRenderer { + private _opts: RendererOptions; + private _loader: Loader = new Loader(); + private _draftContextTop: CanvasRenderingContext2D; + private _draftContextMiddle: CanvasRenderingContext2D; + private _draftContextBottom: CanvasRenderingContext2D; -type QueueItem = { data: IDrawData }; -enum DrawStatus { - NULL = 'null', - FREE = 'free', - DRAWING = 'drawing', - FREEZE = 'freeze' - // STOP = 'stop', -} - -type Options = { - width: number; - height: number; - contextWidth?: number; - contextHeight?: number; - devicePixelRatio: number; -}; - -export default class Renderer extends RendererEvent { - private _queue: QueueItem[] = []; - private _ctx: IDrawContext | null = null; - private _status: DrawStatus = DrawStatus.NULL; - private _loader: Loader; - private _opts?: Options; - - constructor(opts?: Options) { + constructor(opts: RendererOptions) { super(); this._opts = opts; - this._loader = new Loader({ - maxParallelNum: 6 + const { width, height } = this._opts.viewContent.viewContext.canvas; + this._draftContextTop = createOffscreenContext2D({ width, height }) as CanvasRenderingContext2D; + this._draftContextMiddle = createOffscreenContext2D({ width, height }) as CanvasRenderingContext2D; + this._draftContextBottom = createOffscreenContext2D({ width, height }) as CanvasRenderingContext2D; + + this._init(); + } + + private _init() { + const { _loader: loader } = this; + loader.on('load', (e) => { + this.trigger('load', e); }); - this._loader.on('load', (res: TypeLoadDataItem) => { - this._drawFrame(); - this.trigger('load', { element: res.element }); - }); - this._loader.on('error', (res: TypeLoadDataItem) => { - this.trigger('error', { element: res.element, error: res.error }); - }); - this._loader.on('complete', () => { - this.trigger('loadComplete', { t: Date.now() }); + loader.on('error', () => { + // TODO }); } - render( - target: HTMLCanvasElement | IDrawContext, - originData: IDrawData, - opts?: { - // forceUpdate?: boolean, - changeResourceUUIDs?: string[]; - } - ): void { - // if ([DrawStatus.STOP, DrawStatus.FREEZE].includes(this._status)) { - // return; - // } - // this._status = DrawStatus.FREE; + updateOptions(opts: RendererOptions) { + this._opts = opts; + } - const { changeResourceUUIDs = [] } = opts || {}; - this._status = DrawStatus.FREE; + drawData(data: Data, opts: RendererDrawOptions) { + const { _loader: loader } = this; + const { calculator } = this._opts; + const { viewContext } = this._opts.viewContent; + viewContext.clearRect(0, 0, viewContext.canvas.width, viewContext.canvas.height); + drawElementList(viewContext, data.elements, { loader, calculator, ...opts }); + } - const data = deepClone(originData); - if (Array.isArray(data.elements)) { - data.elements.forEach((elem: DataElement) => { - if (!(typeof elem.uuid === 'string' && elem.uuid)) { - elem.uuid = createUUID(); - } + scale(num: number) { + const { sharer } = this._opts; + const { data, offsetTop, offsetBottom, offsetLeft, offsetRight } = sharer.getActiveStoreSnapshot(); + // TODO calc offset data + if (data) { + this.drawData(data, { + scale: num, + offsetTop, + offsetBottom, + offsetLeft, + offsetRight }); } + sharer.setActiveStorage('scale', num); + } - if (!this._ctx) { - // TODO - if ( - this._opts && - Object.prototype.toString.call(target) === '[object HTMLCanvasElement]' - ) { - const { width, height, contextWidth, contextHeight, devicePixelRatio } = - this._opts as Options; - const canvas = target as HTMLCanvasElement; - canvas.width = width * devicePixelRatio; - canvas.height = height * devicePixelRatio; - const ctx2d = canvas.getContext('2d') as CanvasRenderingContext2D; - this._ctx = new Context(ctx2d, { - width, - height, - contextWidth: contextWidth || width, - contextHeight: contextHeight || height, - devicePixelRatio - }); - } else if (target) { - // TODO - this._ctx = target as IDrawContext; - } + scroll(opts: { offsetTop?: number; offsetLeft?: number }) { + const { sharer } = this._opts; + const { data, scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = sharer.getActiveStoreSnapshot(); + // TODO calc offset data + if (data) { + this.drawData(data, { + scale, + offsetTop, + offsetBottom, + offsetLeft, + offsetRight + }); } - - if ([DrawStatus.FREEZE].includes(this._status)) { - return; - } - const _data: QueueItem = deepClone({ data }) as QueueItem; - this._queue.push(_data); - // if (this._status !== DrawStatus.DRAWING) { - // this._status = DrawStatus.DRAWING; - // this._drawFrame(); - // } - this._drawFrame(); - this._loader.load(data, changeResourceUUIDs || []); - } - - getContext(): IDrawContext | null { - return this._ctx; - } - - thaw() { - this._status = DrawStatus.FREE; - } - - private _freeze() { - this._status = DrawStatus.FREEZE; - } - - private _drawFrame() { - if (this._status === DrawStatus.FREEZE) { - return; - } - requestAnimationFrame(() => { - if (this._status === DrawStatus.FREEZE) { - return; - } - const ctx = this._ctx; - - let item: QueueItem | undefined = this._queue[0]; - let isLastFrame = false; - if (this._queue.length > 1) { - item = this._queue.shift(); - } else { - isLastFrame = true; - } - if (this._loader.isComplete() !== true) { - this._drawFrame(); - if (item && ctx) { - drawContext(ctx, item.data, this._loader); - // this._board.draw(); - // this.trigger('drawFrame', { t: Date.now() }) - } - } else if (item && ctx) { - drawContext(ctx, item.data, this._loader); - // this._board.draw(); - // this.trigger('drawFrame', { t: Date.now() }) - this._retainQueueOneItem(); - if (!isLastFrame) { - this._drawFrame(); - } else { - this._status = DrawStatus.FREE; - } - } else { - this._status = DrawStatus.FREE; - } - this.trigger('drawFrame', { t: Date.now() }); - - if ( - this._loader.isComplete() === true && - this._queue.length === 1 && - this._status === DrawStatus.FREE - ) { - if (ctx && this._queue[0] && this._queue[0].data) { - drawContext(ctx, this._queue[0].data, this._loader); - } - this.trigger('drawFrameComplete', { t: Date.now() }); - this._freeze(); - } - }); - } - - private _retainQueueOneItem() { - if (this._queue.length <= 1) { - return; - } - const lastOne = deepClone(this._queue[this._queue.length - 1]); - this._queue = [lastOne]; + // sharer.setActiveStorage('scale', num); } } diff --git a/packages/renderer/src/lib/calculate.ts b/packages/renderer/src/lib/calculate.ts deleted file mode 100644 index 14c8bc4..0000000 --- a/packages/renderer/src/lib/calculate.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { DataElement, DataElemDesc, Point } from '@idraw/types'; - -export function parseRadianToAngle(radian: number): number { - return (radian / Math.PI) * 180; -} - -export function parseAngleToRadian(angle: number): number { - return (angle / 180) * Math.PI; -} - -export function calcElementCenter( - elem: DataElement -): Point { - const p = { - x: elem.x + elem.w / 2, - y: elem.y + elem.h / 2 - }; - return p; -} - -export function calcRadian(center: Point, start: Point, end: Point): number { - const startAngle = calcLineAngle(center, start); - const endAngle = calcLineAngle(center, end); - if (endAngle !== null && startAngle !== null) { - if (startAngle > (Math.PI * 3) / 2 && endAngle < Math.PI / 2) { - return endAngle + (Math.PI * 2 - startAngle); - } else if (endAngle > (Math.PI * 3) / 2 && startAngle < Math.PI / 2) { - return startAngle + (Math.PI * 2 - endAngle); - } else { - return endAngle - startAngle; - } - } else { - return 0; - } -} - -function calcLineAngle(center: Point, p: Point): number | null { - const x = p.x - center.x; - const y = center.y - p.y; - if (x === 0) { - if (y < 0) { - return Math.PI / 2; - } else if (y > 0) { - return Math.PI * (3 / 2); - } - } else if (y === 0) { - if (x < 0) { - return Math.PI; - } else if (x > 0) { - return 0; - } - } - if (x > 0 && y < 0) { - return Math.atan(Math.abs(y) / Math.abs(x)); - } else if (x < 0 && y < 0) { - return Math.PI - Math.atan(Math.abs(y) / Math.abs(x)); - } else if (x < 0 && y > 0) { - return Math.PI + Math.atan(Math.abs(y) / Math.abs(x)); - } else if (x > 0 && y > 0) { - return Math.PI * 2 - Math.atan(Math.abs(y) / Math.abs(x)); - } - return null; -} diff --git a/packages/renderer/src/lib/diff.ts b/packages/renderer/src/lib/diff.ts deleted file mode 100644 index c84ced1..0000000 --- a/packages/renderer/src/lib/diff.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { DataElement, IDrawData, DataElemDesc } from '@idraw/types'; - -type DataElementMap = { - [uuid: string]: DataElement; -}; - -export function isChangeImageElementResource( - before: DataElement<'image'>, - after: DataElement<'image'> -): boolean { - return before?.desc?.src !== after?.desc?.src; -} - -export function isChangeSVGElementResource( - before: DataElement<'svg'>, - after: DataElement<'svg'> -): boolean { - return before?.desc?.svg !== after?.desc?.svg; -} - -export function isChangeHTMLElementResource( - before: DataElement<'html'>, - after: DataElement<'html'> -): boolean { - return ( - before?.desc?.html !== after?.desc?.html || - before?.desc?.width !== after?.desc?.width || - before?.desc?.height !== after?.desc?.height - ); -} - -export function diffElementResourceChange( - before: DataElement, - after: DataElement -): string | null { - let result = null; - let isChange = false; - switch (after.type) { - case 'image': { - isChange = isChangeImageElementResource( - before as DataElement<'image'>, - after as DataElement<'image'> - ); - break; - } - case 'svg': { - isChange = isChangeSVGElementResource( - before as DataElement<'svg'>, - after as DataElement<'svg'> - ); - break; - } - case 'html': { - isChange = isChangeHTMLElementResource( - before as DataElement<'html'>, - after as DataElement<'html'> - ); - break; - } - default: - break; - } - if (isChange === true) { - result = after.uuid; - } - return result; -} - -export function diffElementResourceChangeList( - before: IDrawData, - after: IDrawData -): string[] { - const uuids: string[] = []; - const beforeMap = parseDataElementMap(before); - const afterMap = parseDataElementMap(after); - for (const uuid in afterMap) { - if (['image', 'svg', 'html'].includes(afterMap[uuid]?.type) !== true) { - continue; - } - if (beforeMap[uuid]) { - let isChange = false; - switch (beforeMap[uuid].type) { - case 'image': { - isChange = isChangeImageElementResource( - beforeMap[uuid] as DataElement<'image'>, - afterMap[uuid] as DataElement<'image'> - ); - break; - } - case 'svg': { - isChange = isChangeSVGElementResource( - beforeMap[uuid] as DataElement<'svg'>, - afterMap[uuid] as DataElement<'svg'> - ); - break; - } - case 'html': { - isChange = isChangeHTMLElementResource( - beforeMap[uuid] as DataElement<'html'>, - afterMap[uuid] as DataElement<'html'> - ); - break; - } - default: - break; - } - if (isChange === true) { - uuids.push(uuid); - } - } else { - uuids.push(uuid); - } - } - return uuids; -} - -function parseDataElementMap(data: IDrawData): DataElementMap { - const elemMap: DataElementMap = {}; - data.elements.forEach((elem) => { - elemMap[elem.uuid] = elem; - }); - return elemMap; -} diff --git a/packages/renderer/src/lib/draw/base.ts b/packages/renderer/src/lib/draw/base.ts deleted file mode 100644 index 877aa02..0000000 --- a/packages/renderer/src/lib/draw/base.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { - IDrawContext, - // DataElemDesc, - DataElement -} from '@idraw/types'; -import { is, istype, isColorStr } from '@idraw/util'; -import { rotateElement } from './../transform'; - -export function clearContext(ctx: IDrawContext) { - // ctx.setFillStyle('rgb(0 0 0 / 100%)'); - // ctx.setStrokeStyle('rgb(0 0 0 / 100%)'); - ctx.setFillStyle('#000000'); - ctx.setStrokeStyle('#000000'); - ctx.setLineDash([]); - ctx.setGlobalAlpha(1); - ctx.setShadowColor('#00000000'); - ctx.setShadowOffsetX(0); - ctx.setShadowOffsetY(0); - ctx.setShadowBlur(0); -} - -export function drawBgColor(ctx: IDrawContext, color: string) { - const size = ctx.getSize(); - ctx.setFillStyle(color); - ctx.fillRect(0, 0, size.contextWidth, size.contextHeight); -} - -export function drawBox( - ctx: IDrawContext, - elem: DataElement<'text' | 'rect'>, - pattern: string | CanvasPattern | null -): void { - clearContext(ctx); - drawBoxBorder(ctx, elem); - clearContext(ctx); - rotateElement(ctx, elem, () => { - const { x, y, w, h } = elem; - let r: number = elem.desc.borderRadius || 0; - r = Math.min(r, w / 2, h / 2); - if (w < r * 2 || h < r * 2) { - r = 0; - } - ctx.beginPath(); - ctx.moveTo(x + r, y); - ctx.arcTo(x + w, y, x + w, y + h, r); - ctx.arcTo(x + w, y + h, x, y + h, r); - ctx.arcTo(x, y + h, x, y, r); - ctx.arcTo(x, y, x + w, y, r); - ctx.closePath(); - if (typeof pattern === 'string') { - ctx.setFillStyle(pattern); - } else if (['CanvasPattern'].includes(istype.type(pattern))) { - ctx.setFillStyle(pattern as CanvasPattern); - } - ctx.fill(); - }); -} - -export function drawBoxBorder( - ctx: IDrawContext, - elem: DataElement<'text' | 'rect'> -): void { - clearContext(ctx); - rotateElement(ctx, elem, () => { - if (!(elem.desc.borderWidth && elem.desc.borderWidth > 0)) { - return; - } - const bw = elem.desc.borderWidth; - let borderColor = '#000000'; - if (isColorStr(elem.desc.borderColor) === true) { - borderColor = elem.desc.borderColor as string; - } - const x = elem.x - bw / 2; - const y = elem.y - bw / 2; - const w = elem.w + bw; - const h = elem.h + bw; - - let r: number = elem.desc.borderRadius || 0; - r = Math.min(r, w / 2, h / 2); - if (r < w / 2 && r < h / 2) { - r = r + bw / 2; - } - const { desc } = elem; - if (desc.shadowColor !== undefined && isColorStr(desc.shadowColor)) { - ctx.setShadowColor(desc.shadowColor); - } - if (desc.shadowOffsetX !== undefined && is.number(desc.shadowOffsetX)) { - ctx.setShadowOffsetX(desc.shadowOffsetX); - } - if (desc.shadowOffsetY !== undefined && is.number(desc.shadowOffsetY)) { - ctx.setShadowOffsetY(desc.shadowOffsetY); - } - if (desc.shadowBlur !== undefined && is.number(desc.shadowBlur)) { - ctx.setShadowBlur(desc.shadowBlur); - } - ctx.beginPath(); - ctx.setLineWidth(bw); - ctx.setStrokeStyle(borderColor); - ctx.moveTo(x + r, y); - ctx.arcTo(x + w, y, x + w, y + h, r); - ctx.arcTo(x + w, y + h, x, y + h, r); - ctx.arcTo(x, y + h, x, y, r); - ctx.arcTo(x, y, x + w, y, r); - ctx.closePath(); - ctx.stroke(); - }); -} diff --git a/packages/renderer/src/lib/draw/circle.ts b/packages/renderer/src/lib/draw/circle.ts deleted file mode 100644 index f5830f9..0000000 --- a/packages/renderer/src/lib/draw/circle.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { IDrawContext, DataElement } from '@idraw/types'; -import { rotateElement } from './../transform'; -import { clearContext } from './base'; - -export function drawCircle(ctx: IDrawContext, elem: DataElement<'circle'>) { - clearContext(ctx); - rotateElement(ctx, elem, (ctx) => { - const { x, y, w, h, desc } = elem; - const { - bgColor = '#000000', - borderColor = '#000000', - borderWidth = 0 - } = desc; - - const a = w / 2; - const b = h / 2; - const centerX = x + a; - const centerY = y + b; - - // draw border - if (borderWidth && borderWidth > 0) { - const ba = borderWidth / 2 + a; - const bb = borderWidth / 2 + b; - ctx.beginPath(); - ctx.setStrokeStyle(borderColor); - ctx.setLineWidth(borderWidth); - ctx.ellipse(centerX, centerY, ba, bb, 0, 0, 2 * Math.PI); - - ctx.closePath(); - ctx.stroke(); - } - - // draw content - ctx.beginPath(); - ctx.setFillStyle(bgColor); - ctx.ellipse(centerX, centerY, a, b, 0, 0, 2 * Math.PI); - ctx.closePath(); - ctx.fill(); - - // // draw shadow - // clearContext(ctx); - // if ((desc.shadowOffsetX !== undefined && is.number(desc.shadowOffsetX)) || desc.shadowOffsetY !== undefined && is.number(desc.shadowOffsetY)) { - - // if (desc.shadowColor !== undefined && util.color.isColorStr(desc.shadowColor)) { - // ctx.setShadowColor(desc.shadowColor); - // } - // if (desc.shadowOffsetX !== undefined && is.number(desc.shadowOffsetX)) { - // ctx.setShadowOffsetX(desc.shadowOffsetX); - // } - // if (desc.shadowOffsetY !== undefined && is.number(desc.shadowOffsetY)) { - // ctx.setShadowOffsetY(desc.shadowOffsetY); - // } - // if (desc.shadowBlur !== undefined && is.number(desc.shadowBlur)) { - // ctx.setShadowBlur(desc.shadowBlur); - // } - - // const a = (w + borderWidth * 2) / 2; - // const b = (h + borderWidth * 2) / 2; - // const centerX = x + a - borderWidth; - // const centerY = y + b - borderWidth; - // const unit = (a > b) ? 1 / a : 1 / b; - - // ctx.beginPath(); - // ctx.setFillStyle('#ffffff6a'); - // ctx.moveTo(centerX + a, centerY); - // for(var i = 0; i < 2 * Math.PI; i += unit) { - // ctx.lineTo(centerX + a * Math.cos(i), centerY + b * Math.sin(i)); - // } - // ctx.closePath(); - // ctx.fill(); - // } - }); -} diff --git a/packages/renderer/src/lib/draw/html.ts b/packages/renderer/src/lib/draw/html.ts deleted file mode 100644 index e69533c..0000000 --- a/packages/renderer/src/lib/draw/html.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { IDrawContext, DataElement } from '@idraw/types'; -import { rotateElement } from '../transform'; -import Loader from '../loader'; - -export function drawHTML( - ctx: IDrawContext, - elem: DataElement<'html'>, - loader: Loader -) { - const content = loader.getContent(elem.uuid); - rotateElement(ctx, elem, () => { - if (content) { - ctx.drawImage(content, elem.x, elem.y, elem.w, elem.h); - } - }); -} diff --git a/packages/renderer/src/lib/draw/image.ts b/packages/renderer/src/lib/draw/image.ts deleted file mode 100644 index aec9682..0000000 --- a/packages/renderer/src/lib/draw/image.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { IDrawContext, DataElement } from '@idraw/types'; -import { rotateElement } from '../transform'; -import Loader from '../loader'; - -export function drawImage( - ctx: IDrawContext, - elem: DataElement<'image'>, - loader: Loader -) { - // const desc = elem.desc as DataElemDesc['rect']; - const content = loader.getContent(elem.uuid); - rotateElement(ctx, elem, () => { - // ctx.setFillStyle(desc.color); - // ctx.fillRect(elem.x, elem.y, elem.w, elem.h); - if (content) { - // ctx.drawImage(content, 0, 0, elem.w, elem.h, elem.x, elem.y, elem.w, elem.h); - ctx.drawImage(content, elem.x, elem.y, elem.w, elem.h); - } - }); -} - -// import { -// IDrawContext, -// DataElement, -// HelperConfig, -// DataElemDesc, -// } from '@idraw/types'; -// import Loader from '../loader'; -// import { drawBox } from './base'; - -// export function drawImage( -// ctx: IDrawContext, -// elem: DataElement<'image'>, -// loader: Loader, -// helperConfig: HelperConfig -// ) { -// const content = loader.getPattern(elem, { -// forceUpdate: helperConfig?.selectedElementWrapper?.uuid === elem.uuid -// }); -// drawBox(ctx, elem, content); -// } diff --git a/packages/renderer/src/lib/draw/index.ts b/packages/renderer/src/lib/draw/index.ts deleted file mode 100644 index 571d219..0000000 --- a/packages/renderer/src/lib/draw/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { - IDrawContext, - IDrawData, - DataElement - // Point, -} from '@idraw/types'; -import { isColorStr } from '@idraw/util'; -import Loader from '../loader'; -import { clearContext, drawBgColor } from './base'; -import { drawRect } from './rect'; -import { drawImage } from './image'; -import { drawSVG } from './svg'; -import { drawHTML } from './html'; -import { drawText } from './text'; -import { drawCircle } from './circle'; - -export function drawContext( - ctx: IDrawContext, - data: IDrawData, - loader: Loader -): void { - clearContext(ctx); - const size = ctx.getSize(); - ctx.clearRect(0, 0, size.contextWidth, size.contextHeight); - - if (typeof data.bgColor === 'string' && isColorStr(data.bgColor)) { - drawBgColor(ctx, data.bgColor); - } - - if (!(data.elements.length > 0)) { - return; - } - for (let i = 0; i < data.elements.length; i++) { - const elem = data.elements[i]; - if (elem?.operation?.invisible === true) { - continue; - } - switch (elem.type) { - case 'rect': { - drawRect(ctx, elem as DataElement<'rect'>); - break; - } - case 'text': { - drawText(ctx, elem as DataElement<'text'>, loader); - break; - } - case 'image': { - drawImage(ctx, elem as DataElement<'image'>, loader); - break; - } - case 'svg': { - drawSVG(ctx, elem as DataElement<'svg'>, loader); - break; - } - case 'html': { - drawHTML(ctx, elem as DataElement<'html'>, loader); - break; - } - case 'circle': { - drawCircle(ctx, elem as DataElement<'circle'>); - break; - } - default: { - // nothing - break; - } - } - } -} diff --git a/packages/renderer/src/lib/draw/rect.ts b/packages/renderer/src/lib/draw/rect.ts deleted file mode 100644 index 0d3f98d..0000000 --- a/packages/renderer/src/lib/draw/rect.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IDrawContext, DataElement } from '@idraw/types'; -import { drawBox } from './base'; - -export function drawRect(ctx: IDrawContext, elem: DataElement<'rect'>) { - drawBox(ctx, elem, elem.desc.bgColor as string); -} diff --git a/packages/renderer/src/lib/draw/svg.ts b/packages/renderer/src/lib/draw/svg.ts deleted file mode 100644 index 406bb39..0000000 --- a/packages/renderer/src/lib/draw/svg.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IDrawContext, DataElement } from '@idraw/types'; -import { rotateElement } from '../transform'; -import Loader from '../loader'; - -export function drawSVG( - ctx: IDrawContext, - elem: DataElement<'svg'>, - loader: Loader -) { - // const desc = elem.desc as DataElemDesc['rect']; - const content = loader.getContent(elem.uuid); - rotateElement(ctx, elem, () => { - // ctx.setFillStyle(desc.color); - // ctx.fillRect(elem.x, elem.y, elem.w, elem.h); - if (content) { - // ctx.drawImage(content, 0, 0, elem.w, elem.h, elem.x, elem.y, elem.w, elem.h); - ctx.drawImage(content, elem.x, elem.y, elem.w, elem.h); - } - }); -} - -// import { -// IDrawContext, -// DataElement, -// HelperConfig, -// } from '@idraw/types'; -// import Loader from '../loader'; -// import { drawBox } from './base'; - -// export function drawSVG( -// ctx: IDrawContext, -// elem: DataElement<'svg'>, -// loader: Loader, -// helperConfig: HelperConfig -// ) { -// const content = loader.getPattern(elem, { -// forceUpdate: helperConfig?.selectedElementWrapper?.uuid === elem.uuid -// }); -// drawBox(ctx, elem, content); -// } diff --git a/packages/renderer/src/lib/draw/text.ts b/packages/renderer/src/lib/draw/text.ts deleted file mode 100644 index b9e9f7e..0000000 --- a/packages/renderer/src/lib/draw/text.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { IDrawContext, DataElemDescText, DataElement } from '@idraw/types'; -import { is, isColorStr } from '@idraw/util'; -import Loader from '../loader'; -import { clearContext, drawBox } from './base'; -import { rotateElement } from './../transform'; - -export function drawText( - ctx: IDrawContext, - elem: DataElement<'text'>, - loader: Loader -) { - clearContext(ctx); - drawBox(ctx, elem, elem.desc.bgColor || 'transparent'); - rotateElement(ctx, elem, () => { - const desc: DataElemDescText = { - ...{ - fontSize: 12, - fontFamily: 'sans-serif', - textAlign: 'center' - }, - ...elem.desc - }; - ctx.setFillStyle(elem.desc.color); - ctx.setTextBaseline('top'); - ctx.setFont({ - fontWeight: desc.fontWeight, - fontSize: desc.fontSize, - fontFamily: desc.fontFamily - }); - const descText = desc.text.replace(/\r\n/gi, '\n'); - const fontHeight = desc.lineHeight || desc.fontSize; - const descTextList = descText.split('\n'); - const lines: { text: string; width: number }[] = []; - - let lineNum = 0; - descTextList.forEach((tempText: string, idx: number) => { - let lineText = ''; - - if (tempText.length > 0) { - for (let i = 0; i < tempText.length; i++) { - if ( - ctx.measureText(lineText + (tempText[i] || '')).width < - ctx.calcDeviceNum(elem.w) - ) { - lineText += tempText[i] || ''; - } else { - lines.push({ - text: lineText, - width: ctx.calcScreenNum(ctx.measureText(lineText).width) - }); - lineText = tempText[i] || ''; - lineNum++; - } - if ((lineNum + 1) * fontHeight > elem.h) { - break; - } - if (tempText.length - 1 === i) { - if ((lineNum + 1) * fontHeight < elem.h) { - lines.push({ - text: lineText, - width: ctx.calcScreenNum(ctx.measureText(lineText).width) - }); - if (idx < descTextList.length - 1) { - lineNum++; - } - break; - } - } - } - } else { - lines.push({ - text: '', - width: 0 - }); - } - }); - - let startY = 0; - if (lines.length * fontHeight < elem.h) { - if (elem.desc.verticalAlign === 'top') { - startY = 0; - } else if (elem.desc.verticalAlign === 'bottom') { - startY += elem.h - lines.length * fontHeight; - } else { - // middle and default - startY += (elem.h - lines.length * fontHeight) / 2; - } - } - - // draw text lines - { - const _y = elem.y + startY; - if ( - desc.textShadowColor !== undefined && - isColorStr(desc.textShadowColor) - ) { - ctx.setShadowColor(desc.textShadowColor); - } - if ( - desc.textShadowOffsetX !== undefined && - is.number(desc.textShadowOffsetX) - ) { - ctx.setShadowOffsetX(desc.textShadowOffsetX); - } - if ( - desc.textShadowOffsetY !== undefined && - is.number(desc.textShadowOffsetY) - ) { - ctx.setShadowOffsetY(desc.textShadowOffsetY); - } - if (desc.textShadowBlur !== undefined && is.number(desc.textShadowBlur)) { - ctx.setShadowBlur(desc.textShadowBlur); - } - lines.forEach((line, i) => { - let _x = elem.x; - if (desc.textAlign === 'center') { - _x = elem.x + (elem.w - line.width) / 2; - } else if (desc.textAlign === 'right') { - _x = elem.x + (elem.w - line.width); - } - ctx.fillText(line.text, _x, _y + fontHeight * i); - }); - clearContext(ctx); - } - - // draw text stroke - if ( - isColorStr(desc.strokeColor) && - desc.strokeWidth !== undefined && - desc.strokeWidth > 0 - ) { - const _y = elem.y + startY; - lines.forEach((line, i) => { - let _x = elem.x; - if (desc.textAlign === 'center') { - _x = elem.x + (elem.w - line.width) / 2; - } else if (desc.textAlign === 'right') { - _x = elem.x + (elem.w - line.width); - } - if (desc.strokeColor !== undefined) { - ctx.setStrokeStyle(desc.strokeColor); - } - if (desc.strokeWidth !== undefined && desc.strokeWidth > 0) { - ctx.setLineWidth(desc.strokeWidth); - } - ctx.strokeText(line.text, _x, _y + fontHeight * i); - }); - } - }); -} - -// export function createTextSVG(elem: DataElement<'text'>): string { -// const svg = ` -// -// -//
    -// ${elem.desc.text || ''} -//
    -//
    -//
    -// `; -// return svg; -// } diff --git a/packages/renderer/src/lib/index.ts b/packages/renderer/src/lib/index.ts deleted file mode 100644 index 4745827..0000000 --- a/packages/renderer/src/lib/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './diff'; -export * from './loader-event'; -export * from './loader'; -export * from './parse'; -export * from './temp'; -export * from './value'; diff --git a/packages/renderer/src/lib/loader-event.ts b/packages/renderer/src/lib/loader-event.ts deleted file mode 100644 index 01d6325..0000000 --- a/packages/renderer/src/lib/loader-event.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { DataElement, DataElemDesc } from '@idraw/types'; - -export type TypeLoadDataItem = { - uuid: string; - type: 'image' | 'svg' | 'html'; - status: 'null' | 'loaded' | 'fail'; - content: null | HTMLImageElement | HTMLCanvasElement; - elemW: number; - elemH: number; - source: string; - element: DataElement; - error?: any; -}; - -export type TypeLoadData = { - [uuid: string]: TypeLoadDataItem; -}; - -export type TypeLoaderEventArgMap = { - complete: void; - load: TypeLoadData[string]; - error: TypeLoadData[string]; -}; - -export interface TypeLoaderEvent { - on( - key: T, - callback: (p: TypeLoaderEventArgMap[T]) => void - ): void; - off( - key: T, - callback: (p: TypeLoaderEventArgMap[T]) => void - ): void; - trigger( - key: T, - p: TypeLoaderEventArgMap[T] - ): void; -} - -export class LoaderEvent implements TypeLoaderEvent { - private _listeners: Map void)[]>; - - constructor() { - this._listeners = new Map(); - } - - on( - eventKey: T, - callback: (p: TypeLoaderEventArgMap[T]) => void - ) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - callbacks?.push(callback); - this._listeners.set(eventKey, callbacks || []); - } else { - this._listeners.set(eventKey, [callback]); - } - } - - off( - eventKey: T, - callback: (p: TypeLoaderEventArgMap[T]) => void - ) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - for (let i = 0; i < callbacks?.length; i++) { - if (callbacks[i] === callback) { - callbacks.splice(i, 1); - break; - } - } - } - this._listeners.set(eventKey, callbacks || []); - } - } - - trigger( - eventKey: T, - arg: TypeLoaderEventArgMap[T] - ) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - callbacks.forEach((cb) => { - cb(arg); - }); - return true; - } else { - return false; - } - } - - has(name: string) { - if (this._listeners.has(name)) { - const list: ((p: TypeLoaderEventArgMap[T]) => void)[] | undefined = - this._listeners.get(name); - if (Array.isArray(list) && list.length > 0) { - return true; - } - } - return false; - } -} diff --git a/packages/renderer/src/lib/loader.ts b/packages/renderer/src/lib/loader.ts deleted file mode 100644 index 8b4ffab..0000000 --- a/packages/renderer/src/lib/loader.ts +++ /dev/null @@ -1,347 +0,0 @@ -import { IDrawData, DataElement } from '@idraw/types'; -import { loadImage, loadSVG, loadHTML, deepClone } from '@idraw/util'; -import { - LoaderEvent, - TypeLoadData, - TypeLoaderEventArgMap -} from './loader-event'; -import { filterScript } from './../util/filter'; - -type Options = { - maxParallelNum: number; -}; - -enum LoaderStatus { - FREE = 'free', - LOADING = 'loading', - COMPLETE = 'complete' -} - -export default class Loader { - private _opts: Options; - private _event: LoaderEvent; - // private _patternMap: {[uuid: string]: CanvasPattern} = {} - private _currentLoadData: TypeLoadData = {}; - private _currentUUIDQueue: string[] = []; - private _storageLoadData: TypeLoadData = {}; - private _status: LoaderStatus = LoaderStatus.FREE; - - private _waitingLoadQueue: Array<{ - uuidQueue: string[]; - loadData: TypeLoadData; - }> = []; - - constructor(opts: Options) { - this._opts = opts; - this._event = new LoaderEvent(); - this._waitingLoadQueue = []; - } - - load(data: IDrawData, changeResourceUUIDs: string[]): void { - const [uuidQueue, loadData] = this._resetLoadData( - data, - changeResourceUUIDs - ); - if ( - this._status === LoaderStatus.FREE || - this._status === LoaderStatus.COMPLETE - ) { - this._currentUUIDQueue = uuidQueue; - this._currentLoadData = loadData; - this._loadTask(); - } else if (this._status === LoaderStatus.LOADING && uuidQueue.length > 0) { - this._waitingLoadQueue.push({ - uuidQueue, - loadData - }); - } - } - - on( - name: T, - callback: (arg: TypeLoaderEventArgMap[T]) => void - ) { - this._event.on(name, callback); - } - - off( - name: T, - callback: (arg: TypeLoaderEventArgMap[T]) => void - ) { - this._event.off(name, callback); - } - - isComplete() { - return this._status === LoaderStatus.COMPLETE; - } - - getContent(uuid: string): null | HTMLImageElement | HTMLCanvasElement { - if (this._storageLoadData[uuid]?.status === 'loaded') { - return this._storageLoadData[uuid].content; - } - return null; - } - - // getPattern( - // elem: DataElement, - // opts?: { - // forceUpdate: boolean - // } - // ): null | CanvasPattern { - // if (this._patternMap[elem.uuid] ) { - // if (!(opts && opts.forceUpdate === true)) { - // return this._patternMap[elem.uuid]; - // } - // } - // const item = this._currentLoadData[elem.uuid]; - // if (item?.status === 'loaded') { - // const board = this._opts.board; - // const tempCanvas = board.createCanvas(); - // const tempCtx = board.createContext(tempCanvas); - // const image = this.getContent(elem.uuid); - // tempCtx.drawImage(image, elem.x, elem.y, elem.w, elem.h); - - // const canvas = board.createCanvas(); - // const ctx = board.createContext(canvas); - // const pattern = ctx.createPattern(tempCanvas, 'no-repeat'); - // if (pattern) this._patternMap[elem.uuid] = pattern; - // return pattern; - // } - // return null; - // } - - private _resetLoadData( - data: IDrawData, - changeResourceUUIDs: string[] - ): [string[], TypeLoadData] { - const loadData: TypeLoadData = {}; - const uuidQueue: string[] = []; - - const storageLoadData = this._storageLoadData; - // const currentUUIDs: string[] = [] - - // add new load-data - for (let i = data.elements.length - 1; i >= 0; i--) { - const elem = data.elements[i] as DataElement<'image' | 'svg' | 'html'>; - // currentUUIDs.push(elem.uuid); - if (['image', 'svg', 'html'].includes(elem.type)) { - if (!storageLoadData[elem.uuid]) { - loadData[elem.uuid] = this._createEmptyLoadItem(elem); - uuidQueue.push(elem.uuid); - } else { - if (changeResourceUUIDs.includes(elem.uuid)) { - loadData[elem.uuid] = this._createEmptyLoadItem(elem); - uuidQueue.push(elem.uuid); - } - // if (elem.type === 'image') { - // const _ele = elem as DataElement<'image'>; - // if (_ele.desc.src !== storageLoadData[elem.uuid].source) { - // loadData[elem.uuid] = this._createEmptyLoadItem(elem); - // uuidQueue.push(elem.uuid); - // } - // } else if (elem.type === 'svg') { - // const _ele = elem as DataElement<'svg'>; - // if (_ele.desc.svg !== storageLoadData[elem.uuid].source) { - // loadData[elem.uuid] = this._createEmptyLoadItem(elem); - // uuidQueue.push(elem.uuid); - // } - // } else if (elem.type === 'html') { - // const _ele = elem as DataElement<'html'>; - // if (filterScript(_ele.desc.html) !== storageLoadData[elem.uuid].source) { - // loadData[elem.uuid] = this._createEmptyLoadItem(elem); - // uuidQueue.push(elem.uuid); - // } - // } - } - } - } - - // const loadDataUUIDs = Object.keys(loadData); - // // clear unuse load-data - // loadDataUUIDs.forEach((loadUUID) => { - // if (currentUUIDs.includes(loadUUID) !== true) { - // delete loadData[loadUUID]; - // } - // }); - return [uuidQueue, loadData]; - } - - private _createEmptyLoadItem( - elem: DataElement<'image' | 'svg' | 'html'> - ): TypeLoadData[string] { - let source = ''; - - const type: TypeLoadData[string]['type'] = - elem.type as TypeLoadData[string]['type']; - let elemW: number = elem.w; - let elemH: number = elem.h; - if (elem.type === 'image') { - const _elem = elem as DataElement<'image'>; - source = _elem.desc.src || ''; - } else if (elem.type === 'svg') { - const _elem = elem as DataElement<'svg'>; - source = _elem.desc.svg || ''; - } else if (elem.type === 'html') { - const _elem = elem as DataElement<'html'>; - source = filterScript(_elem.desc.html || ''); - elemW = _elem.desc.width || elem.w; - elemH = _elem.desc.height || elem.h; - } - return { - uuid: elem.uuid, - type: type, - status: 'null', - content: null, - source, - elemW, - elemH, - element: deepClone(elem) - }; - } - - private _loadTask() { - if (this._status === LoaderStatus.LOADING) { - return; - } - this._status = LoaderStatus.LOADING; - - if (this._currentUUIDQueue.length === 0) { - if (this._waitingLoadQueue.length === 0) { - this._status = LoaderStatus.COMPLETE; - this._event.trigger('complete', undefined); - return; - } else { - const waitingItem = this._waitingLoadQueue.shift(); - if (waitingItem) { - const { uuidQueue, loadData } = waitingItem; - this._currentLoadData = loadData; - this._currentUUIDQueue = uuidQueue; - } - } - } - - const { maxParallelNum } = this._opts; - const uuids = this._currentUUIDQueue.splice(0, maxParallelNum); - const uuidMap: { [uuid: string]: number } = {}; - - uuids.forEach((url, i) => { - uuidMap[url] = i; - }); - const loadUUIDList: string[] = []; - const _loadAction = () => { - if (loadUUIDList.length >= maxParallelNum) { - return false; - } - if (uuids.length === 0) { - return true; - } - - for (let i = loadUUIDList.length; i < maxParallelNum; i++) { - const uuid = uuids.shift(); - if (uuid === undefined) { - break; - } - loadUUIDList.push(uuid); - - this._loadElementSource(this._currentLoadData[uuid]) - .then((image) => { - loadUUIDList.splice(loadUUIDList.indexOf(uuid), 1); - const status = _loadAction(); - - this._storageLoadData[uuid] = { - uuid, - type: this._currentLoadData[uuid].type, - status: 'loaded', - content: image, - source: this._currentLoadData[uuid].source, - elemW: this._currentLoadData[uuid].elemW, - elemH: this._currentLoadData[uuid].elemH, - element: this._currentLoadData[uuid].element - }; - - if ( - loadUUIDList.length === 0 && - uuids.length === 0 && - status === true - ) { - this._status = LoaderStatus.FREE; - this._loadTask(); - } - this._event.trigger('load', { - uuid: this._storageLoadData[uuid]?.uuid, - type: this._storageLoadData[uuid].type, - status: this._storageLoadData[uuid].status, - content: this._storageLoadData[uuid].content, - source: this._storageLoadData[uuid].source, - elemW: this._storageLoadData[uuid].elemW, - elemH: this._storageLoadData[uuid].elemH, - element: this._storageLoadData[uuid]?.element - }); - }) - .catch((err) => { - console.warn(err); - - loadUUIDList.splice(loadUUIDList.indexOf(uuid), 1); - const status = _loadAction(); - - if (this._currentLoadData[uuid]) { - this._storageLoadData[uuid] = { - uuid, - type: this._currentLoadData[uuid]?.type, - status: 'fail', - content: null, - error: err, - source: this._currentLoadData[uuid]?.source, - elemW: this._currentLoadData[uuid]?.elemW, - elemH: this._currentLoadData[uuid]?.elemH, - element: this._currentLoadData[uuid]?.element - }; - } - - if ( - loadUUIDList.length === 0 && - uuids.length === 0 && - status === true - ) { - this._status = LoaderStatus.FREE; - this._loadTask(); - } - - if (this._currentLoadData[uuid]) { - this._event.trigger('error', { - uuid: uuid, - type: this._storageLoadData[uuid]?.type, - status: this._storageLoadData[uuid]?.status, - content: this._storageLoadData[uuid]?.content, - source: this._storageLoadData[uuid]?.source, - elemW: this._storageLoadData[uuid]?.elemW, - elemH: this._storageLoadData[uuid]?.elemH, - element: this._storageLoadData[uuid]?.element - }); - } - }); - } - return false; - }; - _loadAction(); - } - - private async _loadElementSource( - params: TypeLoadData[string] - ): Promise { - if (params && params.type === 'image') { - const image = await loadImage(params.source); - return image; - } else if (params && params.type === 'svg') { - const image = await loadSVG(params.source); - return image; - } else if (params && params.type === 'html') { - const image = await loadHTML(params.source, { - width: params.elemW, - height: params.elemH - }); - return image; - } - throw Error("Element's source is not support!"); - } -} diff --git a/packages/renderer/src/lib/parse.ts b/packages/renderer/src/lib/parse.ts deleted file mode 100644 index 3cdcbae..0000000 --- a/packages/renderer/src/lib/parse.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IDrawData, DataElement, DataElemDesc } from '@idraw/types'; -import { elementNames } from './../constant/element'; - -export function parseData(data: any): IDrawData { - const result: IDrawData = { - elements: [] - }; - if (Array.isArray(data?.elements)) { - data?.elements.forEach((elem: any = {}) => { - if (isElement(elem)) { - result.elements.push(elem); - } - }); - } - if (typeof data.bgColor === 'string') { - result.bgColor = data.bgColor; - } - return result; -} - -function isElement(elem: DataElement): boolean { - if ( - !( - isNumber(elem.x) && - isNumber(elem.y) && - isNumber(elem.w) && - isNumber(elem.h) - ) - ) { - return false; - } - if (!(typeof elem.type === 'string' && elementNames.includes(elem.type))) { - return false; - } - return true; -} - -function isNumber(num: any) { - return num >= 0 || num < 0; -} diff --git a/packages/renderer/src/lib/renderer-event.ts b/packages/renderer/src/lib/renderer-event.ts deleted file mode 100644 index 7139769..0000000 --- a/packages/renderer/src/lib/renderer-event.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { DataElement, DataElemDesc } from '@idraw/types'; - -export type TypeRendererEventArgMap = { - drawFrame: { t: number }; - drawFrameComplete: { t: number }; - load: { element: DataElement }; - loadComplete: { t: number }; - error: { element: DataElement; error: any }; -}; - -export interface TypeRendererEvent { - on( - key: T, - callback: (p: TypeRendererEventArgMap[T]) => void - ): void; - off( - key: T, - callback: (p: TypeRendererEventArgMap[T]) => void - ): void; - trigger( - key: T, - p: TypeRendererEventArgMap[T] - ): void; -} - -export class RendererEvent implements TypeRendererEvent { - private _listeners: Map void)[]>; - - constructor() { - this._listeners = new Map(); - } - - on( - eventKey: T, - callback: (p: TypeRendererEventArgMap[T]) => void - ) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - callbacks?.push(callback); - this._listeners.set(eventKey, callbacks || []); - } else { - this._listeners.set(eventKey, [callback]); - } - } - - off( - eventKey: T, - callback: (p: TypeRendererEventArgMap[T]) => void - ) { - if (this._listeners.has(eventKey)) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - for (let i = 0; i < callbacks?.length; i++) { - if (callbacks[i] === callback) { - callbacks.splice(i, 1); - break; - } - } - } - this._listeners.set(eventKey, callbacks || []); - } - } - - trigger( - eventKey: T, - arg: TypeRendererEventArgMap[T] - ) { - const callbacks = this._listeners.get(eventKey); - if (Array.isArray(callbacks)) { - callbacks.forEach((cb) => { - cb(arg); - }); - return true; - } else { - return false; - } - } - - has(name: string) { - if (this._listeners.has(name)) { - const list: ((p: TypeRendererEventArgMap[T]) => void)[] | undefined = - this._listeners.get(name); - if (Array.isArray(list) && list.length > 0) { - return true; - } - } - return false; - } -} diff --git a/packages/renderer/src/lib/temp.ts b/packages/renderer/src/lib/temp.ts deleted file mode 100644 index 6baff8d..0000000 --- a/packages/renderer/src/lib/temp.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { HelperWrapperControllerDirection, Point } from '@idraw/types'; -import { Mode, CursorStatus } from './../constant/static'; - -type TempDataDesc = { - hasInited: boolean; - onlyRender: boolean; - mode: Mode; - cursorStatus: CursorStatus; - selectedUUID: string | null; - selectedUUIDList: string[]; - hoverUUID: string | null; - selectedControllerDirection: HelperWrapperControllerDirection | null; - hoverControllerDirection: HelperWrapperControllerDirection | null; - prevPoint: Point | null; -}; - -function createData(): TempDataDesc { - return { - onlyRender: false, - hasInited: false, - mode: Mode.NULL, - cursorStatus: CursorStatus.NULL, - selectedUUID: null, - selectedUUIDList: [], - hoverUUID: null, - selectedControllerDirection: null, - hoverControllerDirection: null, - prevPoint: null - }; -} - -export class TempData { - private _temp: TempDataDesc; - - constructor() { - this._temp = createData(); - } - - set(name: T, value: TempDataDesc[T]) { - this._temp[name] = value; - } - - get(name: T): TempDataDesc[T] { - return this._temp[name]; - } - - clear() { - this._temp = createData(); - } -} diff --git a/packages/renderer/src/lib/transform.ts b/packages/renderer/src/lib/transform.ts deleted file mode 100644 index 7cfdfbd..0000000 --- a/packages/renderer/src/lib/transform.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { IDrawContext, Point, DataElement, DataElemDesc } from '@idraw/types'; -import { calcElementCenter, parseAngleToRadian } from './calculate'; - -function rotateElement( - ctx: IDrawContext, - elem: DataElement, - callback: (ctx: IDrawContext) => void -): void { - const center: Point = calcElementCenter(elem); - const radian = parseAngleToRadian(elem.angle || 0); - return rotateContext(ctx, center, radian || 0, callback); -} - -function rotateContext( - ctx: IDrawContext, - center: Point | undefined, - radian: number, - callback: (ctx: IDrawContext) => void -): void { - if (center && (radian > 0 || radian < 0)) { - ctx.translate(center.x, center.y); - ctx.rotate(radian); - ctx.translate(-center.x, -center.y); - } - - callback(ctx); - - if (center && (radian > 0 || radian < 0)) { - ctx.translate(center.x, center.y); - ctx.rotate(-radian); - ctx.translate(-center.x, -center.y); - } -} - -export { rotateContext, rotateElement }; diff --git a/packages/renderer/src/lib/value.ts b/packages/renderer/src/lib/value.ts deleted file mode 100644 index c224a9b..0000000 --- a/packages/renderer/src/lib/value.ts +++ /dev/null @@ -1,9 +0,0 @@ - -export function limitNum(num: number): number { - const numStr: string = num.toFixed(2); - return parseFloat(numStr); -} - -export function limitAngle(angle: number): number { - return limitNum(angle % 360); -} diff --git a/packages/renderer/src/loader.ts b/packages/renderer/src/loader.ts new file mode 100644 index 0000000..b73547e --- /dev/null +++ b/packages/renderer/src/loader.ts @@ -0,0 +1,118 @@ +import type { RendererLoader, LoaderEventMap, LoadFunc, LoadContent, LoadItem, LoadElementType, Element } from '@idraw/types'; +import { loadImage, loadHTML, loadSVG, EventEmitter } from '@idraw/util'; + +interface LoadItemMap { + [uuid: string]: LoadItem; +} + +const supportElementTypes: LoadElementType[] = ['image', 'svg', 'html']; + +export class Loader extends EventEmitter implements RendererLoader { + private _loadFuncMap: Record> = {}; + private _currentLoadItemMap: LoadItemMap = {}; + private _storageLoadItemMap: LoadItemMap = {}; + + constructor() { + super(); + this._registerLoadFunc<'image'>('image', async (elem: Element<'image'>) => { + const content = await loadImage(elem.desc.src); + return { + uuid: elem.uuid, + lastModified: Date.now(), + content + }; + }); + this._registerLoadFunc<'html'>('html', async (elem: Element<'html'>) => { + const content = await loadHTML(elem.desc.html, elem.desc); + return { + uuid: elem.uuid, + lastModified: Date.now(), + content + }; + }); + this._registerLoadFunc<'svg'>('svg', async (elem: Element<'svg'>) => { + const content = await loadSVG(elem.desc.svg); + return { + uuid: elem.uuid, + lastModified: Date.now(), + content + }; + }); + } + private _registerLoadFunc(type: T, func: LoadFunc) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this._loadFuncMap[type] = func; + } + + private _createLoadItem(element: Element): LoadItem { + return { + element, + status: 'null', + content: null, + error: null, + startTime: -1, + endTime: -1 + }; + } + + private _emitLoad(item: LoadItem) { + const uuid = item.element.uuid; + const storageItem = this._storageLoadItemMap[uuid]; + if (storageItem) { + if (storageItem.startTime < item.startTime) { + this._storageLoadItemMap[uuid] = item; + this.trigger('load', { ...item, countTime: item.endTime - item.startTime }); + } + } else { + this._storageLoadItemMap[uuid] = item; + this.trigger('load', { ...item, countTime: item.endTime - item.startTime }); + } + } + + private _emitError(item: LoadItem) { + const uuid = item.element.uuid; + const storageItem = this._storageLoadItemMap[uuid]; + if (storageItem) { + if (storageItem.startTime < item.startTime) { + this._storageLoadItemMap[uuid] = item; + this.trigger('error', { ...item, countTime: item.endTime - item.startTime }); + } + } else { + this._storageLoadItemMap[uuid] = item; + this.trigger('error', { ...item, countTime: item.endTime - item.startTime }); + } + } + + private _loadResource(element: Element) { + const item = this._createLoadItem(element); + this._currentLoadItemMap[element.uuid] = item; + const loadFunc = this._loadFuncMap[element.type]; + if (typeof loadFunc === 'function') { + item.startTime = Date.now(); + loadFunc(element) + .then((result) => { + item.content = result.content; + item.endTime = Date.now(); + item.status = 'load'; + this._emitLoad(item); + }) + .catch((err: Error) => { + item.endTime = Date.now(); + item.status = 'error'; + item.error = err; + this._emitError(item); + }); + } + } + + load(element: Element) { + if (supportElementTypes.includes(element.type)) { + this._loadResource(element); + } + } + + getContent(uuid: string): LoadContent | null { + return this._storageLoadItemMap?.[uuid]?.content || null; + } +} diff --git a/packages/renderer/src/util/filter.ts b/packages/renderer/src/util/filter.ts deleted file mode 100644 index df84741..0000000 --- a/packages/renderer/src/util/filter.ts +++ /dev/null @@ -1,4 +0,0 @@ - -export function filterScript(html: string) { - return html.replace(//ig, ''); -} \ No newline at end of file diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 773f851..1e364e0 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -7,3 +7,6 @@ export * from './lib/board'; export * from './lib/renderer'; export * from './lib/loader'; export * from './lib/store'; +export * from './lib/watcher'; +export * from './lib/core'; +export * from './lib/idraw'; diff --git a/packages/types/src/lib/board.ts b/packages/types/src/lib/board.ts index 121ed97..f18a789 100644 --- a/packages/types/src/lib/board.ts +++ b/packages/types/src/lib/board.ts @@ -1,8 +1,9 @@ import type { Point } from './point'; import type { ViewContent, ViewCalculator } from './view'; import type { UtilEventEmitter } from './util'; -import type { Renderer } from '../renderer'; import type { ActiveStore, StoreSharer } from './store'; +import type { RendererEventMap, RendererOptions, RendererDrawOptions } from './renderer'; +import type { Data } from './data'; interface BoardWatcherPointEvent { point: Point; @@ -64,12 +65,13 @@ export interface BoardViewerFrameSnapshot { } export interface BoardViewerEventMap { + // eslint-disable-next-line @typescript-eslint/ban-types drawFrame: {}; } export interface BoardViewerOptions { sharer: StoreSharer; - renderer: Renderer; + renderer: BoardRenderer; viewContent: ViewContent; beforeDrawFrame: (e: { snapshot: BoardViewerFrameSnapshot }) => void; afterDrawFrame: (e: { snapshot: BoardViewerFrameSnapshot }) => void; @@ -78,3 +80,9 @@ export interface BoardViewerOptions { export interface BoardViewer extends UtilEventEmitter { drawFrame(): void; } + +export interface BoardRenderer extends UtilEventEmitter { + updateOptions(opts: RendererOptions): void; + drawData(data: Data, opts: RendererDrawOptions): void; + scale(num: number): void; +} diff --git a/packages/types/src/lib/core.ts b/packages/types/src/lib/core.ts new file mode 100644 index 0000000..3ea84a0 --- /dev/null +++ b/packages/types/src/lib/core.ts @@ -0,0 +1,7 @@ +export interface CoreOptions { + width: number; + height: number; + contextWidth?: number; + contextHeight?: number; + onlyRender?: boolean; +} diff --git a/packages/types/src/lib/idraw.ts b/packages/types/src/lib/idraw.ts new file mode 100644 index 0000000..7885ce9 --- /dev/null +++ b/packages/types/src/lib/idraw.ts @@ -0,0 +1,3 @@ +import type { CoreOptions } from './core'; + +export type IDrawOptions = CoreOptions; diff --git a/packages/types/src/lib/middleware.ts b/packages/types/src/lib/middleware.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/types/src/lib/renderer.ts b/packages/types/src/lib/renderer.ts index 9800550..965e7e9 100644 --- a/packages/types/src/lib/renderer.ts +++ b/packages/types/src/lib/renderer.ts @@ -23,7 +23,7 @@ export interface RendererLoader extends UtilEventEmitter { getContent(uuid: string): LoadContent | null; } -export interface RendererDrawOptions extends ViewScaleInfo {} +export type RendererDrawOptions = ViewScaleInfo; export interface RendererDrawElementOptions extends RendererDrawOptions { loader: RendererLoader; diff --git a/packages/types/src/lib/watcher.ts b/packages/types/src/lib/watcher.ts new file mode 100644 index 0000000..d5ab6ef --- /dev/null +++ b/packages/types/src/lib/watcher.ts @@ -0,0 +1,5 @@ +import type { Point } from './point'; + +export interface PointWatcherEvent { + point: Point; +} diff --git a/tsconfig.web.json b/tsconfig.web.json index 3df948f..f974528 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -7,11 +7,19 @@ "moduleResolution": "node", "allowJs": false, "strict": true, + "strictNullChecks": true, "experimentalDecorators": true, "resolveJsonModule": true, "esModuleInterop": true, "removeComments": true, - "lib": ["ES2016", "DOM"] + "lib": ["ES2016", "DOM"], + "paths": { + "@idraw/types": ["./packages/types/src/index.ts"], + "@idraw/util": ["./packages/util/src/index.ts"], + "@idraw/renderer": ["./packages/renderer/src/index.ts"], + "@idraw/board": ["./packages/board/src/index.ts"], + "@idraw/core": ["./packages/core/src/index.ts"] + } }, "include": [ "packages/*/src",