Skip to content

Commit 731ecae

Browse files
authored
feat(core): 添加蒙层插件冲突处理
1 parent edc87d0 commit 731ecae

File tree

5 files changed

+132
-8
lines changed

5 files changed

+132
-8
lines changed

packages/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export { default as DrawLinePlugin } from './plugin/DrawLinePlugin';
2020
export { default as GroupTextEditorPlugin } from './plugin/GroupTextEditorPlugin';
2121
export { default as GroupAlignPlugin } from './plugin/GroupAlignPlugin';
2222
export { default as WorkspacePlugin } from './plugin/WorkspacePlugin';
23+
export { default as MaskPlugin } from './plugin/MaskPlugin';
2324
export { default as HistoryPlugin } from './plugin/HistoryPlugin';
2425
export { default as FlipPlugin } from './plugin/FlipPlugin';
2526
export { default as RulerPlugin } from './plugin/RulerPlugin';

packages/core/plugin/MaskPlugin.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* @Author: MOmo
3+
* @Date: 2024-07-12 15:10:02
4+
* @LastEditors: MOmo
5+
* @LastEditTime: 2024-07-12 15:15:45
6+
* @Description: 画布蒙层插件
7+
*/
8+
9+
import { fabric } from 'fabric';
10+
import Editor from '../Editor';
11+
type IEditor = Editor;
12+
13+
class MaskPlugin implements IPluginTempl {
14+
static pluginName = 'MaskPlugin';
15+
static apis = ['setCoverMask'];
16+
coverMask: null | fabric.Rect = null;
17+
workspace: null | fabric.Rect = null;
18+
workspaceEl!: HTMLElement;
19+
hackFlag = false;
20+
21+
constructor(public canvas: fabric.Canvas, public editor: IEditor) {
22+
this.init();
23+
}
24+
25+
private init() {
26+
const workspaceEl = document.querySelector('#workspace') as HTMLElement;
27+
if (!workspaceEl) {
28+
throw new Error('element #workspace is missing, plz check!');
29+
}
30+
this.workspaceEl = workspaceEl;
31+
this.initMask();
32+
}
33+
34+
// 返回workspace对象
35+
getWorkspase() {
36+
return this.canvas.getObjects().find((item) => item.id === 'workspace') as fabric.Rect;
37+
}
38+
39+
setCoverMask(hack = false) {
40+
if (!this.coverMask || !this.workspace) {
41+
return;
42+
}
43+
const center = this.canvas.getCenter();
44+
const zoom = this.canvas.getZoom();
45+
let zoomToPointNumber = zoom;
46+
if (hack) {
47+
// 比较hack的方法,判断为fabric内部的数据更新问题
48+
zoomToPointNumber += 0.0000001 * (this.hackFlag ? 1 : -1);
49+
this.hackFlag = !this.hackFlag;
50+
}
51+
52+
this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), zoomToPointNumber);
53+
if (zoom) {
54+
const { workspaceEl } = this;
55+
const width = workspaceEl.offsetWidth;
56+
const height = workspaceEl.offsetHeight;
57+
const cWidth = width / zoom;
58+
const cHeight = height / zoom;
59+
this.coverMask.width = cWidth;
60+
this.coverMask.height = cHeight;
61+
this.coverMask.left = (this.workspace.left || 0) + (this.workspace.width! - cWidth) / 2;
62+
this.coverMask.top = (this.workspace.top || 0) + (this.workspace.height! - cHeight) / 2;
63+
this.workspace.clone((clone: fabric.Rect) => {
64+
clone.left = -clone.width! / 2;
65+
clone.top = -clone.height! / 2;
66+
clone.inverted = true;
67+
this.coverMask!.clipPath = clone;
68+
this.canvas.requestRenderAll();
69+
});
70+
}
71+
}
72+
73+
initMask(needBindLoadJSON = true) {
74+
this.workspace = this.getWorkspase();
75+
if (!this.workspace) {
76+
throw new Error('MaskPlugin must be used after WorkspacePlugin!');
77+
}
78+
const coverMask = new fabric.Rect({
79+
fill: 'rgba(0,0,0,0.7)',
80+
id: 'coverMask',
81+
strokeWidth: 0,
82+
});
83+
coverMask.set('selectable', false);
84+
coverMask.set('hasControls', false);
85+
coverMask.set('evented', false);
86+
coverMask.hoverCursor = 'default';
87+
this.canvas.on('object:added', () => {
88+
coverMask.bringToFront();
89+
});
90+
this.canvas.clipPath = undefined;
91+
this.canvas.add(coverMask);
92+
this.coverMask = coverMask;
93+
this.setCoverMask();
94+
// 适配模板和psd的loadjson,在加载完成后再入mask
95+
needBindLoadJSON && this.editor.on('loadJson', () => this.initMask(false));
96+
}
97+
98+
destroy() {
99+
console.log('pluginDestroy');
100+
}
101+
}
102+
103+
export default MaskPlugin;

packages/core/plugin/ResizePlugin.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,7 @@ class ResizePlugin implements IPluginTempl {
204204
}
205205

206206
this.editor.setCenterFromObject(workspace);
207-
(this.editor.getPlugin('WorkspacePlugin') as WorkspacePlugin).setCoverMask(true);
208-
(this.editor.getPlugin('WorkspacePlugin') as WorkspacePlugin).clipPath();
207+
209208
if (['left', 'right'].includes(type)) {
210209
this.canvas.defaultCursor = 'ew-resize';
211210
} else {

packages/core/plugin/WorkspacePlugin.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type IEditor = Editor;
1313

1414
class WorkspacePlugin implements IPluginTempl {
1515
static pluginName = 'WorkspacePlugin';
16-
static events = ['sizeChange'];
16+
static events = ['sizeChange', 'zoomChange'];
1717
static apis = [
1818
'big',
1919
'small',
@@ -51,6 +51,7 @@ class WorkspacePlugin implements IPluginTempl {
5151
this._initWorkspace();
5252
this._initResizeObserve();
5353
this._bindWheel();
54+
this._bindSizeChange();
5455
}
5556

5657
hookImportAfter() {
@@ -61,7 +62,6 @@ class WorkspacePlugin implements IPluginTempl {
6162
workspace.set('hasControls', false);
6263
workspace.set('evented', false);
6364
this.setSize(workspace.width, workspace.height);
64-
this.editor.emit('sizeChange', workspace.width, workspace.height);
6565
}
6666
resolve('');
6767
});
@@ -223,8 +223,9 @@ class WorkspacePlugin implements IPluginTempl {
223223
this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), scale);
224224
if (!this.workspace) return;
225225
this.setCenterFromObject(this.workspace);
226-
this.setCoverMask();
227-
this.clipPath();
226+
227+
this.editor.emit('zoomChange');
228+
228229
if (cb) cb(this.workspace.left, this.workspace.top);
229230
}
230231

@@ -280,12 +281,31 @@ class WorkspacePlugin implements IPluginTempl {
280281
if (zoom < 0.01) zoom = 0.01;
281282
const center = this.canvas.getCenter();
282283
this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), zoom);
283-
this.setCoverMask();
284+
285+
this.editor.emit('zoomChange');
286+
284287
opt.e.preventDefault();
285288
opt.e.stopPropagation();
286289
});
287290
}
288291

292+
clipPathOrRefreshMask() {
293+
if (this.editor.getPlugin('MaskPlugin')) {
294+
this.editor.setCoverMask(true);
295+
} else {
296+
// 超出画布不展示
297+
this.workspace?.clone((cloned: fabric.Rect) => {
298+
this.canvas.clipPath = cloned;
299+
this.canvas.requestRenderAll();
300+
});
301+
}
302+
}
303+
304+
private _bindSizeChange() {
305+
this.editor.on('sizeChange', () => this.clipPathOrRefreshMask());
306+
this.editor.on('zoomChange', () => this.clipPathOrRefreshMask());
307+
}
308+
289309
destroy() {
290310
this.resizeObserver.disconnect();
291311
this.canvas.off();

src/views/home/index.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ import Editor, {
274274
ResizePlugin,
275275
LockPlugin,
276276
AddBaseTypePlugin,
277+
MaskPlugin,
277278
} from '@kuaitu/core';
278279
import Edit from '@/components/edit.vue';
279280
import ClipImage from '@/components/clipImage.vue';
@@ -391,7 +392,7 @@ onMounted(() => {
391392
canvasEditor.use(ResizePlugin);
392393
canvasEditor.use(LockPlugin);
393394
canvasEditor.use(AddBaseTypePlugin);
394-
canvasEditor.getPlugin('WorkspacePlugin').maskEnable();
395+
canvasEditor.use(MaskPlugin);
395396
396397
state.show = true;
397398
// 默认打开标尺

0 commit comments

Comments
 (0)