feat(editor,stage): 多选支持居中操作

This commit is contained in:
roymondchen 2022-08-12 13:38:02 +08:00 committed by jia000
parent 8f5acff0a6
commit c949590f80
6 changed files with 84 additions and 51 deletions

View File

@ -118,10 +118,13 @@ watchEffect(() => {
stage?.on('update', (ev: UpdateEventData) => { stage?.on('update', (ev: UpdateEventData) => {
if (ev.parentEl) { if (ev.parentEl) {
services?.editorService.moveToContainer({ id: ev.el.id, style: ev.style }, ev.parentEl.id); for (const data of ev.data) {
services?.editorService.moveToContainer({ id: data.el.id, style: data.style }, ev.parentEl.id);
}
return; return;
} }
services?.editorService.update({ id: ev.el.id, style: ev.style });
services?.editorService.update(ev.data.map((data) => ({ id: data.el.id, style: data.style })));
}); });
stage?.on('sort', (ev: SortEventData) => { stage?.on('sort', (ev: SortEventData) => {

View File

@ -34,10 +34,10 @@ const menuData = reactive<MenuItem[]>([
{ {
type: 'button', type: 'button',
text: '水平居中', text: '水平居中',
display: () => canCenter.value && !props.isMultiSelect, display: () => canCenter.value,
handler: () => { handler: () => {
if (!node.value) return; if (!nodes.value) return;
editorService?.alignCenter(node.value); editorService?.alignCenter(nodes.value);
}, },
}, },
{ {

View File

@ -64,11 +64,14 @@ class Editor extends BaseService {
'select', 'select',
'doAdd', 'doAdd',
'add', 'add',
'doRemove',
'remove', 'remove',
'doUpdate',
'update', 'update',
'sort', 'sort',
'copy', 'copy',
'paste', 'paste',
'duAlignCenter',
'alignCenter', 'alignCenter',
'moveLayer', 'moveLayer',
'moveToContainer', 'moveToContainer',
@ -417,12 +420,7 @@ class Editor extends BaseService {
this.emit('remove'); this.emit('remove');
} }
/** public async doUpdate(config: MNode) {
*
* @param config id信息
* @returns
*/
public async update(config: MNode): Promise<MNode> {
if (!config?.id) throw new Error('没有配置或者配置缺少id值'); if (!config?.id) throw new Error('没有配置或者配置缺少id值');
const info = this.getNodeInfo(config.id, false); const info = this.getNodeInfo(config.id, false);
@ -475,13 +473,27 @@ class Editor extends BaseService {
} }
this.addModifiedNodeId(newConfig.id); this.addModifiedNodeId(newConfig.id);
this.pushHistoryState();
this.emit('update', newConfig);
return newConfig; return newConfig;
} }
/**
*
* @param config id信息
* @returns
*/
public async update(config: MNode | MNode[]): Promise<MNode | MNode[]> {
const nodes = Array.isArray(config) ? config : [config];
const newNodes = await Promise.all(nodes.map((node) => this.doUpdate(node)));
this.pushHistoryState();
this.emit('update', newNodes);
return newNodes.length > 1 ? newNodes[0] : newNodes;
}
/** /**
* id为id1的组件移动到id为id2的组件位置上[1,2,3,4] -> sort(1,3) -> [2,1,3,4] * id为id1的组件移动到id为id2的组件位置上[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
* @param id1 ID * @param id1 ID
@ -533,15 +545,13 @@ class Editor extends BaseService {
return this.add(pasteConfigs); return this.add(pasteConfigs);
} }
/** public async doAlignCenter(config: MNode): Promise<MNode> {
* const parent = this.getParentById(config.id);
* @param config
* @returns if (!parent) throw new Error('找不到父节点');
*/
public async alignCenter(config: MNode): Promise<MNode> {
const parent = this.get<MContainer>('parent');
const node = cloneDeep(toRaw(config)); const node = cloneDeep(toRaw(config));
const layout = await this.getLayout(toRaw(parent), node); const layout = await this.getLayout(parent, node);
if (layout === Layout.RELATIVE) { if (layout === Layout.RELATIVE) {
return config; return config;
} }
@ -561,12 +571,23 @@ class Editor extends BaseService {
node.style.left = (parent.style.width - node.style.width) / 2; node.style.left = (parent.style.width - node.style.width) / 2;
} }
const newNode = await this.update(node); return node;
}
this.get<StageCore | null>('stage')?.update({ /**
config: cloneDeep(toRaw(newNode)), *
root: cloneDeep(this.get<MApp>('root')), * @param config
}); * @returns
*/
public async alignCenter(config: MNode | MNode[]): Promise<MNode | MNode[]> {
const nodes = Array.isArray(config) ? config : [config];
const stage = this.get<StageCore | null>('stage');
const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
const newNode = await this.update(newNodes);
await stage?.multiSelect(newNodes.map((node) => node.id));
return newNode; return newNode;
} }

View File

@ -450,9 +450,13 @@ export default class StageDragResize extends EventEmitter {
} }
this.emit('update', { this.emit('update', {
el: this.target, data: [
{
el: this.target,
style: isResize ? { left, top, width, height } : { left, top },
},
],
parentEl, parentEl,
style: isResize ? { left, top, width, height } : { left, top },
}); });
} }

View File

@ -205,16 +205,19 @@ export default class StageMultiDragResize extends EventEmitter {
const doc = contentWindow?.document; const doc = contentWindow?.document;
if (!doc) return; if (!doc) return;
this.targetList.forEach((targetItem) => { this.emit('update', {
const offset = { left: targetItem.offsetLeft, top: targetItem.offsetTop }; data: this.targetList.map((targetItem) => {
const left = calcValueByFontsize(doc, offset.left); const offset = { left: targetItem.offsetLeft, top: targetItem.offsetTop };
const top = calcValueByFontsize(doc, offset.top); const left = calcValueByFontsize(doc, offset.left);
const width = calcValueByFontsize(doc, targetItem.clientWidth); const top = calcValueByFontsize(doc, offset.top);
const height = calcValueByFontsize(doc, targetItem.clientHeight); const width = calcValueByFontsize(doc, targetItem.clientWidth);
this.emit('update', { const height = calcValueByFontsize(doc, targetItem.clientHeight);
el: targetItem, return {
style: isResize ? { left, top, width, height } : { left, top }, el: targetItem,
}); style: isResize ? { left, top, width, height } : { left, top },
};
}),
parentEl: null,
}); });
} }

View File

@ -87,19 +87,21 @@ export interface GuidesEventData {
} }
export interface UpdateEventData { export interface UpdateEventData {
el: HTMLElement; data: {
parentEl: HTMLElement | null; el: HTMLElement;
ghostEl: HTMLElement; style: {
style: { width?: number;
width?: number; height?: number;
height?: number; left?: number;
left?: number; top?: number;
top?: number; transform?: {
transform?: { rotate?: string;
rotate?: string; scale?: string;
scale?: string; };
}; };
}; ghostEl?: HTMLElement;
}[];
parentEl: HTMLElement | null;
} }
export interface SortEventData { export interface SortEventData {