From 50191464b7efbc915bc640d041155a720bf642e6 Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Sun, 27 Jun 2021 14:36:21 +0800 Subject: [PATCH] feat: @idraw/core implement select area --- packages/board/src/lib/context.ts | 5 ++++ packages/core/src/index.ts | 32 ++++++++++++++++++------ packages/core/src/lib/draw/base.ts | 1 + packages/core/src/lib/draw/index.ts | 4 +++ packages/core/src/lib/draw/wrapper.ts | 33 ++++++++++++++++-------- packages/core/src/lib/helper.ts | 36 +++++++++++++++++++++++++++ packages/types/src/lib/context.ts | 3 ++- packages/types/src/lib/helper.ts | 15 ++++++++--- 8 files changed, 105 insertions(+), 24 deletions(-) diff --git a/packages/board/src/lib/context.ts b/packages/board/src/lib/context.ts index f7aabfe..9b7ee66 100644 --- a/packages/board/src/lib/context.ts +++ b/packages/board/src/lib/context.ts @@ -209,6 +209,10 @@ class Context implements TypeContext { this._ctx.textBaseline = baseline; } + setGlobalAlpha(alpha: number): void { + this._ctx.globalAlpha = alpha; + } + private _doSize(num: number) { return this._opts.devicePixelRatio * num; } @@ -224,6 +228,7 @@ class Context implements TypeContext { const _y = (y - scrollY) / scale; return this._doSize(_y); } + } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ae4f216..ed28286 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -30,6 +30,7 @@ enum Mode { NULL = 'null', SELECT_ELEMENT = 'select-element', SELECT_ELEMENT_WRAPPER_DOT = 'select-element-wrapper-dot', + SELECT_AREA = 'select-area', } enum CursorStatus { @@ -264,18 +265,25 @@ class Core { const [uuid, direction] = this[_helper].isPointInElementWrapperDot(point); if (uuid && direction) { + // Controll Element-Wrapper this[_mode] = Mode.SELECT_ELEMENT_WRAPPER_DOT; this[_selectedDotDirection] = direction; this[_selectedUUID] = uuid; } else { const [index, uuid] = this[_element].isPointInElement(point, this[_data]); - this.selectElement(index, { useMode: true }); - if (typeof uuid === 'string' && this[_coreEvent].has('screenSelectElement')) { - this[_coreEvent].trigger( - 'screenSelectElement', - { index, uuid, element: deepClone(this[_data].elements?.[index])} - ); - this[_emitChangeScreen](); + if (index >= 0) { + // Controll Element + this.selectElement(index, { useMode: true }); + if (typeof uuid === 'string' && this[_coreEvent].has('screenSelectElement')) { + this[_coreEvent].trigger( + 'screenSelectElement', + { index, uuid, element: deepClone(this[_data].elements?.[index])} + ); + this[_emitChangeScreen](); + } + } else { + // Controll Area + this[_mode] = Mode.SELECT_AREA; } } this.draw(); @@ -284,6 +292,7 @@ class Core { private [_handleMoveStart](point: TypePoint): void { this[_prevPoint] = point; const uuid = this[_selectedUUID]; + if (typeof uuid === 'string' && this[_coreEvent].has('screenMoveElementStart')) { this[_coreEvent].trigger('screenMoveElementStart', { index: this[_element].getElementIndex(this[_data], uuid), @@ -291,11 +300,12 @@ class Core { x: point.x, y: point.y }); + } else if (this[_mode] === Mode.SELECT_AREA) { + this[_helper].startSelectArea(point); } } private [_handleMove](point: TypePoint): void { - if (typeof this[_selectedUUID] === 'string') { if (this[_mode] === Mode.SELECT_ELEMENT) { this[_dragElement](this[_selectedUUID] as string, point, this[_prevPoint]); @@ -305,6 +315,9 @@ class Core { this[_transfromElement](this[_selectedUUID] as string, point, this[_prevPoint], this[_selectedDotDirection] as TypeHelperWrapperDotDirection); this[_cursorStatus] = CursorStatus.DRAGGING; } + } else if (this[_mode] === Mode.SELECT_AREA) { + this[_helper].changeSelectArea(point); + this.draw(); } this[_prevPoint] = point; } @@ -334,10 +347,13 @@ class Core { } this[_emitChangeData](); } + } else if (this[_mode] === Mode.SELECT_AREA) { + this[_helper].clearSelectedArea(); } this[_selectedUUID] = null; this[_prevPoint] = null; this[_cursorStatus] = CursorStatus.NULL; + this[_mode] = Mode.NULL; } private [_handleHover](point: TypePoint): void { diff --git a/packages/core/src/lib/draw/base.ts b/packages/core/src/lib/draw/base.ts index d3c202a..ad8bd9f 100644 --- a/packages/core/src/lib/draw/base.ts +++ b/packages/core/src/lib/draw/base.ts @@ -11,6 +11,7 @@ const { istype, color } = util; export function clearContext(ctx: TypeContext) { ctx.setFillStyle('rgb(0 0 0 / 0%)'); ctx.setStrokeStyle('rgb(0 0 0 / 0%)'); + ctx.setLineDash([]); } export function drawBgColor(ctx: TypeContext, color: string) { diff --git a/packages/core/src/lib/draw/index.ts b/packages/core/src/lib/draw/index.ts index 94b9ed4..6d33215 100644 --- a/packages/core/src/lib/draw/index.ts +++ b/packages/core/src/lib/draw/index.ts @@ -14,6 +14,7 @@ import { drawSVG } from './svg'; import { drawText } from './text'; import { drawElementWrapper, + drawAreaWrapper, // drawDisplayContextScrollWrapper, } from './wrapper'; @@ -32,6 +33,9 @@ export function drawContext( if (typeof data.bgColor === 'string' && isColorStr(data.bgColor)) { drawBgColor(ctx, data.bgColor); } + + drawAreaWrapper(ctx, helperConfig); + if (!(data.elements.length > 0)) { return; } diff --git a/packages/core/src/lib/draw/wrapper.ts b/packages/core/src/lib/draw/wrapper.ts index dadd5d5..75c3fb9 100644 --- a/packages/core/src/lib/draw/wrapper.ts +++ b/packages/core/src/lib/draw/wrapper.ts @@ -57,14 +57,25 @@ export function drawElementWrapper(ctx: TypeContext, config: TypeHelperConfig) { } -// export function drawDisplayContextScrollWrapper(displayCtx: TypeContext, config: TypeHelperConfig) { -// // console.log('config?.displayContextScrollWrapper = ', config?.displayContextScrollWrapper); -// // if (!config?.displayContextScrollWrapper) { -// // return; -// // } - -// // draw scroll x-line - -// // draw scroll y-line - -// } \ No newline at end of file +export function drawAreaWrapper(ctx: TypeContext, config: TypeHelperConfig) { + if (!config?.selectedAreaWrapper) { + return; + } + const wrapper = config.selectedAreaWrapper; + if (wrapper && wrapper.w > 0 && wrapper.h > 0) { + clearContext(ctx); + // draw wrapper's box + ctx.beginPath(); + ctx.setLineDash([]); + 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(); + } + +} diff --git a/packages/core/src/lib/helper.ts b/packages/core/src/lib/helper.ts index 1d5ebea..5df8207 100644 --- a/packages/core/src/lib/helper.ts +++ b/packages/core/src/lib/helper.ts @@ -17,12 +17,17 @@ import { rotateContext, } from './transform'; const { deepClone } = util.data; +const areaLineWidth = 2; +const areaColor = '#2ab6f1'; + export class Helper implements TypeHelper { private _helperConfig: TypeHelperConfig; private _coreConfig: TypeConfigStrict; private _ctx: TypeContext; private _board: Board; + private _areaStart: TypePoint = { x: 0, y: 0}; + private _areaEnd: TypePoint = { x: 0, y: 0}; constructor(board: Board, config: TypeConfigStrict) { this._board = board; @@ -89,6 +94,37 @@ export class Helper implements TypeHelper { return [uuid, direction]; } + startSelectArea(p: TypePoint) { + this._areaStart = p; + } + + changeSelectArea(p: TypePoint) { + this._areaEnd = p; + this._calcSelectedArea(); + } + + clearSelectedArea() { + this._areaStart = {x: 0, y: 0}; + this._areaStart = {x: 0, y: 0}; + this._calcSelectedArea(); + } + + private _calcSelectedArea() { + const start = this._areaStart; + const end = this._areaEnd; + + this._helperConfig.selectedAreaWrapper = { + x: Math.min(start.x, end.x), + y: Math.min(start.y, end.y), + w: Math.abs(end.x - start.x), + h: Math.abs(end.y - start.y), + startPoint: {x: start.x, y: start.y}, + endPoint: {x: end.x, y: end.y}, + lineWidth: areaLineWidth, + color: areaColor, + } + } + private _updateElementIndex(data: TypeData) { this._helperConfig.elementIndexMap = {}; data.elements.forEach((elem: TypeElement, i) => { diff --git a/packages/types/src/lib/context.ts b/packages/types/src/lib/context.ts index 97cea13..6ff289a 100644 --- a/packages/types/src/lib/context.ts +++ b/packages/types/src/lib/context.ts @@ -45,7 +45,8 @@ interface TypeContext { drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void; drawImage(image: CanvasImageSource, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; - createPattern(image: CanvasImageSource, repetition: string | null): CanvasPattern | null + createPattern(image: CanvasImageSource, repetition: string | null): CanvasPattern | null; + setGlobalAlpha(alpha: number): void; } export { diff --git a/packages/types/src/lib/helper.ts b/packages/types/src/lib/helper.ts index 06ab97b..7e8815b 100644 --- a/packages/types/src/lib/helper.ts +++ b/packages/types/src/lib/helper.ts @@ -5,6 +5,16 @@ import { TypePoint } from './board'; type TypeHelperConfig = { elementIndexMap: {[key: string]: number}, + selectedAreaWrapper?: { + x: number; + y: number; + w: number; + h: number; + startPoint: TypePoint; + endPoint: TypePoint; + lineWidth: number; + color: string; + }; selectedElementWrapper?: { uuid: string; dotSize: number; @@ -19,10 +29,6 @@ type TypeHelperConfig = { left: TypePoint, rotate: TypePoint, }, - // limit: { - // minWidth: number; - // minHeight: number; - // }, lineDash: number[]; lineWidth: number; color: string; @@ -39,6 +45,7 @@ type TypeHelperConfig = { } } + type TypeHelperUpdateOpts = { width: number; height: number;