From 4b9ab4a5b29ae71e5e8d8f4cd995edbda551c137 Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Sat, 29 May 2021 21:00:10 +0800 Subject: [PATCH] feat: rewrite rotate element func --- docs/features/core.md | 3 +- packages/core/src/index.ts | 2 + packages/core/src/lib/draw.ts | 99 +++++++++++------------- packages/core/src/lib/element.ts | 43 ++++------- packages/core/src/lib/helper.ts | 116 ++++++++++++++--------------- packages/core/src/lib/transform.ts | 44 +++++++++++ packages/types/src/lib/helper.ts | 22 +++--- 7 files changed, 179 insertions(+), 150 deletions(-) create mode 100644 packages/core/src/lib/transform.ts diff --git a/docs/features/core.md b/docs/features/core.md index befcafd..49888d7 100644 --- a/docs/features/core.md +++ b/docs/features/core.md @@ -14,4 +14,5 @@ - [x] Move elements' index - [] Rotate elements - [x] Transform elements's size -- [] Undo action record \ No newline at end of file +- [] Undo action record +- [] Controll elements by data \ No newline at end of file diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index f280e9b..0a5b655 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -139,6 +139,8 @@ class Core { // console.log('handlePoint = ', point); const [uuid, direction] = this[_helper].isPointInElementWrapperDot(point); + console.log('uuid, direction =', uuid, direction); + if (uuid && direction) { this[_mode] = Mode.SELECT_ELEMENT_WRAPPER_DOT; this[_selectedDotDirection] = direction; diff --git a/packages/core/src/lib/draw.ts b/packages/core/src/lib/draw.ts index eb1705f..5b24b68 100644 --- a/packages/core/src/lib/draw.ts +++ b/packages/core/src/lib/draw.ts @@ -7,7 +7,7 @@ import { // TypePoint, } from '@idraw/types'; import util from './../util'; -import { translateRotateAngle, translateRotateCenter } from './calculate'; +import { rotateContext, rotateElement } from './transform'; const { isColorStr } = util.color; @@ -36,25 +36,10 @@ export function drawContext(ctx: TypeContext, data: TypeData, config: TypeHelper function drawRect(ctx: TypeContext, ele: TypeElement) { const desc = ele.desc as TypeElemDesc['rect']; - - const angle = translateRotateAngle(ele.angle); - const center = translateRotateCenter(ele); - - if (angle > 0 || angle < 0) { - ctx.translate(center.x, center.y); - ctx.rotate(angle); - ctx.translate(0 - center.x, 0 - center.y); - } - - ctx.setFillStyle(desc.color); - ctx.fillRect(ele.x, ele.y, ele.w, ele.h); - - // reset rotate - if (angle > 0 || angle < 0) { - ctx.translate(center.x, center.y); - ctx.rotate(0 - angle); - ctx.translate(0 - center.x, 0 - center.y); - } + rotateElement(ctx, ele, () => { + ctx.setFillStyle(desc.color); + ctx.fillRect(ele.x, ele.y, ele.w, ele.h); + }); } function drawBgColor(ctx: TypeContext, color: string) { @@ -69,41 +54,47 @@ function drawElementWrapper(ctx: TypeContext, config: TypeHelperConfig) { } const wrapper = config.selectedElementWrapper; - if (typeof wrapper.angle === 'number' && wrapper.translate) { - ctx.translate(wrapper.translate.x, wrapper.translate.y); - ctx.rotate(wrapper.angle); - ctx.translate(0 - wrapper.translate.x, 0 - wrapper.translate.y); - } - - // draw wrapper's box - ctx.beginPath(); - ctx.setLineDash(wrapper.lineDash); - ctx.setLineWidth(wrapper.lineWidth); - ctx.setStrokeStyle(wrapper.color); - ctx.moveTo(wrapper.topLeft.x, wrapper.topLeft.y); - ctx.lineTo(wrapper.topRight.x, wrapper.topRight.y); - ctx.lineTo(wrapper.bottomRight.x, wrapper.bottomRight.y); - ctx.lineTo(wrapper.bottomLeft.x, wrapper.bottomLeft.y); - ctx.lineTo(wrapper.topLeft.x, wrapper.topLeft.y - wrapper.lineWidth / 2); - ctx.stroke(); - ctx.closePath(); - - // draw wrapper's dots - ctx.setFillStyle(wrapper.color); - [ - wrapper.topLeft, wrapper.top, wrapper.topRight, wrapper.right, - wrapper.bottomRight, wrapper.bottom, wrapper.bottomLeft, wrapper.left, - ].forEach((dot) => { + rotateContext(ctx, wrapper.translate, wrapper.angle || 0, () => { + // draw wrapper's box ctx.beginPath(); - ctx.arc(dot.x, dot.y, wrapper.dotSize, 0, Math.PI * 2); - ctx.fill(); + ctx.setLineDash(wrapper.lineDash); + ctx.setLineWidth(wrapper.lineWidth); + ctx.setStrokeStyle(wrapper.color); + ctx.moveTo(wrapper.dots.topLeft.x, wrapper.dots.topLeft.y); + ctx.lineTo(wrapper.dots.topRight.x, wrapper.dots.topRight.y); + ctx.lineTo(wrapper.dots.bottomRight.x, wrapper.dots.bottomRight.y); + ctx.lineTo(wrapper.dots.bottomLeft.x, wrapper.dots.bottomLeft.y); + ctx.lineTo(wrapper.dots.topLeft.x, wrapper.dots.topLeft.y - wrapper.lineWidth / 2); + ctx.stroke(); ctx.closePath(); - }); - // reset rotate - if (typeof wrapper.angle === 'number' && wrapper.translate) { - ctx.translate(wrapper.translate.x, wrapper.translate.y); - ctx.rotate(0 - wrapper.angle); - ctx.translate(0 - wrapper.translate.x, 0 - wrapper.translate.y); - } + + // draw wrapper's rotate line + ctx.beginPath(); + ctx.moveTo(wrapper.dots.top.x, wrapper.dots.top.y); + ctx.lineTo(wrapper.dots.rotate.x, wrapper.dots.rotate.y + wrapper.dotSize); + ctx.stroke(); + ctx.closePath(); + + // draw wrapper's rotate + ctx.beginPath(); + ctx.setLineDash([]); + ctx.setLineWidth(wrapper.dotSize / 2); + ctx.arc(wrapper.dots.rotate.x, wrapper.dots.rotate.y, wrapper.dotSize * 0.8, Math.PI / 6, Math.PI * 2); + ctx.stroke(); + ctx.closePath(); + + // draw wrapper's dots + ctx.setFillStyle(wrapper.color); + [ + wrapper.dots.topLeft, wrapper.dots.top, wrapper.dots.topRight, wrapper.dots.right, + wrapper.dots.bottomRight, wrapper.dots.bottom, wrapper.dots.bottomLeft, wrapper.dots.left, + ].forEach((dot) => { + ctx.beginPath(); + ctx.arc(dot.x, dot.y, wrapper.dotSize, 0, Math.PI * 2); + ctx.fill(); + ctx.closePath(); + }); + + }); } diff --git a/packages/core/src/lib/element.ts b/packages/core/src/lib/element.ts index ae53214..bf7f1a0 100644 --- a/packages/core/src/lib/element.ts +++ b/packages/core/src/lib/element.ts @@ -7,7 +7,7 @@ import { // TypeElemDesc, } from '@idraw/types'; import util from './../util'; -import { translateRotateAngle, translateRotateCenter } from './calculate'; +import { rotateElement } from './transform'; const { createUUID } = util.uuid; @@ -33,35 +33,22 @@ export class Element { let uuid = null for (let i = data.elements.length - 1; i >= 0; i--) { const ele = data.elements[i]; - const angle = translateRotateAngle(ele.angle); - const center = translateRotateCenter(ele); - - if (angle > 0 || angle < 0) { - ctx.translate(center.x, center.y); - ctx.rotate(angle); - ctx.translate(0 - center.x, 0 - center.y); - } - ctx.beginPath(); - ctx.moveTo(ele.x, ele.y); - ctx.lineTo(ele.x + ele.w, ele.y); - ctx.lineTo(ele.x + ele.w, ele.y + ele.h); - ctx.lineTo(ele.x, ele.y + ele.h); - ctx.lineTo(ele.x, ele.y); + rotateElement(ctx, ele, () => { + ctx.beginPath(); + ctx.moveTo(ele.x, ele.y); + ctx.lineTo(ele.x + ele.w, ele.y); + ctx.lineTo(ele.x + ele.w, ele.y + ele.h); + ctx.lineTo(ele.x, ele.y + ele.h); + ctx.lineTo(ele.x, ele.y); - ctx.rect(ele.x, ele.y, ele.w, ele.h); - ctx.closePath(); - if (ctx.isPointInPath(p.x, p.y)) { - idx = i; - uuid = ele.uuid; - } - - // reset rotate - if (angle > 0 || angle < 0) { - ctx.translate(center.x, center.y); - ctx.rotate(0 - angle); - ctx.translate(0 - center.x, 0 - center.y); - } + ctx.rect(ele.x, ele.y, ele.w, ele.h); + ctx.closePath(); + if (ctx.isPointInPath(p.x, p.y)) { + idx = i; + uuid = ele.uuid; + } + }); if (idx >= 0) { break; diff --git a/packages/core/src/lib/helper.ts b/packages/core/src/lib/helper.ts index 70d001f..6b9d127 100644 --- a/packages/core/src/lib/helper.ts +++ b/packages/core/src/lib/helper.ts @@ -11,6 +11,7 @@ import { TypeConfigStrict, } from '@idraw/types'; import { translateRotateAngle, translateRotateCenter } from './calculate'; +import { rotateContext } from './transform'; export class Helper implements TypeHelper { @@ -55,37 +56,29 @@ export class Helper implements TypeHelper { } const wrapper = this._helperConfig.selectedElementWrapper; const dots = [ - wrapper.topLeft, wrapper.top, wrapper.topRight, wrapper.right, - wrapper.bottomRight, wrapper.bottom, wrapper.bottomLeft, wrapper.left, + wrapper.dots.topLeft, wrapper.dots.top, wrapper.dots.topRight, wrapper.dots.right, + wrapper.dots.bottomRight, wrapper.dots.bottom, wrapper.dots.bottomLeft, wrapper.dots.left, + wrapper.dots.rotate, ]; const directionNames: TypeHelperWrapperDotDirection[] = [ 'top-left', 'top', 'top-right', 'right', - 'bottom-right', 'bottom', 'bottom-left', 'left', + 'bottom-right', 'bottom', 'bottom-left', 'left', + 'rotate', ]; - - if (typeof wrapper.angle === 'number' && wrapper.translate) { - ctx.translate(wrapper.translate.x, wrapper.translate.y); - ctx.rotate(wrapper.angle); - ctx.translate(0 - wrapper.translate.x, 0 - wrapper.translate.y); - } - for (let i = 0; i < dots.length; i ++) { - const dot = dots[i]; - ctx.beginPath(); - ctx.arc(dot.x, dot.y, wrapper.dotSize, 0, Math.PI * 2); - ctx.closePath(); - if (ctx.isPointInPath(p.x, p.y)) { - direction = directionNames[i]; + rotateContext(ctx, wrapper.translate, wrapper.angle || 0, () => { + for (let i = 0; i < dots.length; i ++) { + const dot = dots[i]; + ctx.beginPath(); + ctx.arc(dot.x, dot.y, wrapper.dotSize, 0, Math.PI * 2); + ctx.closePath(); + if (ctx.isPointInPath(p.x, p.y)) { + direction = directionNames[i]; + } + if (direction) { + break; + } } - if (direction) { - break; - } - } - // reset rotate - if (typeof wrapper.angle === 'number' && wrapper.translate) { - ctx.translate(wrapper.translate.x, wrapper.translate.y); - ctx.rotate(0 - wrapper.angle); - ctx.translate(0 - wrapper.translate.x, 0 - wrapper.translate.y); - } + }); return [uuid, direction]; } @@ -108,45 +101,52 @@ export class Helper implements TypeHelper { const dotSize = this._coreConfig.elementWrapper.dotSize / scale; const lineWidth = this._coreConfig.elementWrapper.lineWidth / scale; const lineDash = this._coreConfig.elementWrapper.lineDash.map(n => (n / scale)); + const rotateLimit = 12; const wrapper: TypeHelperConfig['selectedElementWrapper'] = { uuid, dotSize: dotSize, + dots: { + topLeft: { + x: elem.x - dotSize, + y: elem.y - dotSize, + }, + top: { + x: elem.x + elem.w / 2, + y: elem.y - dotSize, + }, + topRight: { + x: elem.x + elem.w + dotSize, + y: elem.y - dotSize, + }, + right: { + x: elem.x + elem.w + dotSize, + y: elem.y + elem.h / 2, + }, + bottomRight: { + x: elem.x + elem.w + dotSize, + y: elem.y + elem.h + dotSize, + }, + bottom: { + x: elem.x + elem.w / 2, + y: elem.y + elem.h + dotSize, + }, + bottomLeft: { + x: elem.x - dotSize, + y: elem.y + elem.h + dotSize, + }, + left: { + x: elem.x - dotSize, + y: elem.y + elem.h / 2, + }, + rotate: { + x: elem.x + elem.w / 2, + y: elem.y - dotSize - (dotSize * 2 + rotateLimit), + } + }, lineWidth: lineWidth, lineDash: lineDash, color: '#2ab6f1', - topLeft: { - x: elem.x - dotSize, - y: elem.y - dotSize, - }, - top: { - x: elem.x + elem.w / 2, - y: elem.y - dotSize, - }, - topRight: { - x: elem.x + elem.w + dotSize, - y: elem.y - dotSize, - }, - right: { - x: elem.x + elem.w + dotSize, - y: elem.y + elem.h / 2, - }, - bottomRight: { - x: elem.x + elem.w + dotSize, - y: elem.y + elem.h + dotSize, - }, - bottom: { - x: elem.x + elem.w / 2, - y: elem.y + elem.h + dotSize, - }, - bottomLeft: { - x: elem.x - dotSize, - y: elem.y + elem.h + dotSize, - }, - left: { - x: elem.x - dotSize, - y: elem.y + elem.h / 2, - }, }; if (typeof elem.angle === 'number' && (elem.angle > 0 || elem.angle < 0)) { diff --git a/packages/core/src/lib/transform.ts b/packages/core/src/lib/transform.ts new file mode 100644 index 0000000..e9d046b --- /dev/null +++ b/packages/core/src/lib/transform.ts @@ -0,0 +1,44 @@ +import { + TypeContext, + TypePoint, + TypeElement, + TypeElemDesc, +} from '@idraw/types'; +import { translateRotateCenter, translateRotateAngle } from './calculate'; + +function rotateElement( + ctx: TypeContext, + elem: TypeElement, + callback: (ctx: TypeContext) => void +) { + const center: TypePoint = translateRotateCenter(elem); + const angle = translateRotateAngle(elem.angle); + return rotateContext(ctx, center, angle || 0, callback); +} + + +function rotateContext( + ctx: TypeContext, + center: TypePoint | undefined, + angle: number, + callback: (ctx: TypeContext) => void +): void { + if (center && (angle > 0 || angle < 0)) { + ctx.translate(center.x, center.y); + ctx.rotate(angle); + ctx.translate(- center.x, - center.y); + } + + callback(ctx); + + if (center && (angle > 0 || angle < 0)) { + ctx.translate(center.x, center.y); + ctx.rotate(- angle); + ctx.translate(- center.x, - center.y); + } +} + +export { + rotateContext, + rotateElement, +} \ No newline at end of file diff --git a/packages/types/src/lib/helper.ts b/packages/types/src/lib/helper.ts index 5198270..2abf98c 100644 --- a/packages/types/src/lib/helper.ts +++ b/packages/types/src/lib/helper.ts @@ -8,17 +8,20 @@ type TypeHelperConfig = { selectedElementWrapper?: { uuid: string; dotSize: number; + dots: { + topLeft: TypePoint, + top: TypePoint, + topRight: TypePoint, + right: TypePoint, + bottomRight: TypePoint, + bottom: TypePoint, + bottomLeft: TypePoint, + left: TypePoint, + rotate: TypePoint, + } lineDash: number[]; lineWidth: number; color: string; - topLeft: TypePoint, - top: TypePoint, - topRight: TypePoint, - right: TypePoint, - bottomRight: TypePoint, - bottom: TypePoint, - bottomLeft: TypePoint, - left: TypePoint, angle?: number; translate?: TypePoint; } @@ -40,7 +43,8 @@ interface TypeHelper { type TypeHelperWrapperDotDirection = 'top-left' | 'top' | 'top-right' | 'right' -| 'bottom-right' | 'bottom' | 'bottom-left' | 'left'; +| 'bottom-right' | 'bottom' | 'bottom-left' | 'left' +| 'rotate'; export { TypeHelper,