不要让自己的底限成为你的上限

思路

  1. 熊猫头表情包固定的宽高,储存熊猫头高度
  2. 次要内容,标题、时间、天气,此处也需要记录高度以及间距(这些内容可以控制显示)
  3. 随机的文案
  4. 可以生成图片,canvas直接渲染会变成一行,所以需要根据每行多少字做切割

render node节点

处理页面文案显示,舔狗文案是从网上扒的,包含了****高亮内容。通过切割**形式高亮文本,小程序无法直接渲染wxml,需要转换成array形式。

 getNodeText(text) { const soulTextArray = text.split('**'); let nodes = [] for (const key of Object.keys(soulTextArray)) { nodes.push({ name: 'view', attrs: { class: key % 2 === 0 ? 'text' : 'lineheight' }, children: [{ type: 'text', text: soulTextArray[key] }] }) } return nodes; } 

动态处理canvas高度

 setCanvasHeight() { let canvasDrawHeightOffset = 20; const { title, time, weather } = this.data.checkboxValue; if (title) { canvasDrawHeightOffset = canvasDrawHeightOffset + 4; } else { canvasDrawHeightOffset = 0; } if (weather || time) { canvasDrawHeightOffset = canvasDrawHeightOffset + 40; } // 这里处理空白区域的 if (!title && !time && !weather) { canvasDrawHeightOffset = 20; } this.setData({ // 按照每行高度 18 * 每句句子 + 图片高度 + canvas渲染文案差距的高度 'canvasInfo.height': 18 * this.data.textArr.length + this.data.imgHeight + canvasDrawHeightOffset }); } 

生成canvas内容

需要注意的是,我用的是最新的2.17.0的库,使用的也是小程序最新的api<canvas type="2d" id="myCanvas"></canvas>,之前的api被官方废弃了。

wxml

通过动态高度,这样就能动态适应文案内容了。

<canvas type="2d" id="myCanvas" style="width: 300px;height: {{canvasInfo.height}}px;" bindlongtap="saveCanvas"></canvas> 

js

小程序canvas这块的api更新后用法需要注意

  • const ctx = canvas.getContext('2d');获得 Canvas 的绘图上下文
  • 需要先拿到页面canvas实例,然后使用 canvas.requestAnimationFrame 添加到计划中的动画帧
  • 渲染图片使用canvas.createImage(), ctx.drawImage(this._img, 0, 0, 300, imgHeight * 2, 75, 20, 150, imgHeight);
  • 结尾使用ctx.restore()即可,每次对ctx的操作都会由requestAnimationFrame自动渲染
 // 页面转canvas pageToCanvas() { this.setData({ canvasHidden: false }); const query = wx.createSelectorQuery() query.select('#myCanvas') .fields({ node: true, size: true }) .exec(this.canvasInit.bind(this)); }, // canvas初始化 canvasInit(res) { const width = res[0].width const height = res[0].height const canvas = res[0].node; const ctx = canvas.getContext('2d'); // 先清空一次 ctx.clearRect(0, 0, 300, 300); const dpr = wx.getSystemInfoSync().pixelRatio; canvas.width = width * dpr; canvas.height = height * dpr; this.setData({ 'canvasInfo.destWidth': width * dpr, 'canvasInfo.destHeight': height * dpr }) ctx.scale(dpr, dpr); const renderLoop = () => { this.drawDog(ctx, canvas); // 控制渲染 if (this.data.countDraw < 3) { this.setData({ countDraw: this.data.countDraw + 1 }); canvas.requestAnimationFrame(renderLoop); } }; canvas.requestAnimationFrame(renderLoop); // 渲染图片 const img = canvas.createImage(); img.onload = () => { this._img = img; } img.src = this.data.dogOptions.img; this.setData({ canvas }); }, drawDog(ctx, canvas) { if (!this._img) return; // 获得句子 const { imgHeight, canvasInfo: {height} } = this.data; ctx.fillStyle = '#FFFFFF'; ctx.fillRect(0, 0, 300, height); ctx.fillStyle = '#000000'; ctx.font = 'normal 14px sans-serif'; // 渲染图片高度 ctx.drawImage(this._img, 0, 0, 300, imgHeight * 2, 75, 20, 150, imgHeight); let canvasDrawHeightOffset = 4; if (this.data.checkboxValue.title) { ctx.font = 'normal bold 16px sans-serif'; ctx.fillText('舔狗日记', 300 / 2 - 30, imgHeight + canvasDrawHeightOffset); canvasDrawHeightOffset = canvasDrawHeightOffset + 20; } ctx.font = 'normal 14px sans-serif'; // canvas渲染平行offset let timeOffset = 0; let timeText = ''; if (this.data.checkboxValue.time) { timeText += this.data.currTime; timeOffset = timeOffset - 30; } if (this.data.checkboxValue.weather) { timeText += ' 阴'; timeOffset = timeOffset - 10; } console.log(this.data.checkboxValue) if (timeText) { ctx.fillText(timeText, 300 / 2 + timeOffset, imgHeight + canvasDrawHeightOffset); canvasDrawHeightOffset = canvasDrawHeightOffset + 20; } for (const [key, value] of Object.entries(this.data.textArr)) { ctx.fillText(value, 20, imgHeight + key * 18 + 4 + canvasDrawHeightOffset); } ctx.restore(); }, 

保存canvas渲染后的图片

小程序canvas这块的api更新后用法需要注意

保存图片前需要把canvas转成图片,通过canvasToTempFilePathapi可以拿到canvas转成图片后的内容

生成图片

 async getCurrentCanvasImage() { return new Promise((resolve, reject) => { wx.canvasToTempFilePath({ canvas: this.data.canvas, success: (toFile) => { console.log(toFile.tempFilePath); resolve(toFile.tempFilePath); }, fail: (res) => { console.log('图片生成失败'); reject(null); } }); }); } 

保存图片

使用saveImageToPhotosAlbum可以保存图片,但是需要拿到保存图片的权限,如果没有权限需要进行判断提示用户开启权限

 async saveCanvas() { const filePath = await this.getCurrentCanvasImage(); // 此处做一下失败处理 if (!filePath) { wx.showModal({ title: '失败', content: '未知原因,生成图片失败' }); return; } wx.saveImageToPhotosAlbum({ filePath, success: (res) => { wx.showToast({ title: '图片已保存', }); }, fail: async (error) => { const settingInfo = await wx.getSetting(); if (!settingInfo.authSetting['scope.writePhotosAlbum']) { wx.showModal({ title: '没有权限', content: '请开启相册权限', success: () => { wx.openSetting({ success: (setting) => { console.log(setting) } }); } }); } } }) } 

成果:

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。