小程序canvas生成海报 - 海报如此简单

554 阅读4分钟

canvas - 海报如此简单

小程序生成海报 canvas海报 百度小程序

下面以百度小程序为例,使用canvas生成海报

组件

canvas

api

swan.createCanvasContext

属性/方法

方法参数说明
.setFillStylecolor设置填充色
.fillRect(x,y,width,height)填充一个矩形
.fill填充内容
.setFontSizenumber设置字体大小
.fillText(text,x,y)绘制填充文本
.setTextAlignstring设置文字对齐方式
.drawImage...绘制图像到画布
.measureTextstring测量文本尺寸
.draw绘制到canvas上

开始之前

  1. canvas是分层级的 - js代码执行逻辑。默认情况下,写在越靠前的代码层级越低。
  2. 所有绘制的图形/形状必须给宽高。
  3. 后设置的setFillStyle会覆盖先设置的setFillStyle。如果想要回到原来设置的填充色,需要重新设置setFillStyle - 不会影响之前的效果。
  4. 默认情况下图形/文字/图片是靠左上的,并且canvas中没有提供靠右排版的api。
  5. canvas是没有让文本换行的api的

废话不多说,上代码

index.swan

<view class="container">
 <view class="main">
     <canvas
         canvas-id="myCanvas"
         style="width:100%;height:100%">
     </canvas>
 </view>
 <view>
     <button bindtap="renderCanvas">绘制</button>
 </view>
</view>

index.css

.container{
 background-color: #f1f1f1;
​
}
.main{
 width: 750rpx;
 height: 100vh;
 box-sizing: border-box;
 padding: 20rpx 40rpx;
}

index.js

/* eslint-disable import/unambiguous, @babel/new-cap */
​
const app = getApp();
let ctx;
Page({
 data: {
     name: 'swan',
     windowHeight:app.globalData.windowHeight + 'px',
     windowWidth:app.globalData.windowWitdh + 'px',
 },
 onLoad() {
     // Do something when page load.
     ctx = this.createCanvasContext('myCanvas');
 },
 // 绘制canvas画布大小
 renderCanvas(){
     let canvasWidth = app.globalData.windowWidth - 40
     let canvasHeight = canvasWidth + 100 + 100 + 50;
     ctx.setFillStyle('#fff'); // 设置矩形的填充颜色为蓝色
     ctx.fillRect(0, 0, canvasWidth, canvasHeight);
     let head_left = canvasWidth * 0.6;
     let head_center = canvasWidth * 0.15;
     let head_right = canvasWidth * 0.25 - 10;
     ctx.drawImage('../../static/images/head_bg.jpg',0,0,canvasWidth,100);
     ctx.drawImage('../../static/images/dfhm.png',10,15,head_left,70);
     ctx.drawImage('../../static/images/zb.png',head_left + head_center,15,head_right,35);
     ctx.setFillStyle('#000'); // 设置文字的填充颜色为黑色
     ctx.setFontSize(12);
     ctx.fillText('12号', head_left + head_center, 65);
     ctx.fillText('12号', head_left + head_center, 80);
​
     // 顶部结束 - 顶部高为100
     // 中间部分
     ctx.setFillStyle('#e8e8e8')
     ctx.fillRect(0,100,canvasWidth,canvasWidth);
     ctx.setFillStyle('#f00');// 恢复填充颜色为之前设置的颜色
     // 计算矩形中心坐标
     let rectCenterX = canvasWidth / 2;
     let rectCenterY = canvasWidth / 2 + 100;
     ctx.setFillStyle('#ccc');
     ctx.drawImage('../../static/images/head_bg.jpg',rectCenterX - 100, rectCenterY - 100, 200, 200);
     ctx.fillRect(0,canvasWidth + 100,canvasWidth,50)
     ctx.setFillStyle('#000');
     ctx.setFontSize(24);
     ctx.setTextAlign('center');
     ctx.fillText('商品名称',rectCenterX,canvasWidth + 100 + 24 + 10)
​
     // 顶部+中间部分结束 - 高度为canvasWidth + 100 + 50
     // 底部二维码部分
     ctx.drawImage('../../static/images/head_bg.jpg',20, canvasWidth + 100 + 50 + 15, 70, 70);
     ctx.setFontSize(14)
     ctx.setTextAlign('left');
     this.drawTextWithWrap(ctx, '点击下方按钮,保存分享图,快乐分享每一天!', 110, 50 + canvasWidth + 100 + 50, canvasWidth / 2 - 20, 16);
     ctx.fill();
     ctx.draw();
 },
 drawTextWithWrap(ctx, text, x, y, maxWidth, lineHeight) {
     let words = text.split('');
     let line = '';
     console.log('进入判断',words);
​
     for(let i = 0; i < words.length; i++) {
         let testLine = line + words[i] + '';
         let metrics = ctx.measureText(testLine);
         console.log(metrics);
         let testWidth = metrics.width;
         if(testWidth > maxWidth && i > 0) {
             console.log('超出一行');
             ctx.fillText(line, x, y);
             line = words[i] + '';
             y += lineHeight;
         } else {
             line = testLine;
         }
     }
     ctx.fillText(line, x, y);
 },
});

image-20240319163608571

逻辑

首先创建canvas上下文对象 - ctx = this.createCanvasContext('myCanvas');

创建一个矩形作为背景

let canvasWidth = app.globalData.windowWidth - 40;//
let canvasHeight = canvasWidth + 100 + 100 + 50;
ctx.setFillStyle('#fff'); // 设置矩形的填充颜色为蓝色
ctx.fillRect(0, 0, canvasWidth, canvasHeight); // x偏移0,y偏移0,canvasWidth矩形宽,canvasHeight矩形高

开始绘制海报中需要的元素

let head_left = canvasWidth * 0.6;
let head_center = canvasWidth * 0.15;
let head_right = canvasWidth * 0.25 - 10;
ctx.drawImage('../../static/images/head_bg.jpg',0,0,canvasWidth,100);
ctx.drawImage('../../static/images/dfhm.png',10,15,head_left,70);
ctx.drawImage('../../static/images/zb.png',head_left + head_center,15,head_right,35);
// 先前提到的由于canvas不能设置靠右
// 要适配不同的微小偏差的机型,使用百分比的形式进行偏移
// 绘制的图像不要忘记给宽高,图像支持相对路径,网络图片,临时文件

如何将元素居中

// 我们可以得知上面矩形的高是100,我们想将矩形放到下面矩形的正中间
// 我们就需要设置小矩形的中心点
// 计算大矩形中心坐标 - 由于默认坐标是左上,也就是默认情况下的0,0 ,我们需要将坐标设置到大矩形中心
let rectCenterX = canvasWidth / 2;
let rectCenterY = canvasWidth / 2 + 100;
ctx.setFillStyle('#ccc');
// rectCenterX - 100, rectCenterY - 100将坐标进行偏移 - 相当于以rectCenterX - 100, rectCenterY - 100,为起始点画200*200的正方形
ctx.drawImage('../../static/images/head_bg.jpg',rectCenterX - 100, rectCenterY - 100, 200, 200);
ctx.fillRect(0,canvasWidth + 100,canvasWidth,50);
ctx.setFillStyle('#000');
ctx.setFontSize(24);
ctx.setTextAlign('center');
ctx.fillText('商品名称',rectCenterX,canvasWidth + 100 + 24 + 10)

如何将文本自动换行

// ctx.measureText - 获取文本宽度
drawTextWithWrap(ctx, text, x, y, maxWidth, lineHeight) {
     let words = text.split('');// 将传入的文本分成数组 - 分别计算每一个字体的宽
     let line = '';
     console.log('进入判断',words);
     for(let i = 0; i < words.length; i++) { // 将文字进行拼接
         let testLine = line + words[i] + '';
         let metrics = ctx.measureText(testLine);
         console.log(metrics);
         let testWidth = metrics.width;// 每次拼接计算一次宽度
         if(testWidth > maxWidth && i > 0) {// 当计算的宽度大于传入的容器宽度之后,绘制第一行文本,并准备第二行文本
             console.log('超出一行');
             ctx.fillText(line, x, y);
             line = words[i] + '';
             y += lineHeight;
         } else {
             line = testLine;
         }
     }
     ctx.fillText(line, x, y);
 },

如此就结束啦。

关于如何将绘制的canvas保存成临时文件,那就是另一个api了

swan.canvasToTempFilePath

未完待续。。。