不要让自己的底限成为你的上限
思路
- 熊猫头表情包固定的宽高,储存熊猫头高度
- 次要内容,标题、时间、天气,此处也需要记录高度以及间距(这些内容可以控制显示)
- 随机的文案
- 可以生成图片,canvas直接渲染会变成一行,所以需要根据每行多少字做切割
render node节点
处理页面文案显示,舔狗文案是从网上扒的,包含了****
高亮内容。通过切割**
形式高亮文本,小程序无法直接渲染wxml,需要转换成array形式。
1 | getNodeText(text) { |
动态处理canvas高度
1 | setCanvasHeight() { |
生成canvas内容
需要注意的是,我用的是最新的2.17.0
的库,使用的也是小程序最新的api<canvas type="2d" id="myCanvas"></canvas>
,之前的api被官方废弃了。
wxml
通过动态高度,这样就能动态适应文案内容了。
1 | <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
自动渲染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// 页面转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转成图片,通过canvasToTempFilePath
api可以拿到canvas转成图片后的内容
生成图片
1 | async getCurrentCanvasImage() { |
保存图片
使用saveImageToPhotosAlbum
可以保存图片,但是需要拿到保存图片的权限,如果没有权限需要进行判断提示用户开启权限
1 | async saveCanvas() { |
成果: