zhangxiao
2024-08-20 e47b788ff5f5c699c682999c95da17eb284ca21d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import html2canvas from "html2canvas";
 
export function htmlCanvas(domId: string): Promise<{ file: any }> {
    return new Promise((resolve, reject) => {
        const element = document.getElementById(domId);
        if (!element) {
            reject("htmlCanvas获取DOM元素失败");
            return;
        }
        html2canvas(element, {
            useCORS: true
        })
            .then((c) => {
                const url = c.toDataURL("image/png");
                const filename = "主页截图-" + new Date().getTime();
                const arr = url.split(",");
                const mime = arr[0].match(/:(.*?);/)?.[1];
                const suffix = mime?.split("/")[1];
                const bstr = atob(arr[1]);
                let n = bstr.length;
                const u8arr = new Uint8Array(n);
                while (n--) {
                    u8arr[n] = bstr.charCodeAt(n);
                }
                const file_name = new File([u8arr], `${filename}.${suffix}`, {
                    type: mime
                });
                resolve({ file: file_name });
            })
            .catch((err) => {
                reject(err);
            });
    });
}
 
/**
 * promise加载远程图片
 * @param src 图片远程地址
 * @returns
 */
export function loadImg(src: string): Promise<HTMLImageElement> {
    return new Promise((resolve, reject) => {
        try {
            const img = new Image();
            const timestamp = new Date().getTime();
            img.setAttribute("crossOrigin", "anonymous");
            if (src.indexOf("data:image") !== -1) {
                img.src = src;
            } else {
                img.src = `${src}?${timestamp}`;
            }
            img.onload = (): void => {
                resolve(img);
            };
            img.onerror = (err): void => {
                console.error("海报资源图片加载失败:", img, err);
                reject("资源图片加载失败");
            };
        } catch (e) {
            reject(e);
        }
    });
}
 
/**
 * 画带角度的图片
 * @param ctx canvas上下文
 * @param path 图片资源路径
 * @param width 图片宽度,直接填写设计稿大小
 * @param height 图片高度,直接填写设计稿大小
 * @param x 画布x轴,直接填写设计稿大小
 * @param y 画布y轴,直接填写设计稿大小
 * @param border 圆角大小,直接填写设计稿大小
 * @returns
 */
export function drawImagedWithRound(
    ctx: CanvasRenderingContext2D,
    path: string,
    width: number,
    height: number,
    x: number,
    y: number,
    border: number
): Promise<string> {
    return new Promise((resolve, reject) => {
        try {
            loadImg(path)
                .then((res) => {
                    // 绘制图片
                    ctx.save();
                    // 开始创建一个路径
                    ctx.beginPath();
                    // 画一个带border裁剪区域
                    // ctx.arc(img_x + img_border, img_y + img_border, img_border, 0, 2 * Math.PI)
                    ctx.arc(x + border, y + border, border, Math.PI, Math.PI * 1.5);
                    ctx.arc(x + width - border, y + border, border, Math.PI * 1.5, Math.PI * 2);
                    ctx.arc(x + width - border, y + height - border, border, 0, Math.PI * 0.5);
                    ctx.arc(x + border, y + height - border, border, Math.PI * 0.5, Math.PI);
                    ctx.closePath();
                    // 裁剪
                    ctx.clip();
                    // 绘制图片
                    ctx.drawImage(res as HTMLImageElement, x, y, width, height);
                    // 恢复之前保存的绘图上下文
                    ctx.restore();
                    resolve("success");
                })
                .catch((err) => {
                    reject(err);
                });
        } catch (e) {
            reject(e);
        }
    });
}
 
/**
 * canvas文字换行
 * @param ctx canvas上下文
 * @param content 文字内容
 * @param drawX 画布x轴,直接填写设计稿大小
 * @param drawY 画布y轴,直接填写设计稿大小
 * @param lineMaxWidth 最大宽度,直接填写设计稿大小
 * @param lineHeight 行间距,根据实际字体大小填写,建议1.5倍
 * @param lineNum 最大行数
 * @returns
 */
export function textWrap(
    ctx: CanvasRenderingContext2D,
    content: string,
    drawX: number,
    drawY: number,
    lineMaxWidth: number,
    lineHeight: number,
    lineNum: number
): void {
    let drawTxt = ""; // 当前绘制的内容
    let drawLine = 1; // 第几行开始绘制
    let drawIndex = 0; // 当前绘制内容的索引
    if (ctx.measureText(content).width <= lineMaxWidth) {
        // 判断内容是否可以一行绘制完毕
        ctx.fillText(content, drawX, drawY);
        return;
    }
    for (let i = 0; i < content.length; i++) {
        // 需要换行
        drawTxt += content[i];
        if (ctx.measureText(drawTxt).width >= lineMaxWidth) {
            if (drawLine >= lineNum) {
                ctx.fillText(`${content.substring(drawIndex, i)}..`, drawX, drawY);
                break;
            } else {
                ctx.fillText(content.substring(drawIndex, i + 1), drawX, drawY);
                drawIndex = i + 1;
                drawLine += 1;
                drawY += lineHeight;
                drawTxt = "";
            }
        } else {
            // 内容绘制完毕,但是剩下的内容宽度不到lineMaxWidth
            if (i === content.length - 1) {
                ctx.fillText(content.substring(drawIndex), drawX, drawY);
            }
        }
    }
}