mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-11-02 09:32:13 +08:00
feat(stage): 支持rotate scale fix #92
This commit is contained in:
parent
46b26328ef
commit
a9936b5276
@ -107,6 +107,16 @@ class App extends EventEmitter {
|
|||||||
Object.entries(styleObj).forEach(([key, value]) => {
|
Object.entries(styleObj).forEach(([key, value]) => {
|
||||||
if (key === 'backgroundImage') {
|
if (key === 'backgroundImage') {
|
||||||
value && (results[key] = fillBackgroundImage(value));
|
value && (results[key] = fillBackgroundImage(value));
|
||||||
|
} else if (key === 'transform' && typeof value !== 'string') {
|
||||||
|
results[key] = Object.entries(value as Record<string, string>)
|
||||||
|
.map(([transformKey, transformValue]) => {
|
||||||
|
let defaultValue = 0;
|
||||||
|
if (transformKey === 'scale') {
|
||||||
|
defaultValue = 1;
|
||||||
|
}
|
||||||
|
return `${transformKey}(${transformValue || defaultValue})`;
|
||||||
|
})
|
||||||
|
.join(' ');
|
||||||
} else if (!whiteList.includes(key) && value && /^[-]?[0-9]*[.]?[0-9]*$/.test(value)) {
|
} else if (!whiteList.includes(key) && value && /^[-]?[0-9]*[.]?[0-9]*$/.test(value)) {
|
||||||
results[key] = `${value / 100}rem`;
|
results[key] = `${value / 100}rem`;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -161,6 +161,21 @@ export const fillConfig = (config: FormConfig = []) => [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'fieldset',
|
||||||
|
legend: '变形',
|
||||||
|
name: 'transform',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: 'rotate',
|
||||||
|
text: '旋转角度',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'scale',
|
||||||
|
text: '缩放',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@ -203,49 +203,41 @@ export default class StageDragResize extends EventEmitter {
|
|||||||
|
|
||||||
this.bindResizeEvent();
|
this.bindResizeEvent();
|
||||||
this.bindDragEvent();
|
this.bindDragEvent();
|
||||||
|
this.bindRotateEvent();
|
||||||
|
this.bindScaleEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bindResizeEvent(): void {
|
private bindResizeEvent(): void {
|
||||||
if (!this.moveable) throw new Error('moveable 为初始化');
|
if (!this.moveable) throw new Error('moveable 为初始化');
|
||||||
|
|
||||||
const frame = {
|
const frame = {
|
||||||
translate: [0, 0],
|
left: 0,
|
||||||
|
top: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.moveable
|
this.moveable
|
||||||
.on('resizeStart', (e) => {
|
.on('resizeStart', (e) => {
|
||||||
if (e.dragStart) {
|
if (!this.target) return;
|
||||||
const rect = this.moveable!.getRect();
|
|
||||||
const offset = getAbsolutePosition(e.target as HTMLElement, rect);
|
this.dragStatus = ActionStatus.START;
|
||||||
e.dragStart.set([offset.left, offset.top]);
|
this.moveableHelper?.onResizeStart(e);
|
||||||
}
|
|
||||||
|
frame.top = this.target.offsetTop;
|
||||||
|
frame.left = this.target.offsetLeft;
|
||||||
})
|
})
|
||||||
.on('resize', ({ width, height, drag }) => {
|
.on('resize', (e) => {
|
||||||
|
const { width, height, drag } = e;
|
||||||
if (!this.moveable || !this.target || !this.dragEl) return;
|
if (!this.moveable || !this.target || !this.dragEl) return;
|
||||||
|
|
||||||
const { beforeTranslate } = drag;
|
const { beforeTranslate } = drag;
|
||||||
frame.translate = beforeTranslate;
|
|
||||||
this.dragStatus = ActionStatus.ING;
|
this.dragStatus = ActionStatus.ING;
|
||||||
|
|
||||||
|
this.moveableHelper?.onResize(e);
|
||||||
|
|
||||||
this.target.style.width = `${width}px`;
|
this.target.style.width = `${width}px`;
|
||||||
this.target.style.height = `${height}px`;
|
this.target.style.height = `${height}px`;
|
||||||
this.dragEl.style.width = `${width}px`;
|
this.target.style.left = `${frame.left + beforeTranslate[0]}px`;
|
||||||
this.dragEl.style.height = `${height}px`;
|
this.target.style.top = `${frame.top + beforeTranslate[1]}px`;
|
||||||
|
|
||||||
// 流式布局
|
|
||||||
if (this.mode === Mode.SORTABLE) {
|
|
||||||
this.dragEl.style.top = `${beforeTranslate[1]}px`;
|
|
||||||
this.target.style.top = `0px`;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dragEl.style.left = `${beforeTranslate[0]}px`;
|
|
||||||
this.dragEl.style.top = `${beforeTranslate[1]}px`;
|
|
||||||
|
|
||||||
const offset = getAbsolutePosition(this.target, { left: beforeTranslate[0], top: beforeTranslate[1] });
|
|
||||||
|
|
||||||
this.target.style.left = `${offset.left}px`;
|
|
||||||
this.target.style.top = `${offset.top}px`;
|
|
||||||
})
|
})
|
||||||
.on('resizeEnd', () => {
|
.on('resizeEnd', () => {
|
||||||
this.dragStatus = ActionStatus.END;
|
this.dragStatus = ActionStatus.END;
|
||||||
@ -311,6 +303,60 @@ export default class StageDragResize extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bindRotateEvent(): void {
|
||||||
|
if (!this.moveable) throw new Error('moveable 为初始化');
|
||||||
|
|
||||||
|
this.moveable
|
||||||
|
.on('rotateStart', (e) => {
|
||||||
|
this.dragStatus = ActionStatus.START;
|
||||||
|
this.moveableHelper?.onRotateStart(e);
|
||||||
|
})
|
||||||
|
.on('rotate', (e) => {
|
||||||
|
if (!this.target || !this.dragEl) return;
|
||||||
|
this.dragStatus = ActionStatus.ING;
|
||||||
|
this.moveableHelper?.onRotate(e);
|
||||||
|
const frame = this.moveableHelper?.getFrame(e.target);
|
||||||
|
this.target.style.transform = frame?.toCSSObject().transform || '';
|
||||||
|
})
|
||||||
|
.on('rotateEnd', (e) => {
|
||||||
|
this.dragStatus = ActionStatus.END;
|
||||||
|
const frame = this.moveableHelper?.getFrame(e.target);
|
||||||
|
this.emit('update', {
|
||||||
|
el: this.target,
|
||||||
|
style: {
|
||||||
|
transform: frame?.get('transform'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private bindScaleEvent(): void {
|
||||||
|
if (!this.moveable) throw new Error('moveable 为初始化');
|
||||||
|
|
||||||
|
this.moveable
|
||||||
|
.on('scaleStart', (e) => {
|
||||||
|
this.dragStatus = ActionStatus.START;
|
||||||
|
this.moveableHelper?.onScaleStart(e);
|
||||||
|
})
|
||||||
|
.on('scale', (e) => {
|
||||||
|
if (!this.target || !this.dragEl) return;
|
||||||
|
this.dragStatus = ActionStatus.ING;
|
||||||
|
this.moveableHelper?.onScale(e);
|
||||||
|
const frame = this.moveableHelper?.getFrame(e.target);
|
||||||
|
this.target.style.transform = frame?.toCSSObject().transform || '';
|
||||||
|
})
|
||||||
|
.on('scaleEnd', (e) => {
|
||||||
|
this.dragStatus = ActionStatus.END;
|
||||||
|
const frame = this.moveableHelper?.getFrame(e.target);
|
||||||
|
this.emit('update', {
|
||||||
|
el: this.target,
|
||||||
|
style: {
|
||||||
|
transform: frame?.get('transform'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private sort(): void {
|
private sort(): void {
|
||||||
if (!this.target || !this.ghostEl) throw new Error('未知错误');
|
if (!this.target || !this.ghostEl) throw new Error('未知错误');
|
||||||
const { top } = this.ghostEl.getBoundingClientRect();
|
const { top } = this.ghostEl.getBoundingClientRect();
|
||||||
@ -331,14 +377,15 @@ export default class StageDragResize extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private update(isResize = false): void {
|
private update(isResize = false): void {
|
||||||
const rect = this.moveable!.getRect();
|
if (!this.target) return;
|
||||||
|
|
||||||
const offset =
|
const offset =
|
||||||
this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : getAbsolutePosition(this.target as HTMLElement, rect);
|
this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : { left: this.target.offsetLeft, top: this.target.offsetTop };
|
||||||
|
|
||||||
const left = this.calcValueByFontsize(offset.left);
|
const left = this.calcValueByFontsize(offset.left);
|
||||||
const top = this.calcValueByFontsize(offset.top);
|
const top = this.calcValueByFontsize(offset.top);
|
||||||
const width = this.calcValueByFontsize(rect.width);
|
const width = this.calcValueByFontsize(this.target.clientWidth);
|
||||||
const height = this.calcValueByFontsize(rect.height);
|
const height = this.calcValueByFontsize(this.target.clientHeight);
|
||||||
|
|
||||||
this.emit('update', {
|
this.emit('update', {
|
||||||
el: this.target,
|
el: this.target,
|
||||||
@ -369,15 +416,16 @@ export default class StageDragResize extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateDragEl(el: HTMLElement) {
|
private updateDragEl(el: HTMLElement) {
|
||||||
const { width, height } = el.getBoundingClientRect();
|
|
||||||
const offset = getOffset(el);
|
const offset = getOffset(el);
|
||||||
|
const { transform } = getComputedStyle(el);
|
||||||
|
|
||||||
this.dragEl.style.cssText = `
|
this.dragEl.style.cssText = `
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
transform: ${transform};
|
||||||
left: ${offset.left}px;
|
left: ${offset.left}px;
|
||||||
top: ${offset.top}px;
|
top: ${offset.top}px;
|
||||||
width: ${width}px;
|
width: ${el.clientWidth}px;
|
||||||
height: ${height}px;
|
height: ${el.clientHeight}px;
|
||||||
z-index: ${ZIndex.DRAG_EL};
|
z-index: ${ZIndex.DRAG_EL};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -415,6 +463,8 @@ export default class StageDragResize extends EventEmitter {
|
|||||||
dragArea: false,
|
dragArea: false,
|
||||||
draggable: true,
|
draggable: true,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
scalable: false,
|
||||||
|
rotatable: false,
|
||||||
snappable: isAbsolute || isFixed,
|
snappable: isAbsolute || isFixed,
|
||||||
snapGap: isAbsolute || isFixed,
|
snapGap: isAbsolute || isFixed,
|
||||||
snapThreshold: 5,
|
snapThreshold: 5,
|
||||||
|
|||||||
@ -46,14 +46,15 @@ export default class TargetCalibrate extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public update(el: HTMLElement, prefix: String): HTMLElement {
|
public update(el: HTMLElement, prefix: String): HTMLElement {
|
||||||
const { width, height } = el.getBoundingClientRect();
|
|
||||||
const { left, top } = this.getOffset(el);
|
const { left, top } = this.getOffset(el);
|
||||||
|
const { transform } = getComputedStyle(el);
|
||||||
this.operationEl.style.cssText = `
|
this.operationEl.style.cssText = `
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
transform: ${transform};
|
||||||
left: ${left}px;
|
left: ${left}px;
|
||||||
top: ${top}px;
|
top: ${top}px;
|
||||||
width: ${width}px;
|
width: ${el.clientWidth}px;
|
||||||
height: ${height}px;
|
height: ${el.clientHeight}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
this.operationEl.id = `${prefix}${el.id}`;
|
this.operationEl.id = `${prefix}${el.id}`;
|
||||||
@ -65,35 +66,10 @@ export default class TargetCalibrate extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getOffset(el: HTMLElement): Offset {
|
private getOffset(el: HTMLElement): Offset {
|
||||||
const { transform } = getComputedStyle(el);
|
|
||||||
const { offsetParent } = el;
|
const { offsetParent } = el;
|
||||||
|
|
||||||
let left = el.offsetLeft;
|
const left = el.offsetLeft;
|
||||||
let top = el.offsetTop;
|
const top = el.offsetTop;
|
||||||
|
|
||||||
if (transform.indexOf('matrix') > -1) {
|
|
||||||
let a = 1;
|
|
||||||
let b = 1;
|
|
||||||
let c = 1;
|
|
||||||
let d = 1;
|
|
||||||
let e = 0;
|
|
||||||
let f = 0;
|
|
||||||
transform.replace(
|
|
||||||
/matrix\((.+), (.+), (.+), (.+), (.+), (.+)\)/,
|
|
||||||
($0: string, $1: string, $2: string, $3: string, $4: string, $5: string, $6: string): string => {
|
|
||||||
a = +$1;
|
|
||||||
b = +$2;
|
|
||||||
c = +$3;
|
|
||||||
d = +$4;
|
|
||||||
e = +$5;
|
|
||||||
f = +$6;
|
|
||||||
return transform;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
left = a * left + c * top + e;
|
|
||||||
top = b * left + d * top + f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offsetParent) {
|
if (offsetParent) {
|
||||||
const parentOffset = this.getOffset(offsetParent as HTMLElement);
|
const parentOffset = this.getOffset(offsetParent as HTMLElement);
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MoveableOptions } from 'react-moveable/declaration/types';
|
import { MoveableOptions } from 'moveable';
|
||||||
|
|
||||||
import Core from '@tmagic/core';
|
import Core from '@tmagic/core';
|
||||||
import { Id, MApp, MNode } from '@tmagic/schema';
|
import { Id, MApp, MNode } from '@tmagic/schema';
|
||||||
@ -58,6 +58,7 @@ export type Rect = {
|
|||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
} & Offset;
|
} & Offset;
|
||||||
|
|
||||||
export interface Offset {
|
export interface Offset {
|
||||||
left: number;
|
left: number;
|
||||||
top: number;
|
top: number;
|
||||||
@ -72,10 +73,14 @@ export interface UpdateEventData {
|
|||||||
el: HTMLElement;
|
el: HTMLElement;
|
||||||
ghostEl: HTMLElement;
|
ghostEl: HTMLElement;
|
||||||
style: {
|
style: {
|
||||||
width: number;
|
width?: number;
|
||||||
height: number;
|
height?: number;
|
||||||
left?: number;
|
left?: number;
|
||||||
top?: number;
|
top?: number;
|
||||||
|
transform?: {
|
||||||
|
rotate?: string;
|
||||||
|
scale?: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,35 +30,10 @@ const getParents = (el: Element, relative: Element) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getOffset = (el: HTMLElement): Offset => {
|
export const getOffset = (el: HTMLElement): Offset => {
|
||||||
const { transform } = getComputedStyle(el);
|
|
||||||
const { offsetParent } = el;
|
const { offsetParent } = el;
|
||||||
|
|
||||||
let left = el.offsetLeft;
|
const left = el.offsetLeft;
|
||||||
let top = el.offsetTop;
|
const top = el.offsetTop;
|
||||||
|
|
||||||
if (transform.indexOf('matrix') > -1) {
|
|
||||||
let a = 1;
|
|
||||||
let b = 1;
|
|
||||||
let c = 1;
|
|
||||||
let d = 1;
|
|
||||||
let e = 0;
|
|
||||||
let f = 0;
|
|
||||||
transform.replace(
|
|
||||||
/matrix\((.+), (.+), (.+), (.+), (.+), (.+)\)/,
|
|
||||||
($0: string, $1: string, $2: string, $3: string, $4: string, $5: string, $6: string): string => {
|
|
||||||
a = +$1;
|
|
||||||
b = +$2;
|
|
||||||
c = +$3;
|
|
||||||
d = +$4;
|
|
||||||
e = +$5;
|
|
||||||
f = +$6;
|
|
||||||
return transform;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
left = a * left + c * top + e;
|
|
||||||
top = b * left + d * top + f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offsetParent) {
|
if (offsetParent) {
|
||||||
const parentOffset = getOffset(offsetParent as HTMLElement);
|
const parentOffset = getOffset(offsetParent as HTMLElement);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user