@hprint/shared 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.
@@ -0,0 +1,6 @@
1
+ import { default as LengthConvert } from './lengthConvert';
2
+ import { default as mathHelper } from './mathHelper';
3
+ import { default as utils } from './utils';
4
+ import { fabric } from 'fabric';
5
+ export { LengthConvert, mathHelper, utils, fabric };
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,OAAO,UAAU,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC"}
@@ -0,0 +1,90 @@
1
+ export default class LengthConvert {
2
+ static devicePixelRatio: number;
3
+ static _deviceDPI: number | null;
4
+ static CONSTANTS: {
5
+ INCH_TO_MM: number;
6
+ DEFAULT_DPI: number;
7
+ STANDARD_DPI: {
8
+ SCREEN: number;
9
+ PRINT: number;
10
+ HIGH_RES: number;
11
+ };
12
+ };
13
+ /**
14
+ * 获取设备DPI(缓存结果避免重复计算)
15
+ */
16
+ static getDeviceDPI(): number;
17
+ /**
18
+ * 毫米转像素
19
+ * @param {number|string} mm - 毫米值
20
+ * @param {number|string} [dpi] - DPI值
21
+ * @param {object} [options] - 可选参数 { direct: true } 是否允许非整数
22
+ * @returns {number} 像素值
23
+ */
24
+ static mmToPx(mm: number | string, dpi?: number, options?: {
25
+ direct?: boolean;
26
+ }): number;
27
+ /**
28
+ * 像素转毫米
29
+ * @param {number|string} px - 像素值
30
+ * @param {number|string} [dpi] - DPI值
31
+ * @param {object} [options] - 可选参数
32
+ * @returns {number} 毫米值
33
+ */
34
+ static pxToMm(px: number | string, dpi?: number, options?: unknown): number;
35
+ /**
36
+ * 批量转换毫米到像素
37
+ */
38
+ static mmToPxBatch(mmArray: Array<number | string>, dpi?: number): number[];
39
+ /**
40
+ * 批量转换像素到毫米
41
+ */
42
+ static pxToMmBatch(pxArray: Array<number | string>, dpi?: number): number[];
43
+ static getValidDpi(dpi?: number): number;
44
+ /**
45
+ * 规范化数字输入(支持字符串和数字)
46
+ * @param {number|string} value - 输入值
47
+ * @param {string} name - 参数名称(用于错误提示)
48
+ * @returns {number} 规范化后的数字
49
+ */
50
+ static normalizeNumber(value: number | string, name: string): number;
51
+ static validateNumber(value: number | string, name: string): void;
52
+ static resetCache(): void;
53
+ /**
54
+ * pt(磅)转 px(像素)
55
+ * @param {number|string} pt - 磅值
56
+ * @param {object} [options] - 可选参数 { direct: true } 是否允许非整数
57
+ * @returns {number} 像素值
58
+ */
59
+ static ptToPx(pt: number | string, options?: {
60
+ direct?: boolean;
61
+ }): number;
62
+ /**
63
+ * px(像素)转 pt(磅)
64
+ * @param {number|string} px - 像素值
65
+ * @returns {number} 磅值
66
+ */
67
+ static pxToPt(px: number | string): number;
68
+ /**
69
+ * 批量pt转px
70
+ * @param {number[]} ptArray
71
+ * @param {object} [options]
72
+ * @returns {number[]}
73
+ */
74
+ static ptToPxBatch(ptArray: Array<number | string>, options?: {
75
+ direct?: boolean;
76
+ }): number[];
77
+ /**
78
+ * 批量px转pt
79
+ * @param {number[]} pxArray
80
+ * @returns {number[]}
81
+ */
82
+ static pxToPtBatch(pxArray: Array<number | string>): number[];
83
+ /**
84
+ * 毫米转磅(pt)
85
+ * @param {number|string} mm - 毫米值
86
+ * @returns {number} 磅值
87
+ */
88
+ static mmToPt(mm: number | string): number;
89
+ }
90
+ //# sourceMappingURL=lengthConvert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lengthConvert.d.ts","sourceRoot":"","sources":["../../src/lengthConvert.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,OAAO,aAAa;IAC9B,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAA2B;IAC1D,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,SAAS;;;;;;;;MAQd;IAEF;;OAEG;IACH,MAAM,CAAC,YAAY,IAAI,MAAM;IA2B7B;;;;;;OAMG;IACH,MAAM,CAAC,MAAM,CACT,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,GAAG,CAAC,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC/B,MAAM;IAQT;;;;;;OAMG;IACH,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM;IAM3E;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAI3E;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAK3E,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM;IAexC;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAkBpE,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAKjE,MAAM,CAAC,UAAU;IAIjB;;;;;OAKG;IACH,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM;IAQ1E;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM;IAO1C;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CACd,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,EAC/B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC/B,MAAM,EAAE;IAIX;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,EAAE;IAI7D;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM;CAM7C"}
@@ -0,0 +1,8 @@
1
+ declare const _default: {
2
+ getPolygonVertices: (edges: number, radius: number) => {
3
+ x: number;
4
+ y: number;
5
+ }[];
6
+ };
7
+ export default _default;
8
+ //# sourceMappingURL=mathHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mathHelper.d.ts","sourceRoot":"","sources":["../../src/mathHelper.ts"],"names":[],"mappings":";gCAMmC,MAAM,UAAU,MAAM;;;;;AAkBzD,wBAAsC"}
@@ -0,0 +1,62 @@
1
+ import { useClipboard } from '@vueuse/core';
2
+ import { fabric } from 'fabric';
3
+ /**
4
+ * @description: 图片文件转字符串
5
+ * @param {Blob|File} file 文件
6
+ * @return {String}
7
+ */
8
+ export declare function getImgStr(file: File | Blob): Promise<FileReader['result']>;
9
+ /**
10
+ * @description: 选择文件
11
+ * @param {Object} options accept = '', capture = '', multiple = false
12
+ * @return {Promise}
13
+ */
14
+ export declare function selectFiles(options: {
15
+ accept?: string;
16
+ capture?: string;
17
+ multiple?: boolean;
18
+ }): Promise<FileList | null>;
19
+ /**
20
+ * @description: 创建图片元素
21
+ * @param {String} str 图片地址或者base64图片
22
+ * @return {Promise} element 图片元素
23
+ */
24
+ export declare function insertImgFile(str: string): Promise<unknown>;
25
+ /**
26
+ * Copying text to the clipboard
27
+ * @param source Copy source
28
+ * @param options Copy options
29
+ * @returns Promise that resolves when the text is copied successfully, or rejects when the copy fails.
30
+ */
31
+ export declare const clipboardText: (source: string, options?: Parameters<typeof useClipboard>[0]) => Promise<void>;
32
+ export declare function downFile(fileStr: string, fileType: string): void;
33
+ export declare function drawImg(ctx: CanvasRenderingContext2D, left: number, top: number, img: HTMLImageElement, wSize: number, hSize: number, angle: number | undefined): void;
34
+ export declare function shiftAngle(start: fabric.Point, end: fabric.Point): {
35
+ x: number;
36
+ y: number;
37
+ };
38
+ /**
39
+ * 类型工具
40
+ */
41
+ export declare const isImage: (thing: unknown) => thing is fabric.Image;
42
+ export declare const isGroup: (thing: unknown) => thing is fabric.Group;
43
+ export declare const isIText: (thing: unknown) => thing is fabric.IText;
44
+ export declare const isActiveSelection: (thing: unknown) => thing is fabric.ActiveSelection;
45
+ export declare function blobToBase64(blob: Blob): Promise<unknown>;
46
+ export declare function base64ToBlob(base64Data: string): (string | Blob)[] | null;
47
+ declare const _default: {
48
+ getImgStr: typeof getImgStr;
49
+ downFile: typeof downFile;
50
+ selectFiles: typeof selectFiles;
51
+ insertImgFile: typeof insertImgFile;
52
+ clipboardText: (source: string, options?: Parameters<typeof useClipboard>[0]) => Promise<void>;
53
+ drawImg: typeof drawImg;
54
+ isImage: (thing: unknown) => thing is fabric.Image;
55
+ isGroup: (thing: unknown) => thing is fabric.Group;
56
+ isIText: (thing: unknown) => thing is fabric.IText;
57
+ isActiveSelection: (thing: unknown) => thing is fabric.ActiveSelection;
58
+ blobToBase64: typeof blobToBase64;
59
+ base64ToBlob: typeof base64ToBlob;
60
+ };
61
+ export default _default;
62
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAA4B,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAE1E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAQ3B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,oBAUxC;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACtB,QAAQ,MAAM,EACd,UAAU,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,kBAG/C,CAAC;AAEF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAOzD;AAED,wBAAgB,OAAO,CACnB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GAAG,SAAS,QAQ5B;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK;;;EAgBhE;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,KAExD,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,KAExD,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,KAExD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC1B,OAAO,OAAO,KACf,KAAK,IAAI,MAAM,CAAC,eAElB,CAAC;AAEF,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,oBAQtC;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,4BAa9C;;;;;;4BA9FW,MAAM,YACJ,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;;qBAoDjB,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,KAAK;qBAI/B,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,KAAK;qBAI/B,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,KAAK;+BAKnD,OAAO,KACf,KAAK,IAAI,MAAM,CAAC,eAAe;;;;AA6BlC,wBAaE"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@hprint/shared",
3
+ "version": "0.0.1-alpha.0",
4
+ "description": "",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "vite build",
17
+ "clean": "node -e \"require('fs').rmSync('dist', {recursive: true, force: true})\"",
18
+ "type-check": "tsc --noEmit",
19
+ "watch": "vite build --watch",
20
+ "test": "echo \"Error: no test specified\" && exit 1"
21
+ },
22
+ "devDependencies": {
23
+ "@types/fabric": "~5.3.10",
24
+ "rimraf": "^6.1.2",
25
+ "vite": "^7.2.4",
26
+ "vite-plugin-dts": "^4.5.4"
27
+ },
28
+ "keywords": [],
29
+ "author": "george-hong",
30
+ "license": "ISC",
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "packageManager": "pnpm@10.20.0",
35
+ "dependencies": {
36
+ "@types/uuid": "~8.3.4",
37
+ "@vueuse/core": "~10.11.1",
38
+ "fabric": "~5.3.0",
39
+ "uuid": "~8.3.2"
40
+ }
41
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ import LengthConvert from './lengthConvert';
2
+ import mathHelper from './mathHelper';
3
+ import utils from './utils';
4
+ import { fabric } from 'fabric';
5
+
6
+ export { LengthConvert, mathHelper, utils, fabric };
@@ -0,0 +1,198 @@
1
+ export default class LengthConvert {
2
+ static devicePixelRatio: number = window.devicePixelRatio;
3
+ static _deviceDPI: number | null;
4
+ static CONSTANTS = {
5
+ INCH_TO_MM: 25.4,
6
+ DEFAULT_DPI: 96,
7
+ STANDARD_DPI: {
8
+ SCREEN: 96,
9
+ PRINT: 300,
10
+ HIGH_RES: 600,
11
+ },
12
+ };
13
+
14
+ /**
15
+ * 获取设备DPI(缓存结果避免重复计算)
16
+ */
17
+ static getDeviceDPI(): number {
18
+ if (!this._deviceDPI) {
19
+ try {
20
+ const element = document.createElement('div');
21
+ element.style.width = '1in';
22
+ element.style.height = '0';
23
+ element.style.position = 'absolute';
24
+ element.style.visibility = 'hidden';
25
+
26
+ document.body.appendChild(element);
27
+ const cssPixels = element.offsetWidth;
28
+ document.body.removeChild(element);
29
+
30
+ this._deviceDPI =
31
+ cssPixels * window.devicePixelRatio ||
32
+ this.CONSTANTS.DEFAULT_DPI;
33
+ } catch (error) {
34
+ console.warn(
35
+ '无法获取设备DPI,使用默认值:',
36
+ this.CONSTANTS.DEFAULT_DPI
37
+ );
38
+ this._deviceDPI = this.CONSTANTS.DEFAULT_DPI;
39
+ }
40
+ }
41
+ return this._deviceDPI;
42
+ }
43
+
44
+ /**
45
+ * 毫米转像素
46
+ * @param {number|string} mm - 毫米值
47
+ * @param {number|string} [dpi] - DPI值
48
+ * @param {object} [options] - 可选参数 { direct: true } 是否允许非整数
49
+ * @returns {number} 像素值
50
+ */
51
+ static mmToPx(
52
+ mm: number | string,
53
+ dpi?: number,
54
+ options?: { direct?: boolean }
55
+ ): number {
56
+ const normalizedMm = this.normalizeNumber(mm, '毫米值');
57
+ const currentDpi = this.getValidDpi(dpi);
58
+ const directValue =
59
+ (normalizedMm * currentDpi) / this.CONSTANTS.INCH_TO_MM;
60
+ return options?.direct ? directValue : Math.ceil(directValue);
61
+ }
62
+
63
+ /**
64
+ * 像素转毫米
65
+ * @param {number|string} px - 像素值
66
+ * @param {number|string} [dpi] - DPI值
67
+ * @param {object} [options] - 可选参数
68
+ * @returns {number} 毫米值
69
+ */
70
+ static pxToMm(px: number | string, dpi?: number, options?: unknown): number {
71
+ const normalizedPx = this.normalizeNumber(px, '像素值');
72
+ const currentDpi = this.getValidDpi(dpi);
73
+ return (normalizedPx * this.CONSTANTS.INCH_TO_MM) / currentDpi;
74
+ }
75
+
76
+ /**
77
+ * 批量转换毫米到像素
78
+ */
79
+ static mmToPxBatch(mmArray: Array<number | string>, dpi?: number): number[] {
80
+ return mmArray.map((mm) => this.mmToPx(mm, dpi, undefined));
81
+ }
82
+
83
+ /**
84
+ * 批量转换像素到毫米
85
+ */
86
+ static pxToMmBatch(pxArray: Array<number | string>, dpi?: number): number[] {
87
+ return pxArray.map((px) => this.pxToMm(px, dpi, undefined));
88
+ }
89
+
90
+ // 私有方法
91
+ static getValidDpi(dpi?: number): number {
92
+ if (dpi !== undefined && dpi !== null) {
93
+ const normalizedDpi = this.normalizeNumber(dpi, 'DPI值');
94
+ if (normalizedDpi <= 0) {
95
+ throw new Error('DPI值必须大于0');
96
+ }
97
+ return normalizedDpi;
98
+ }
99
+ const deviceDpi = this.getDeviceDPI();
100
+ if (deviceDpi <= 0) {
101
+ throw new Error('DPI值必须大于0');
102
+ }
103
+ return deviceDpi;
104
+ }
105
+
106
+ /**
107
+ * 规范化数字输入(支持字符串和数字)
108
+ * @param {number|string} value - 输入值
109
+ * @param {string} name - 参数名称(用于错误提示)
110
+ * @returns {number} 规范化后的数字
111
+ */
112
+ static normalizeNumber(value: number | string, name: string): number {
113
+ if (typeof value === 'string') {
114
+ const trimmed = value.trim();
115
+ if (trimmed === '') {
116
+ throw new Error(`${name}不能为空字符串`);
117
+ }
118
+ const num = Number(trimmed);
119
+ if (isNaN(num)) {
120
+ throw new Error(`${name}必须是有效数字,无法转换: "${value}"`);
121
+ }
122
+ return num;
123
+ }
124
+ if (typeof value !== 'number' || isNaN(value)) {
125
+ throw new Error(`${name}必须是有效数字`);
126
+ }
127
+ return value;
128
+ }
129
+
130
+ static validateNumber(value: number | string, name: string): void {
131
+ this.normalizeNumber(value, name);
132
+ }
133
+
134
+ // 重置设备DPI缓存(用于响应设备变化)
135
+ static resetCache() {
136
+ this._deviceDPI = null;
137
+ }
138
+
139
+ /**
140
+ * pt(磅)转 px(像素)
141
+ * @param {number|string} pt - 磅值
142
+ * @param {object} [options] - 可选参数 { direct: true } 是否允许非整数
143
+ * @returns {number} 像素值
144
+ */
145
+ static ptToPx(pt: number | string, options?: { direct?: boolean }): number {
146
+ const normalizedPt = this.normalizeNumber(pt, '磅值');
147
+ const currentDpi = this.getValidDpi(undefined);
148
+ // 1英寸 = 72pt,所以 px = pt * dpi / 72
149
+ const directValue = (normalizedPt * currentDpi) / 72;
150
+ return options?.direct ? directValue : Math.ceil(directValue);
151
+ }
152
+
153
+ /**
154
+ * px(像素)转 pt(磅)
155
+ * @param {number|string} px - 像素值
156
+ * @returns {number} 磅值
157
+ */
158
+ static pxToPt(px: number | string): number {
159
+ const normalizedPx = this.normalizeNumber(px, '像素值');
160
+ const currentDpi = this.getValidDpi(undefined);
161
+ // 1英寸 = 72pt,所以 pt = px * 72 / dpi
162
+ return (normalizedPx * 72) / currentDpi;
163
+ }
164
+
165
+ /**
166
+ * 批量pt转px
167
+ * @param {number[]} ptArray
168
+ * @param {object} [options]
169
+ * @returns {number[]}
170
+ */
171
+ static ptToPxBatch(
172
+ ptArray: Array<number | string>,
173
+ options?: { direct?: boolean }
174
+ ): number[] {
175
+ return ptArray.map((pt) => this.ptToPx(pt, options));
176
+ }
177
+
178
+ /**
179
+ * 批量px转pt
180
+ * @param {number[]} pxArray
181
+ * @returns {number[]}
182
+ */
183
+ static pxToPtBatch(pxArray: Array<number | string>): number[] {
184
+ return pxArray.map((px) => this.pxToPt(px));
185
+ }
186
+
187
+ /**
188
+ * 毫米转磅(pt)
189
+ * @param {number|string} mm - 毫米值
190
+ * @returns {number} 磅值
191
+ */
192
+ static mmToPt(mm: number | string): number {
193
+ // 毫米转磅(pt)
194
+ // 1英寸 = 25.4毫米,1英寸 = 72pt,所以 1毫米 = 72/25.4 pt
195
+ const normalizedMm = this.normalizeNumber(mm, '毫米值');
196
+ return (normalizedMm * 72) / 25.4;
197
+ }
198
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 获取多边形顶点坐标
3
+ * @param edges 变数
4
+ * @param radius 半径
5
+ * @returns 坐标数组
6
+ */
7
+ const getPolygonVertices = (edges: number, radius: number) => {
8
+ const vertices = [];
9
+ const interiorAngle = (Math.PI * 2) / edges;
10
+ let rotationAdjustment = -Math.PI / 2;
11
+ if (edges % 2 === 0) {
12
+ rotationAdjustment += interiorAngle / 2;
13
+ }
14
+ for (let i = 0; i < edges; i++) {
15
+ // 画圆取顶点坐标
16
+ const rad = i * interiorAngle + rotationAdjustment;
17
+ vertices.push({
18
+ x: Math.cos(rad) * radius,
19
+ y: Math.sin(rad) * radius,
20
+ });
21
+ }
22
+ return vertices;
23
+ };
24
+
25
+ export default { getPolygonVertices };
package/src/utils.ts ADDED
@@ -0,0 +1,166 @@
1
+ import { v4 as uuid } from 'uuid';
2
+ import { useClipboard, useFileDialog, useBase64 } from '@vueuse/core';
3
+ import { fabric } from 'fabric';
4
+
5
+ /**
6
+ * @description: 图片文件转字符串
7
+ * @param {Blob|File} file 文件
8
+ * @return {String}
9
+ */
10
+ export function getImgStr(file: File | Blob): Promise<FileReader['result']> {
11
+ return useBase64(file).promise.value;
12
+ }
13
+
14
+ /**
15
+ * @description: 选择文件
16
+ * @param {Object} options accept = '', capture = '', multiple = false
17
+ * @return {Promise}
18
+ */
19
+ export function selectFiles(options: {
20
+ accept?: string;
21
+ capture?: string;
22
+ multiple?: boolean;
23
+ }): Promise<FileList | null> {
24
+ return new Promise((resolve) => {
25
+ const { onChange, open } = useFileDialog(options);
26
+ onChange((files) => {
27
+ resolve(files);
28
+ });
29
+ open();
30
+ });
31
+ }
32
+
33
+ /**
34
+ * @description: 创建图片元素
35
+ * @param {String} str 图片地址或者base64图片
36
+ * @return {Promise} element 图片元素
37
+ */
38
+ export function insertImgFile(str: string) {
39
+ return new Promise((resolve) => {
40
+ const imgEl = document.createElement('img');
41
+ imgEl.src = str;
42
+ // 插入页面
43
+ document.body.appendChild(imgEl);
44
+ imgEl.onload = () => {
45
+ resolve(imgEl);
46
+ };
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Copying text to the clipboard
52
+ * @param source Copy source
53
+ * @param options Copy options
54
+ * @returns Promise that resolves when the text is copied successfully, or rejects when the copy fails.
55
+ */
56
+ export const clipboardText = (
57
+ source: string,
58
+ options?: Parameters<typeof useClipboard>[0]
59
+ ) => {
60
+ return useClipboard({ source, ...options }).copy();
61
+ };
62
+
63
+ export function downFile(fileStr: string, fileType: string) {
64
+ const anchorEl = document.createElement('a');
65
+ anchorEl.href = fileStr;
66
+ anchorEl.download = `${uuid()}.${fileType}`;
67
+ document.body.appendChild(anchorEl); // required for firefox
68
+ anchorEl.click();
69
+ anchorEl.remove();
70
+ }
71
+
72
+ export function drawImg(
73
+ ctx: CanvasRenderingContext2D,
74
+ left: number,
75
+ top: number,
76
+ img: HTMLImageElement,
77
+ wSize: number,
78
+ hSize: number,
79
+ angle: number | undefined
80
+ ) {
81
+ if (angle === undefined) return;
82
+ ctx.save();
83
+ ctx.translate(left, top);
84
+ ctx.rotate(angle);
85
+ ctx.drawImage(img, -wSize / 2, -hSize / 2, wSize, hSize);
86
+ ctx.restore();
87
+ }
88
+
89
+ export function shiftAngle(start: fabric.Point, end: fabric.Point) {
90
+ const startX = start.x;
91
+ const startY = start.y;
92
+ const x2 = end.x - startX;
93
+ const y2 = end.y - startY;
94
+ const r = Math.sqrt(x2 * x2 + y2 * y2);
95
+ let angle = (Math.atan2(y2, x2) / Math.PI) * 180;
96
+ angle = ~~(((angle + 7.5) % 360) / 15) * 15;
97
+
98
+ const cosx = r * Math.cos((angle * Math.PI) / 180);
99
+ const sinx = r * Math.sin((angle * Math.PI) / 180);
100
+
101
+ return {
102
+ x: cosx + startX,
103
+ y: sinx + startY,
104
+ };
105
+ }
106
+
107
+ /**
108
+ * 类型工具
109
+ */
110
+ export const isImage = (thing: unknown): thing is fabric.Image => {
111
+ return thing instanceof fabric.Image;
112
+ };
113
+
114
+ export const isGroup = (thing: unknown): thing is fabric.Group => {
115
+ return thing instanceof fabric.Group;
116
+ };
117
+
118
+ export const isIText = (thing: unknown): thing is fabric.IText => {
119
+ return thing instanceof fabric.IText;
120
+ };
121
+
122
+ export const isActiveSelection = (
123
+ thing: unknown
124
+ ): thing is fabric.ActiveSelection => {
125
+ return thing instanceof fabric.ActiveSelection;
126
+ };
127
+
128
+ export function blobToBase64(blob: Blob) {
129
+ return new Promise((resolve) => {
130
+ const reader = new FileReader();
131
+ reader.addEventListener('load', () => {
132
+ resolve(reader.result as string);
133
+ });
134
+ reader.readAsDataURL(blob);
135
+ });
136
+ }
137
+
138
+ export function base64ToBlob(base64Data: string) {
139
+ if (!base64Data) {
140
+ return null;
141
+ }
142
+ const dataArr = base64Data.split(',');
143
+ const imageType = dataArr[0].match(/:(.*?);/)![1];
144
+ const textData = window.atob(dataArr[1]);
145
+ const arrayBuffer = new ArrayBuffer(textData.length);
146
+ const uint8Array = new Uint8Array(arrayBuffer);
147
+ for (let i = 0; i < textData.length; i++) {
148
+ uint8Array[i] = textData.charCodeAt(i);
149
+ }
150
+ return [new Blob([arrayBuffer], { type: imageType }), imageType.slice(6)];
151
+ }
152
+
153
+ export default {
154
+ getImgStr,
155
+ downFile,
156
+ selectFiles,
157
+ insertImgFile,
158
+ clipboardText,
159
+ drawImg,
160
+ isImage,
161
+ isGroup,
162
+ isIText,
163
+ isActiveSelection,
164
+ blobToBase64,
165
+ base64ToBlob,
166
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./",
6
+ "composite": true
7
+ },
8
+ "include": ["**/*.ts"],
9
+ "exclude": ["node_modules", "dist"]
10
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,29 @@
1
+ import { defineConfig } from 'vite';
2
+ import { resolve } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import dts from 'vite-plugin-dts';
5
+
6
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
7
+
8
+ export default defineConfig({
9
+ plugins: [
10
+ dts({
11
+ outDir: 'dist',
12
+ include: ['src/**/*'],
13
+ }),
14
+ ],
15
+ build: {
16
+ lib: {
17
+ entry: resolve(__dirname, 'src/index.ts'),
18
+ name: '@hprint/shared',
19
+ fileName: 'index',
20
+ formats: ['es', 'cjs'],
21
+ },
22
+ rollupOptions: {
23
+ external: [],
24
+ output: {
25
+ globals: {},
26
+ },
27
+ },
28
+ },
29
+ });