|
@@ -0,0 +1,229 @@
|
|
|
+// 默认配置参数
|
|
|
+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',
|
|
|
+ userBg: 'https://static.caimei365.com/app/img/icon/bg-card.png',
|
|
|
+ userTitleBg: 'https://static.caimei365.com/app/img/icon/logo-fanbai.png',
|
|
|
+ // ewmUrl: 'https://static.caimei365.com/app/mini-hehe/icon/icon-ewm-hehe.jpg',
|
|
|
+ textArray: [],
|
|
|
+ scale: 0.5,
|
|
|
+})
|
|
|
+// 绘制海报
|
|
|
+export default class DrawPoster {
|
|
|
+ constructor(ctx, options = {}) {
|
|
|
+ this.ctx = ctx
|
|
|
+ this.options = Object.assign(defaultOptions(), options)
|
|
|
+ console.log('配置信息为:', this.options)
|
|
|
+ }
|
|
|
+ // 开始绘制
|
|
|
+ draw() {
|
|
|
+ return new Promise(async (resolve, reject) => {
|
|
|
+ try {
|
|
|
+ await this.drawBgImage()
|
|
|
+ // await this.drawHeader()
|
|
|
+ await this.drawUserCoverImage()
|
|
|
+ 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.setFillStyle('#999999')
|
|
|
+ // 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 drawRoundRect(x, y, w, h, r) {
|
|
|
+ this.ctx.beginPath()
|
|
|
+ this.ctx.moveTo(x + r , y)
|
|
|
+ this.ctx.arcTo(x + w, y, x + w, y + h, r)
|
|
|
+ this.ctx.arcTo(x + w, y + h, x , y + h, r)
|
|
|
+ this.ctx.arcTo(x, y + h, x, y, r)
|
|
|
+ this.ctx.arcTo(x, y, x + w, y , r)
|
|
|
+ this.ctx.setFillStyle('#FFFFFF')
|
|
|
+ this.ctx.fill()
|
|
|
+ this.ctx.clip()
|
|
|
+ }
|
|
|
+ // 绘制中心区域
|
|
|
+ async drawCenterInfo() {
|
|
|
+ try {
|
|
|
+ const { scale } = this.options
|
|
|
+
|
|
|
+ this.ctx.beginPath()
|
|
|
+ this.drawRoundRect(28 * scale, 28 * scale, 694 * scale, 878 * scale, 8)
|
|
|
+ // this.ctx.rect(28 * scale, 28 * scale, 694 * scale, 878 * scale)
|
|
|
+ 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, 24 * scale, 638 * scale, 678 * scale)
|
|
|
+ return Promise.resolve(true)
|
|
|
+ } catch (e) {
|
|
|
+ return Promise.reject(e)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 绘制名片封面
|
|
|
+ async drawUserCoverImage() {
|
|
|
+ try {
|
|
|
+ const { userBg, scale } = this.options
|
|
|
+ const [error, result] = await uni.downloadFile({ url: userBg })
|
|
|
+ if (error) return
|
|
|
+ this.drawBorderReduisImage(result.tempFilePath, 28 * scale, 920 * scale, 694 * scale, 290 * scale, 8)
|
|
|
+ await this.drawUserCardInner() // 绘制名片内容
|
|
|
+ return Promise.resolve(true)
|
|
|
+ } catch (e) {
|
|
|
+ return Promise.reject(e)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ async drawUserCardInner() {
|
|
|
+ try {
|
|
|
+ const { userTitleBg, scale, avatarUrl } = this.options
|
|
|
+ const [error, result] = await uni.downloadFile({ url: userTitleBg })
|
|
|
+
|
|
|
+ if (error) return
|
|
|
+ // this.drawBorderReduisImage(result.tempFilePath, 28 * scale, 920 * scale, 694 * scale, 280 * scale, 8)
|
|
|
+ this.ctx.drawImage(result.tempFilePath, 56 * scale, 940 * scale, 200 * scale, 70 * scale)
|
|
|
+ await this.drawCircleImg(avatarUrl, 170 * scale, 1000 * scale, 50)
|
|
|
+ return Promise.resolve(true)
|
|
|
+ } catch (e) {
|
|
|
+ return Promise.reject(e)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async drawCircleImg(img, x, y, r) {
|
|
|
+ const [error, result] = await uni.downloadFile({ url: img })
|
|
|
+ if (error) return
|
|
|
+ this.ctx.save()
|
|
|
+ this.ctx.beginPath()
|
|
|
+ let size = 2 * r
|
|
|
+ this.ctx.arc(x, y, r, 0, 2 * Math.PI)
|
|
|
+ this.ctx.clip()
|
|
|
+ this.ctx.drawImage(result.tempFilePath, x - r, y - r, size, size)
|
|
|
+ this.ctx.restore()
|
|
|
+ }
|
|
|
+ drawBorderReduisImage(imgUrl, bg_x, bg_y, bg_w, bg_h, bg_r) {
|
|
|
+ this.ctx.save()
|
|
|
+ this.ctx.beginPath()
|
|
|
+ this.ctx.arc(bg_x + bg_r, bg_y + bg_r, bg_r, Math.PI, Math.PI*1.5)
|
|
|
+ this.ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_r, bg_r, Math.PI * 1.5, Math.PI * 2)
|
|
|
+ this.ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_h - bg_r, bg_r, 0, Math.PI * 0.5)
|
|
|
+ this.ctx.arc(bg_x + bg_r, bg_y + bg_h - bg_r, bg_r, Math.PI * 0.5, Math.PI)
|
|
|
+ this.ctx.clip()
|
|
|
+ this.ctx.drawImage(imgUrl, bg_x, bg_y, bg_w, bg_h)
|
|
|
+ this.ctx.restore()
|
|
|
+ }
|
|
|
+ // 绘制底部
|
|
|
+ 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, 56 * scale, (678 + 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, 678 * scale, 160 * scale, 160 * scale)
|
|
|
+ return Promise.resolve(true)
|
|
|
+ } catch (e) {
|
|
|
+ return Promise.reject(e)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|