// 默认配置参数 const defaultOptions = () => ({ avatarUrl: 'https://static.caimei365.com/app/mini-hehe/icon/icon-join-us.png', userName: '颜选美学', subTitle: '强烈为你推荐该商城', coverUrl: 'https://static.caimei365.com/app/mini-hehe/icon/icon-share.png', bgImageUrl: 'https://static.caimei365.com/app/mini-hehe/icon/bg-share-01.png', ewmUrl: 'https://static.caimei365.com/app/mini-hehe/icon/icon-ewm-hehe.jpg', textArray: ['¥500.00¥300.00', '哈喽,赶快来参团吧!这件商品', '拼团买更便宜~'], scale: 0.5, }) // 绘制海报 export default class DrawPoster { constructor(ctx, options = {}) { this.ctx = ctx this.options = Object.assign(defaultOptions(), options) } // 开始绘制 draw() { return new Promise(async (resolve, reject) => { try { await this.drawBgImage() await this.drawHeader() await this.drawCenterInfo() } catch (e) { console.log(e) reject(e) } finally { this.ctx.draw(true, res => { resolve(true) }) } }) } // 绘制海报头部(用户信息区域) async drawHeader() { try { const { avatarUrl, userName, scale, subTitle } = this.options const [error, result] = await uni.downloadFile({ url: avatarUrl }) if (error) return // 绘制用户头像 this.ctx.beginPath() this.ctx.arc(116 * scale, 108 * scale, 60 * scale, 0, 2 * Math.PI) this.ctx.setFillStyle('#fff') this.ctx.fill() this.ctx.clip() this.ctx.drawImage(result.tempFilePath, 56 * scale, 48 * scale, 120 * scale, 120 * scale) this.ctx.restore() // 绘制用户名和推荐语 this.ctx.setFillStyle('#FFFFFF') this.ctx.font = 'bold 10px sans-serif' this.ctx.setFontSize(40 * scale) this.ctx.fillText(userName, 205 * scale, 96 * scale, 350 * scale) this.ctx.font = 'normal 10px sans-serif' this.ctx.setFontSize(26 * scale) this.ctx.fillText(subTitle, 205 * scale, 150 * scale, 350 * scale) this.ctx.save() return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } // 绘制背景 async drawBgImage() { try { const { bgImageUrl, scale } = this.options const [error, result] = await uni.downloadFile({ url: bgImageUrl }) if (error) return this.ctx.drawImage(result.tempFilePath, 0, 0, 750 * scale, 1220 * scale) this.ctx.save() return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } // 绘制中心区域 async drawCenterInfo() { try { const { scale } = this.options this.ctx.beginPath() this.ctx.rect(28 * scale, 214 * scale, 694 * scale, 978 * scale) this.ctx.setFillStyle('#FFFFFF') this.ctx.fill() this.ctx.clip() await this.drawCoverImage() await this.drawFooterText() await this.drawEwmImage() return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } // 绘制封面图片 async drawCoverImage() { try { const { coverUrl, scale } = this.options const [error, result] = await uni.downloadFile({ url: coverUrl }) if (error) return this.ctx.drawImage(result.tempFilePath, 56 * scale, 242 * scale, 638 * scale, 638 * scale) return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } // 绘制底部 drawFooterText(callback) { const { scale, textArray } = this.options if (callback) { callback({ scale, ctx: this.ctx, textArray }) } else { textArray.forEach((txt, index) => { this.ctx.setFontSize(30 * scale) this.ctx.setFillStyle('#333') if (txt && index === 0) { this.drawPrice(txt) } else { this.ctx.fillText(txt, 70 * scale, (980 + 56 * index) * scale) } }) } } drawPrice(txt) { const { scale } = this.options const txts = (txt.startsWith('¥') ? txt.slice(1) : txt).split('¥') let txtLeft = 60 * scale txts.forEach((priceText, index) => { if (index === 0) { this.ctx.setFillStyle('#FF457B') this.ctx.setFontSize(24 * scale) this.ctx.fillText('¥', txtLeft, 954 * scale) const m1 = this.ctx.measureText('¥') this.ctx.setFontSize(40 * scale) this.ctx.fillText(priceText, txtLeft + m1.width, 954 * scale) const m2 = this.ctx.measureText(priceText) txtLeft = txtLeft + m1.width + m2.width + 8 } else { this.ctx.setFillStyle('#999') this.ctx.setFontSize(24 * scale) this.ctx.fillText('¥' + priceText, txtLeft, 954 * scale) let m = this.ctx.measureText('¥' + priceText) this.ctx.fillRect(txtLeft, 946 * scale, m.width + 4, 1) } }) } // 绘制底部二维码 async drawEwmImage() { try { const { ewmUrl, scale } = this.options const [error, result] = await uni.downloadFile({ url: ewmUrl }) if (error) return this.ctx.drawImage(result.tempFilePath, 524 * scale, 976 * scale, 160 * scale, 160 * scale) return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } }