@hprint/plugins 0.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/index.css +1 -0
  2. package/dist/index.js +478 -0
  3. package/dist/index.mjs +41731 -0
  4. package/dist/src/index.d.ts +8 -0
  5. package/dist/src/index.d.ts.map +1 -0
  6. package/dist/src/objects/Arrow.d.ts +2 -0
  7. package/dist/src/objects/Arrow.d.ts.map +1 -0
  8. package/dist/src/objects/ThinTailArrow.d.ts +2 -0
  9. package/dist/src/objects/ThinTailArrow.d.ts.map +1 -0
  10. package/dist/src/plugins/AddBaseTypePlugin.d.ts +26 -0
  11. package/dist/src/plugins/AddBaseTypePlugin.d.ts.map +1 -0
  12. package/dist/src/plugins/AlignGuidLinePlugin.d.ts +16 -0
  13. package/dist/src/plugins/AlignGuidLinePlugin.d.ts.map +1 -0
  14. package/dist/src/plugins/BarCodePlugin.d.ts +68 -0
  15. package/dist/src/plugins/BarCodePlugin.d.ts.map +1 -0
  16. package/dist/src/plugins/CenterAlignPlugin.d.ts +29 -0
  17. package/dist/src/plugins/CenterAlignPlugin.d.ts.map +1 -0
  18. package/dist/src/plugins/ControlsPlugin.d.ts +11 -0
  19. package/dist/src/plugins/ControlsPlugin.d.ts.map +1 -0
  20. package/dist/src/plugins/ControlsRotatePlugin.d.ts +11 -0
  21. package/dist/src/plugins/ControlsRotatePlugin.d.ts.map +1 -0
  22. package/dist/src/plugins/CopyPlugin.d.ts +30 -0
  23. package/dist/src/plugins/CopyPlugin.d.ts.map +1 -0
  24. package/dist/src/plugins/CreateElementPlugin.d.ts +121 -0
  25. package/dist/src/plugins/CreateElementPlugin.d.ts.map +1 -0
  26. package/dist/src/plugins/DeleteHotKeyPlugin.d.ts +25 -0
  27. package/dist/src/plugins/DeleteHotKeyPlugin.d.ts.map +1 -0
  28. package/dist/src/plugins/DrawLinePlugin.d.ts +26 -0
  29. package/dist/src/plugins/DrawLinePlugin.d.ts.map +1 -0
  30. package/dist/src/plugins/DrawPolygonPlugin.d.ts +41 -0
  31. package/dist/src/plugins/DrawPolygonPlugin.d.ts.map +1 -0
  32. package/dist/src/plugins/DringPlugin.d.ts +33 -0
  33. package/dist/src/plugins/DringPlugin.d.ts.map +1 -0
  34. package/dist/src/plugins/FlipPlugin.d.ts +26 -0
  35. package/dist/src/plugins/FlipPlugin.d.ts.map +1 -0
  36. package/dist/src/plugins/FontPlugin.d.ts +33 -0
  37. package/dist/src/plugins/FontPlugin.d.ts.map +1 -0
  38. package/dist/src/plugins/FreeDrawPlugin.d.ts +23 -0
  39. package/dist/src/plugins/FreeDrawPlugin.d.ts.map +1 -0
  40. package/dist/src/plugins/GroupAlignPlugin.d.ts +24 -0
  41. package/dist/src/plugins/GroupAlignPlugin.d.ts.map +1 -0
  42. package/dist/src/plugins/GroupPlugin.d.ts +24 -0
  43. package/dist/src/plugins/GroupPlugin.d.ts.map +1 -0
  44. package/dist/src/plugins/GroupTextEditorPlugin.d.ts +18 -0
  45. package/dist/src/plugins/GroupTextEditorPlugin.d.ts.map +1 -0
  46. package/dist/src/plugins/HistoryPlugin.d.ts +30 -0
  47. package/dist/src/plugins/HistoryPlugin.d.ts.map +1 -0
  48. package/dist/src/plugins/ImageStroke.d.ts +18 -0
  49. package/dist/src/plugins/ImageStroke.d.ts.map +1 -0
  50. package/dist/src/plugins/LayerPlugin.d.ts +31 -0
  51. package/dist/src/plugins/LayerPlugin.d.ts.map +1 -0
  52. package/dist/src/plugins/LockPlugin.d.ts +27 -0
  53. package/dist/src/plugins/LockPlugin.d.ts.map +1 -0
  54. package/dist/src/plugins/MaskPlugin.d.ts +38 -0
  55. package/dist/src/plugins/MaskPlugin.d.ts.map +1 -0
  56. package/dist/src/plugins/MaterialPlugin.d.ts +45 -0
  57. package/dist/src/plugins/MaterialPlugin.d.ts.map +1 -0
  58. package/dist/src/plugins/MiddleMousePlugin.d.ts +18 -0
  59. package/dist/src/plugins/MiddleMousePlugin.d.ts.map +1 -0
  60. package/dist/src/plugins/MoveHotKeyPlugin.d.ts +12 -0
  61. package/dist/src/plugins/MoveHotKeyPlugin.d.ts.map +1 -0
  62. package/dist/src/plugins/PathTextPlugin.d.ts +30 -0
  63. package/dist/src/plugins/PathTextPlugin.d.ts.map +1 -0
  64. package/dist/src/plugins/PolygonModifyPlugin.d.ts +28 -0
  65. package/dist/src/plugins/PolygonModifyPlugin.d.ts.map +1 -0
  66. package/dist/src/plugins/PrintPlugin.d.ts +39 -0
  67. package/dist/src/plugins/PrintPlugin.d.ts.map +1 -0
  68. package/dist/src/plugins/PsdPlugin.d.ts +17 -0
  69. package/dist/src/plugins/PsdPlugin.d.ts.map +1 -0
  70. package/dist/src/plugins/QrCodePlugin.d.ts +137 -0
  71. package/dist/src/plugins/QrCodePlugin.d.ts.map +1 -0
  72. package/dist/src/plugins/ResizePlugin.d.ts +44 -0
  73. package/dist/src/plugins/ResizePlugin.d.ts.map +1 -0
  74. package/dist/src/plugins/RulerPlugin.d.ts +24 -0
  75. package/dist/src/plugins/RulerPlugin.d.ts.map +1 -0
  76. package/dist/src/plugins/SimpleClipImagePlugin.d.ts +18 -0
  77. package/dist/src/plugins/SimpleClipImagePlugin.d.ts.map +1 -0
  78. package/dist/src/plugins/UnitPlugin.d.ts +84 -0
  79. package/dist/src/plugins/UnitPlugin.d.ts.map +1 -0
  80. package/dist/src/plugins/WaterMarkPlugin.d.ts +40 -0
  81. package/dist/src/plugins/WaterMarkPlugin.d.ts.map +1 -0
  82. package/dist/src/plugins/WorkspacePlugin.d.ts +57 -0
  83. package/dist/src/plugins/WorkspacePlugin.d.ts.map +1 -0
  84. package/dist/src/types/eventType.d.ts +11 -0
  85. package/dist/src/types/eventType.d.ts.map +1 -0
  86. package/dist/src/utils/psd.d.ts +3 -0
  87. package/dist/src/utils/psd.d.ts.map +1 -0
  88. package/dist/src/utils/ruler/guideline.d.ts +4 -0
  89. package/dist/src/utils/ruler/guideline.d.ts.map +1 -0
  90. package/dist/src/utils/ruler/index.d.ts +5 -0
  91. package/dist/src/utils/ruler/index.d.ts.map +1 -0
  92. package/dist/src/utils/ruler/ruler.d.ts +147 -0
  93. package/dist/src/utils/ruler/ruler.d.ts.map +1 -0
  94. package/dist/src/utils/ruler/utils.d.ts +50 -0
  95. package/dist/src/utils/ruler/utils.d.ts.map +1 -0
  96. package/dist/src/utils/units.d.ts +22 -0
  97. package/dist/src/utils/units.d.ts.map +1 -0
  98. package/package.json +51 -0
  99. package/src/assets/edgecontrol.svg +17 -0
  100. package/src/assets/lock.svg +7 -0
  101. package/src/assets/middlecontrol.svg +17 -0
  102. package/src/assets/middlecontrolhoz.svg +17 -0
  103. package/src/assets/rotateicon.svg +20 -0
  104. package/src/assets/style/resizePlugin.css +27 -0
  105. package/src/index.ts +121 -0
  106. package/src/objects/Arrow.js +47 -0
  107. package/src/objects/ThinTailArrow.js +50 -0
  108. package/src/plugins/AddBaseTypePlugin.ts +107 -0
  109. package/src/plugins/AlignGuidLinePlugin.ts +1141 -0
  110. package/src/plugins/BarCodePlugin.ts +860 -0
  111. package/src/plugins/CenterAlignPlugin.ts +133 -0
  112. package/src/plugins/ControlsPlugin.ts +251 -0
  113. package/src/plugins/ControlsRotatePlugin.ts +111 -0
  114. package/src/plugins/CopyPlugin.ts +255 -0
  115. package/src/plugins/CreateElementPlugin.ts +548 -0
  116. package/src/plugins/DeleteHotKeyPlugin.ts +57 -0
  117. package/src/plugins/DrawLinePlugin.ts +162 -0
  118. package/src/plugins/DrawPolygonPlugin.ts +205 -0
  119. package/src/plugins/DringPlugin.ts +125 -0
  120. package/src/plugins/FlipPlugin.ts +59 -0
  121. package/src/plugins/FontPlugin.ts +165 -0
  122. package/src/plugins/FreeDrawPlugin.ts +49 -0
  123. package/src/plugins/GroupAlignPlugin.ts +365 -0
  124. package/src/plugins/GroupPlugin.ts +82 -0
  125. package/src/plugins/GroupTextEditorPlugin.ts +198 -0
  126. package/src/plugins/HistoryPlugin.ts +181 -0
  127. package/src/plugins/ImageStroke.ts +121 -0
  128. package/src/plugins/LayerPlugin.ts +108 -0
  129. package/src/plugins/LockPlugin.ts +240 -0
  130. package/src/plugins/MaskPlugin.ts +155 -0
  131. package/src/plugins/MaterialPlugin.ts +224 -0
  132. package/src/plugins/MiddleMousePlugin.ts +45 -0
  133. package/src/plugins/MoveHotKeyPlugin.ts +46 -0
  134. package/src/plugins/PathTextPlugin.ts +89 -0
  135. package/src/plugins/PolygonModifyPlugin.ts +224 -0
  136. package/src/plugins/PrintPlugin.ts +81 -0
  137. package/src/plugins/PsdPlugin.ts +52 -0
  138. package/src/plugins/QrCodePlugin.ts +393 -0
  139. package/src/plugins/ResizePlugin.ts +274 -0
  140. package/src/plugins/RulerPlugin.ts +78 -0
  141. package/src/plugins/SimpleClipImagePlugin.ts +244 -0
  142. package/src/plugins/UnitPlugin.ts +327 -0
  143. package/src/plugins/WaterMarkPlugin.ts +257 -0
  144. package/src/plugins/WorkspacePlugin.ts +307 -0
  145. package/src/types/eventType.ts +11 -0
  146. package/src/utils/psd.js +432 -0
  147. package/src/utils/ruler/guideline.ts +145 -0
  148. package/src/utils/ruler/index.ts +91 -0
  149. package/src/utils/ruler/ruler.ts +924 -0
  150. package/src/utils/ruler/utils.ts +162 -0
  151. package/src/utils/units.ts +133 -0
  152. package/tsconfig.json +10 -0
  153. package/vite.config.ts +29 -0
@@ -0,0 +1,165 @@
1
+ import { fabric } from '@hprint/core';
2
+ import FontFaceObserver from 'fontfaceobserver';
3
+ import axios from 'axios';
4
+ import { utils } from '@hprint/shared';
5
+ import type { IEditor, IPluginTempl } from '@hprint/core';
6
+
7
+ type IPlugin = Pick<
8
+ FontPlugin,
9
+ 'getFontList' | 'loadFont' | 'getFontJson' | 'downFontByJSON'
10
+ >;
11
+
12
+ declare module '@hprint/core' {
13
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
14
+ interface IEditor extends IPlugin {}
15
+ }
16
+
17
+ interface Font {
18
+ type: string;
19
+ fontFamily: string;
20
+ }
21
+
22
+ interface FontSource {
23
+ name: string;
24
+ type: string;
25
+ file: string;
26
+ img: string;
27
+ }
28
+
29
+ class FontPlugin implements IPluginTempl {
30
+ private tempPromise: Promise<FontSource[]> | null;
31
+ static pluginName = 'FontPlugin';
32
+ static apis = ['getFontList', 'loadFont', 'getFontJson', 'downFontByJSON'];
33
+ repoSrc: string;
34
+ cacheList: FontSource[];
35
+ constructor(
36
+ public canvas: fabric.Canvas,
37
+ public editor: IEditor,
38
+ config: { repoSrc: string }
39
+ ) {
40
+ this.repoSrc = config.repoSrc;
41
+ this.cacheList = [];
42
+ this.tempPromise = null;
43
+ }
44
+
45
+ hookImportBefore(json: string) {
46
+ return this.downFontByJSON(json);
47
+ }
48
+ getFontList() {
49
+ // 返回暂存字体
50
+ if (this.cacheList.length) {
51
+ return Promise.resolve(this.cacheList);
52
+ }
53
+ if (this.tempPromise) return this.tempPromise;
54
+ this.tempPromise = axios
55
+ .get(
56
+ `${this.repoSrc}/api/fonts?populate=*&pagination[pageSize]=100`
57
+ )
58
+ .then((res) => {
59
+ const list = res.data.data.map((item: any) => {
60
+ return {
61
+ name: item.attributes.name,
62
+ type: item.attributes.type,
63
+ file:
64
+ this.repoSrc +
65
+ item.attributes.file.data.attributes.url,
66
+ img:
67
+ this.repoSrc +
68
+ item.attributes.img.data.attributes.url,
69
+ };
70
+ });
71
+ this.cacheList = list;
72
+ this.createFontCSS(list);
73
+ return list;
74
+ });
75
+ return this.tempPromise;
76
+ }
77
+
78
+ downFontByJSON(str: string) {
79
+ const object = JSON.parse(str);
80
+ let fontFamilies: string[] = [];
81
+ const skipFonts = ['arial'];
82
+ if (object.objects) {
83
+ fontFamilies = JSON.parse(str)
84
+ .objects.filter((item: Font) => {
85
+ const hasFontFile = this.cacheList.find(
86
+ (font) => font.name === item.fontFamily
87
+ );
88
+ return (
89
+ item.type.includes('text') &&
90
+ !skipFonts.includes(item.fontFamily) &&
91
+ hasFontFile
92
+ );
93
+ })
94
+ .map((item: Font) => item.fontFamily);
95
+ } else {
96
+ fontFamilies = skipFonts.includes(object.fontFamily)
97
+ ? []
98
+ : [object.fontFamily];
99
+ }
100
+
101
+ const fontFamiliesAll = fontFamilies.map((fontName) => {
102
+ const font = new FontFaceObserver(fontName);
103
+ return font.load(null, 150000);
104
+ });
105
+ return Promise.all(fontFamiliesAll);
106
+ }
107
+
108
+ // 获取字体数据 新增字体样式使用
109
+ getFontJson() {
110
+ const activeObject = this.canvas.getActiveObject();
111
+ if (activeObject) {
112
+ const json = activeObject.toJSON([
113
+ 'id',
114
+ 'gradientAngle',
115
+ 'selectable',
116
+ 'hasControls',
117
+ ]);
118
+ const fileStr = `data:text/json;charset=utf-8,${encodeURIComponent(
119
+ JSON.stringify(json, null, '\t')
120
+ )}`;
121
+ const dataUrl = activeObject.toDataURL({});
122
+ utils.downFile(fileStr, 'font.json');
123
+ utils.downFile(dataUrl, 'font.png');
124
+ }
125
+ }
126
+
127
+ loadFont(fontName: string) {
128
+ const font = new FontFaceObserver(fontName);
129
+ return font.load(null, 150000).then(() => {
130
+ const activeObject = this.canvas.getActiveObjects()[0];
131
+ if (activeObject) {
132
+ activeObject.set('fontFamily', fontName);
133
+ this.canvas.renderAll();
134
+ }
135
+ });
136
+ }
137
+
138
+ createFontCSS(arr: any[]) {
139
+ let code = '';
140
+ arr.forEach((item) => {
141
+ code =
142
+ code +
143
+ `
144
+ @font-face {
145
+ font-family: ${item.name};
146
+ src: url('${item.file}');
147
+ }
148
+ `;
149
+ });
150
+ const style = document.createElement('style');
151
+ try {
152
+ style.appendChild(document.createTextNode(code));
153
+ } catch (error) {
154
+ // style.styleSheet.cssText = code;
155
+ }
156
+ const head = document.getElementsByTagName('head')[0];
157
+ head.appendChild(style);
158
+ }
159
+
160
+ destroy() {
161
+ console.log('pluginDestroy');
162
+ }
163
+ }
164
+
165
+ export default FontPlugin;
@@ -0,0 +1,49 @@
1
+ import { fabric } from '@hprint/core';
2
+ import { v4 as uuid } from 'uuid';
3
+ import type { IEditor, IPluginTempl } from '@hprint/core';
4
+
5
+ type IPlugin = Pick<FreeDrawPlugin, 'startDraw' | 'endDraw'>;
6
+
7
+ declare module '@hprint/core' {
8
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
9
+ interface IEditor extends IPlugin {}
10
+ }
11
+
12
+ type DrawOptions = {
13
+ width: number;
14
+ };
15
+
16
+ export default class FreeDrawPlugin implements IPluginTempl {
17
+ static pluginName = 'FreeDrawPlugin';
18
+ static apis = ['startDraw', 'endDraw'];
19
+ constructor(
20
+ public canvas: fabric.Canvas,
21
+ public editor: IEditor
22
+ ) {}
23
+
24
+ _bindEvent() {
25
+ this.canvas.on('path:created', this._createdHandler);
26
+ }
27
+
28
+ _unbindEvent() {
29
+ this.canvas.off('path:created', this._createdHandler);
30
+ }
31
+
32
+ _createdHandler = (opt: any) => {
33
+ opt.path.set('id', uuid());
34
+ };
35
+
36
+ startDraw(options: DrawOptions) {
37
+ this.canvas.isDrawingMode = true;
38
+ this.canvas.freeDrawingBrush = new fabric.PencilBrush(this.canvas);
39
+ this.canvas.freeDrawingBrush.width = options.width;
40
+ this._bindEvent();
41
+ }
42
+ endDraw() {
43
+ if (this.canvas.isDrawingMode) {
44
+ this.canvas.isDrawingMode = false;
45
+ this._unbindEvent();
46
+ return;
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,365 @@
1
+ import { fabric } from '@hprint/core';
2
+ import type { IEditor, IPluginTempl } from '@hprint/core';
3
+
4
+ type IPlugin = Pick<
5
+ GroupAlignPlugin,
6
+ | 'left'
7
+ | 'right'
8
+ | 'xcenter'
9
+ | 'ycenter'
10
+ | 'top'
11
+ | 'bottom'
12
+ | 'xequation'
13
+ | 'yequation'
14
+ >;
15
+
16
+ declare module '@hprint/core' {
17
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
18
+ interface IEditor extends IPlugin {}
19
+ }
20
+
21
+ class GroupAlignPlugin implements IPluginTempl {
22
+ static pluginName = 'GroupAlignPlugin';
23
+ static apis = [
24
+ 'left',
25
+ 'right',
26
+ 'xcenter',
27
+ 'ycenter',
28
+ 'top',
29
+ 'bottom',
30
+ 'xequation',
31
+ 'yequation',
32
+ ];
33
+ // public hotkeys: string[] = ['space'];
34
+ constructor(
35
+ public canvas: fabric.Canvas,
36
+ public editor: IEditor
37
+ ) {}
38
+
39
+ left() {
40
+ const { canvas } = this;
41
+
42
+ const activeObject = canvas.getActiveObject();
43
+ const selectObjects = canvas.getActiveObjects();
44
+ if (activeObject) {
45
+ const { left = 0 } = activeObject;
46
+ canvas.discardActiveObject();
47
+ selectObjects.forEach((item) => {
48
+ const bounding = item.getBoundingRect(true);
49
+ item.set({
50
+ left: left - bounding.left + Number(item.left),
51
+ });
52
+ item.setCoords();
53
+ });
54
+ const activeSelection = new fabric.ActiveSelection(selectObjects, {
55
+ canvas: canvas,
56
+ });
57
+ canvas.setActiveObject(activeSelection);
58
+ canvas.requestRenderAll();
59
+ }
60
+ }
61
+
62
+ right() {
63
+ const { canvas } = this;
64
+
65
+ const activeObject = canvas.getActiveObject();
66
+ const selectObjects = canvas.getActiveObjects();
67
+ if (activeObject) {
68
+ const { left = 0, width = 0 } = activeObject;
69
+ canvas.discardActiveObject();
70
+ selectObjects.forEach((item) => {
71
+ const bounding = item.getBoundingRect(true);
72
+ item.set({
73
+ left:
74
+ left +
75
+ width -
76
+ (bounding.left + bounding.width) +
77
+ Number(item.left),
78
+ });
79
+ });
80
+ const activeSelection = new fabric.ActiveSelection(selectObjects, {
81
+ canvas: canvas,
82
+ });
83
+ canvas.setActiveObject(activeSelection);
84
+ canvas.requestRenderAll();
85
+ }
86
+ }
87
+
88
+ xcenter() {
89
+ const { canvas } = this;
90
+
91
+ const activeObject = canvas.getActiveObject();
92
+ const selectObjects = canvas.getActiveObjects();
93
+ if (activeObject) {
94
+ const { left = 0, width = 0 } = activeObject;
95
+ canvas.discardActiveObject();
96
+ selectObjects.forEach((item) => {
97
+ const bounding = item.getBoundingRect(true);
98
+ item.set({
99
+ left:
100
+ left +
101
+ width / 2 -
102
+ (bounding.left + bounding.width / 2) +
103
+ Number(item.left),
104
+ });
105
+ });
106
+ const activeSelection = new fabric.ActiveSelection(selectObjects, {
107
+ canvas: canvas,
108
+ });
109
+ canvas.setActiveObject(activeSelection);
110
+ canvas.requestRenderAll();
111
+ }
112
+ }
113
+
114
+ ycenter() {
115
+ const { canvas } = this;
116
+
117
+ const activeObject = canvas.getActiveObject();
118
+ const selectObjects = canvas.getActiveObjects();
119
+ if (activeObject) {
120
+ const { top = 0, height = 0 } = activeObject;
121
+ canvas.discardActiveObject();
122
+ selectObjects.forEach((item) => {
123
+ const bounding = item.getBoundingRect(true);
124
+ item.set({
125
+ top:
126
+ top +
127
+ height / 2 -
128
+ (bounding.top + bounding.height / 2) +
129
+ Number(item.top),
130
+ });
131
+ });
132
+ const activeSelection = new fabric.ActiveSelection(selectObjects, {
133
+ canvas: canvas,
134
+ });
135
+ canvas.setActiveObject(activeSelection);
136
+ canvas.requestRenderAll();
137
+ }
138
+ }
139
+
140
+ top() {
141
+ const { canvas } = this;
142
+
143
+ const activeObject = canvas.getActiveObject();
144
+ const selectObjects = canvas.getActiveObjects();
145
+ if (activeObject) {
146
+ const { top = 0 } = activeObject;
147
+ canvas.discardActiveObject();
148
+ selectObjects.forEach((item) => {
149
+ const bounding = item.getBoundingRect(true);
150
+ item.set({
151
+ top: top - bounding.top + Number(item.top),
152
+ });
153
+ });
154
+ const activeSelection = new fabric.ActiveSelection(selectObjects, {
155
+ canvas: canvas,
156
+ });
157
+ canvas.setActiveObject(activeSelection);
158
+ canvas.requestRenderAll();
159
+ }
160
+ }
161
+
162
+ bottom() {
163
+ const { canvas } = this;
164
+
165
+ const activeObject = canvas.getActiveObject();
166
+ const selectObjects = canvas.getActiveObjects();
167
+ if (activeObject) {
168
+ const { top = 0, height = 0 } = activeObject;
169
+ canvas.discardActiveObject();
170
+ selectObjects.forEach((item) => {
171
+ const bounding = item.getBoundingRect(true);
172
+ item.set({
173
+ top:
174
+ top +
175
+ height -
176
+ (bounding.top + bounding.height) +
177
+ Number(item.top),
178
+ });
179
+ });
180
+ const activeSelection = new fabric.ActiveSelection(selectObjects, {
181
+ canvas: canvas,
182
+ });
183
+ canvas.setActiveObject(activeSelection);
184
+ canvas.requestRenderAll();
185
+ }
186
+ }
187
+
188
+ xequation() {
189
+ const { canvas } = this;
190
+ const activeObject = canvas.getActiveObject() as fabric.ActiveSelection;
191
+ // width属性不准确,需要坐标换算
192
+ function getItemWidth(item: fabric.Object) {
193
+ let x1 = Infinity,
194
+ x2 = -Infinity;
195
+ for (const key in item.aCoords) {
196
+ if (item.aCoords[key].x < x1) {
197
+ x1 = item.aCoords[key].x;
198
+ }
199
+ if (item.aCoords[key].x > x2) {
200
+ x2 = item.aCoords[key].x;
201
+ }
202
+ }
203
+ return x2 - x1;
204
+ }
205
+
206
+ // 获取所有元素高度
207
+ function getAllItemHeight() {
208
+ let count = 0;
209
+ if (activeObject) {
210
+ activeObject.forEachObject((item: fabric.Object) => {
211
+ count += getItemWidth(item);
212
+ });
213
+ }
214
+
215
+ return count;
216
+ }
217
+ // 获取平均间距
218
+ function spacWidth() {
219
+ const count = getAllItemHeight();
220
+ if (activeObject) {
221
+ const allSpac = Number(activeObject.width) - count;
222
+ return allSpac / (activeObject._objects.length - 1);
223
+ }
224
+ }
225
+
226
+ // 获取当前元素之前所有元素的高度
227
+ function getItemLeft(i: number) {
228
+ if (i === 0) return 0;
229
+ let width = 0;
230
+ if (activeObject) {
231
+ for (let index = 0; index < i; index++) {
232
+ width += getItemWidth(activeObject._objects[index]);
233
+ }
234
+ }
235
+
236
+ return width;
237
+ }
238
+ if (activeObject && activeObject.type === 'activeSelection') {
239
+ const activeSelection = activeObject;
240
+ // 排序
241
+ activeSelection._objects.sort((a, b) => a.left - b.left);
242
+
243
+ // 平均间距计算
244
+ const itemSpac = spacWidth() as number;
245
+ // 组原点高度
246
+ const yHeight = Number(activeObject.width) / 2;
247
+
248
+ activeObject.forEachObject((item: fabric.Object, i: number) => {
249
+ // 获取当前元素之前所有元素的高度
250
+ const preHeight = getItemLeft(i);
251
+ // 顶部距离 间距 * 索引 + 之前元素高度 - 原点高度
252
+ const top = itemSpac * i + preHeight - yHeight;
253
+ item.set('left', top);
254
+ });
255
+ }
256
+
257
+ const objecs = canvas.getActiveObjects();
258
+ canvas.discardActiveObject();
259
+ objecs.forEach((item: fabric.Object) => {
260
+ let x = Infinity;
261
+ for (const key in item.aCoords) {
262
+ if (item.aCoords[key].x < x) {
263
+ x = item.aCoords[key].x;
264
+ }
265
+ }
266
+ item.set('left', 2 * item.left - x);
267
+ });
268
+
269
+ const sel = new fabric.ActiveSelection(objecs, {
270
+ canvas: canvas,
271
+ });
272
+ canvas.setActiveObject(sel);
273
+ canvas.requestRenderAll();
274
+ }
275
+
276
+ yequation() {
277
+ const { canvas } = this;
278
+ const activeObject =
279
+ (canvas.getActiveObject() as fabric.ActiveSelection) || {
280
+ top: 0,
281
+ height: 0,
282
+ };
283
+ // width属性不准确,需要坐标换算
284
+ function getItemHeight(item: fabric.Object) {
285
+ let y1 = Infinity,
286
+ y2 = -Infinity;
287
+ for (const key in item.aCoords) {
288
+ if (item.aCoords[key].y < y1) {
289
+ y1 = item.aCoords[key].y;
290
+ }
291
+ if (item.aCoords[key].y > y2) {
292
+ y2 = item.aCoords[key].y;
293
+ }
294
+ }
295
+ return y2 - y1;
296
+ }
297
+ // 获取所有元素高度
298
+ function getAllItemHeight() {
299
+ let count = 0;
300
+ activeObject.forEachObject((item: fabric.Object) => {
301
+ count += getItemHeight(item);
302
+ });
303
+ return count;
304
+ }
305
+ // 获取平均间距
306
+ function spacHeight() {
307
+ const count = getAllItemHeight();
308
+ const allSpac = activeObject.height - count;
309
+ return allSpac / (activeObject._objects.length - 1);
310
+ }
311
+
312
+ // 获取当前元素之前所有元素的高度
313
+ function getItemTop(i: number) {
314
+ if (i === 0) return 0;
315
+ let height = 0;
316
+ for (let index = 0; index < i; index++) {
317
+ height += getItemHeight(activeObject._objects[index]);
318
+ }
319
+ return height;
320
+ }
321
+
322
+ if (activeObject && activeObject.type === 'activeSelection') {
323
+ const activeSelection = activeObject;
324
+ // 排序
325
+ activeSelection._objects.sort((a, b) => a.top - b.top);
326
+
327
+ // 平均间距计算
328
+ const itemSpac = spacHeight();
329
+ // 组原点高度
330
+ const yHeight = Number(activeObject.height) / 2;
331
+
332
+ activeObject.forEachObject((item: fabric.Object, i: number) => {
333
+ // 获取当前元素之前所有元素的高度
334
+ const preHeight = getItemTop(i);
335
+ // 顶部距离 间距 * 索引 + 之前元素高度 - 原点高度
336
+ const top = itemSpac * i + preHeight - yHeight;
337
+ item.set('top', top);
338
+ });
339
+ }
340
+
341
+ const objecs = canvas.getActiveObjects();
342
+ canvas.discardActiveObject();
343
+ objecs.forEach((item) => {
344
+ let y = Infinity;
345
+ for (const key in item.aCoords) {
346
+ if (item.aCoords[key].y < y) {
347
+ y = item.aCoords[key].y;
348
+ }
349
+ }
350
+ item.set('top', 2 * item.top - y);
351
+ });
352
+
353
+ const sel = new fabric.ActiveSelection(objecs, {
354
+ canvas: canvas,
355
+ });
356
+ canvas.setActiveObject(sel);
357
+ canvas.requestRenderAll();
358
+ }
359
+
360
+ destroy() {
361
+ console.log('pluginDestroy');
362
+ }
363
+ }
364
+
365
+ export default GroupAlignPlugin;
@@ -0,0 +1,82 @@
1
+ import { fabric } from '@hprint/core';
2
+ import { utils } from '@hprint/shared';
3
+ import { v4 as uuid } from 'uuid';
4
+ import type { IEditor, IPluginTempl } from '@hprint/core';
5
+
6
+ type IPlugin = Pick<GroupPlugin, 'unGroup' | 'group'>;
7
+
8
+ declare module '@hprint/core' {
9
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
10
+ interface IEditor extends IPlugin {}
11
+ }
12
+
13
+ class GroupPlugin implements IPluginTempl {
14
+ static pluginName = 'GroupPlugin';
15
+ static apis = ['unGroup', 'group'];
16
+ constructor(
17
+ public canvas: fabric.Canvas,
18
+ public editor: IEditor
19
+ ) {}
20
+
21
+ // 拆分组
22
+ unGroup() {
23
+ const activeObject = this.canvas.getActiveObject() as fabric.Group;
24
+ if (!activeObject) return;
25
+ // 先获取当前选中的对象,然后打散
26
+ const activeObjectList = activeObject.getObjects();
27
+ activeObject.toActiveSelection();
28
+ for (const item of activeObjectList) {
29
+ item.set('id', uuid());
30
+ }
31
+ this.canvas.discardActiveObject().renderAll();
32
+ }
33
+
34
+ group() {
35
+ // 组合元素
36
+ const activeObj =
37
+ this.canvas.getActiveObject() as fabric.ActiveSelection;
38
+ if (!activeObj) return;
39
+ const activegroup = activeObj.toGroup();
40
+ const objectsInGroup = activegroup.getObjects();
41
+ activegroup.clone((newgroup: fabric.Group) => {
42
+ newgroup.set('id', uuid());
43
+ this.canvas.remove(activegroup);
44
+ objectsInGroup.forEach((object) => {
45
+ this.canvas.remove(object);
46
+ });
47
+ this.canvas.add(newgroup);
48
+ this.canvas.setActiveObject(newgroup);
49
+ });
50
+ }
51
+
52
+ contextMenu() {
53
+ const activeObject = this.canvas.getActiveObject();
54
+
55
+ if (utils.isActiveSelection(activeObject)) {
56
+ return [
57
+ {
58
+ text: '组合',
59
+ hotkey: 'Ctrl+V',
60
+ disabled: false,
61
+ onclick: () => this.group(),
62
+ },
63
+ ];
64
+ }
65
+
66
+ if (utils.isGroup(activeObject)) {
67
+ return [
68
+ {
69
+ text: '拆分组合',
70
+ hotkey: 'Ctrl+V',
71
+ disabled: false,
72
+ onclick: () => this.unGroup(),
73
+ },
74
+ ];
75
+ }
76
+ }
77
+ destroy() {
78
+ console.log('pluginDestroy');
79
+ }
80
+ }
81
+
82
+ export default GroupPlugin;