feat: rewrite rotate element func

This commit is contained in:
chenshenhai 2021-05-29 21:00:10 +08:00
parent 5d3e84fbec
commit 4b9ab4a5b2
7 changed files with 179 additions and 150 deletions

View file

@ -14,4 +14,5 @@
- [x] Move elements' index
- [] Rotate elements
- [x] Transform elements's size
- [] Undo action record
- [] Undo action record
- [] Controll elements by data

View file

@ -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;

View file

@ -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<T extends keyof TypeElemDesc>(ctx: TypeContext, ele: TypeElement<T>) {
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();
});
});
}

View file

@ -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;

View file

@ -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)) {

View file

@ -0,0 +1,44 @@
import {
TypeContext,
TypePoint,
TypeElement,
TypeElemDesc,
} from '@idraw/types';
import { translateRotateCenter, translateRotateAngle } from './calculate';
function rotateElement(
ctx: TypeContext,
elem: TypeElement<keyof TypeElemDesc>,
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,
}

View file

@ -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,