-
前言
由于接到需求需要使用 canvas 生成一些图片,然后每次改动的都不是特别多,但是真的很烦。网上也没有现成的demo,我决定自己new一个。(本期完成图片大小 位置 圆角的设置,字体大小 颜色 加粗 换行 省略 居中的功能) -
代码
- index.wxml 代码
<canvas class="canvas" canvas-id="shareCanvas"></canvas>
- index.wxss
.canvas {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: calc(750px / 2 );
height: calc(1050px / 2 );
/* transform: translateY(-200%); */
z-index: 1;
background: #98c379;
}
- index.js
const app = getApp()
const ctx = wx.createCanvasContext('shareCanvas');
const keyValue = {
'image': 0,
'text': 1
}
Page({
data: {
canvasList:[
{
type:keyValue.image,
width:750,
height:1050,
x:0,
y:0,
url:'https://mg-shop-test.oss-cn-hangzhou.aliyuncs.com/public/xcx_images/index-share-list-001.png',
borderRadius:0,
},
{
type: keyValue.image,
width: 124,
height: 124,
x: 313,
y: 48,
url:'https://wx.qlogo.cn/mmopen/vi_32/UFBlX5BwfmflsuyEhGFSNCksLX33yicawcSx4rYRB25uTC7HkWgSiclKjWPkJor2BPPdXSG3FQuI0WDt5EAHQmsg/132',
borderRadius: 62,
},
{
type:keyValue.text,
text:'Hello World 的简介',
width:550,
lineHeight:40,
fontSize: 32,
fontWeight: 'bold',
color: '#FFFFFF',
lineNumber: '1',
x: 100,
y: 200,
textAlign: 'center'
},
{
type:keyValue.text,
text:' Hello World 中文意思是『你好,世界』。因为《The C Programming Language》中使用它做为第一个演示程序,非常著名,所以后来的程序员在学习编程或进行设备调试时延续了这一习惯。',
width:550,
lineHeight:40,
fontSize:28,
fontWeight:'normal',
color:'#87CEEB',
lineNumber:'max',
x:100,
y:300,
textAlign:'right'
},{
type: keyValue.text,
text: '“Hello, world"程序是指在计算机屏幕上输出“Hello,world”这行字符串的计算机程序,“hello, world”的中文意思是“你好,世界。”。这个例程在Brian Kernighan 和Dennis M. Ritchie合著的《The C Programme Language》使用而广泛流行',
width: 550,
lineHeight: 36,
fontSize: 26,
fontWeight: 'normal',
color: '#b3e98f',
lineNumber: 3,
x: 100,
y: 550,
textAlign: 'center'
}
]
},
onLoad: function () {
this.downFile();
},
// 下载所需所需文件
downFile(index = 0){
let item = this.data.canvasList[index];
if(item.type == keyValue.image){ // 验证它的类型是否为 image
wx.downloadFile({
url:item.url,
complete:res=>{
if (res.errMsg == 'downloadFile:ok'){
item.tempFilePath = res.tempFilePath;
item.x = item.x / 2;
item.y = item.y / 2;
item.width = item.width / 2;
item.height = item.height / 2;
item.borderRadius = item.borderRadius / 2;
if (++index < this.data.canvasList.length) { // 验证是否为canvasList的最后一个
this.downFile(index);
}
else{
this.drawCanvas();
}
}
else{
console.error(res.errMsg);
}
}
})
}
else if (item.type == keyValue.text) { // 验证它的类型是否为 string
item.x = item.x / 2;
item.y = item.y / 2;
item.width = item.width / 2;
item.lineHeight = item.lineHeight / 2;
item.fontSize = item.fontSize / 2;
if (++index < this.data.canvasList.length) {
this.downFile(index); // 验证是否为canvasList的最后一个
}
else {
this.drawCanvas();
}
}
},
// 绘制图片
drawCanvas(index = 0){
let item = this.data.canvasList[index];
if (item.type == keyValue.image){
if(item.borderRadius == 0){ // 验证是否需要绘制圆角
ctx.drawImage(item.tempFilePath, item.x, item.y, item.width,item.height);
}
else{
// 怎么使用官方文档说的明明白白,我这不过多结束
// https://developers.weixin.qq.com/miniprogram/dev/api/CanvasContext.clip.html
ctx.beginPath()
let borderRadius = Math.sqrt(Math.pow((item.height / 2), 2) + Math.pow((item.width / 2) - item.borderRadius, 2)); // 计算圆角的半径(原理下图1)
ctx.arc(item.width / 2 + item.x, item.height / 2 + item.y, borderRadius , 0, 2 * Math.PI)
ctx.clip()
console.log(item.tempFilePath, item.x, item.y, item.width, item.height);
ctx.drawImage(item.tempFilePath, item.x, item.y,item.width,item.height);
ctx.restore()
}
ctx.save();
}
else if(item.type == keyValue.text){
ctx.setFillStyle(item.color); // 设置字体颜色
ctx.setFontSize(item.fontSize); // 设置字体大小
let tempTextList = []; // 存储分割字符串使用
let tempIndexNumber = 0;
for (let i = 1; i < item.text.length ; i++){
if (ctx.measureText(item.text.substring(tempIndexNumber, i)).width > item.width){
i--;
tempTextList.push(item.text.substring(tempIndexNumber, i));
tempIndexNumber = i;
}
else if(i == item.text.length - 1){
tempTextList.push(item.text.substring(tempIndexNumber));
}
}
let tempLength = item.lineNumber == 'max' ? tempTextList.length : item.lineNumber;
for(let i = 0 ; i < tempLength ; i++){
if(item.fontWeight == 'bold'){// 是否加粗字体
if (i == tempLength - 1 && tempLength < tempTextList.length){ // 验证是否超出了所需的行数限制
ctx.fillText(tempTextList[i].substring(0, tempTextList[i].length - 2) + '...', item.x, item.lineHeight * i + item.y + item.fontSize + 0.5);
ctx.fillText(tempTextList[i].substring(0, tempTextList[i].length - 2) + '...', item.x + 0.5, item.lineHeight * i + item.y + item.fontSize);
}
else if (tempLength == tempTextList.length){
if(item.textAlign == 'center'){// 文字居中
let tempWidth = (item.width - ctx.measureText(tempTextList[i]).width) / 2;
ctx.fillText(tempTextList[i], tempWidth + item.x, item.lineHeight * i + item.y + item.fontSize + 0.5);
ctx.fillText(tempTextList[i], tempWidth + item.x + 0.5, item.lineHeight * i + item.y + item.fontSize);
}
else if(item.textAlign == 'right'){// 文字居右
let tempWidth = item.width - ctx.measureText(tempTextList[i]).width;
ctx.fillText(tempTextList[i], tempWidth + item.x, item.lineHeight * i + item.y + item.fontSize + 0.5);
ctx.fillText(tempTextList[i], tempWidth + item.x + 0.5, item.lineHeight * i + item.y + item.fontSize);
}
else { // 文字默认居左 不作处理
ctx.fillText(tempTextList[i], item.x, item.lineHeight * i + item.y + item.fontSize + 0.5);
ctx.fillText(tempTextList[i], item.x + 0.5, item.lineHeight * i + item.y + item.fontSize);
}
}
else{
ctx.fillText(tempTextList[i], item.x, item.lineHeight * i + item.y + item.fontSize + 0.5);
ctx.fillText(tempTextList[i], item.x + 0.5, item.lineHeight * i + item.y + item.fontSize);
}
}
else{
if (i == tempLength - 1 && tempLength < tempTextList.length){
ctx.fillText(tempTextList[i].substring(0, tempTextList[i].length - 2) + '...', item.x, item.lineHeight * i + item.y + item.fontSize);
}
else if (tempLength == tempTextList.length){
if (item.textAlign == 'center') {// 文字居中
let tempWidth = (item.width - ctx.measureText(tempTextList[i]).width) / 2;
ctx.fillText(tempTextList[i], tempWidth + item.x, item.lineHeight * i + item.y + item.fontSize);
}
else if (item.textAlign == 'right') {// 文字居右
let tempWidth = item.width - ctx.measureText(tempTextList[i]).width;
ctx.fillText(tempTextList[i], tempWidth + item.x, item.lineHeight * i + item.y + item.fontSize);
}
else { // 文字默认居左 不作处理
ctx.fillText(tempTextList[i], item.x, item.lineHeight * i + item.y + item.fontSize);
}
}
else { // 文字默认居左 不作处理
ctx.fillText(tempTextList[i], item.x, item.lineHeight * i + item.y + item.fontSize);
}
}
}
}
if (++index < this.data.canvasList.length) {// 验证是否绘制完成
this.drawCanvas(index);
}
else {
// 渲染图片
ctx.draw(true,()=>{
this.savePhoto()
});
}
},
// 保存图片到本地
savePhoto(){
wx.canvasToTempFilePath({
destWidth: 750 / 2,
destHeight: 1050 / 2,
quality: 1,
fileType: 'jpg',
canvasId: 'shareCanvas',
complete: res => {
console.log(res);
if (res.errMsg == 'canvasToTempFilePath:ok'){
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
complete: res => {
if (res.errMsg == 'saveImageToPhotosAlbum:ok') {
wx.showToast('保存成功');
} else {
wx.showToast('用户取消了保存');
}
}
})
}
}
})
}
})
效果图
- 结尾
头一次编写分享文章,如有编写错误或者写不好的地方希望大家多担待,如有不明白的地方请留言,我将对其解答。后期将会再为 canvas 迭代几个版本尽量能将所有样式能再canvas 中实现出来。
By:Axs
这个可以,学习了
谢谢
可以尝试用下这个开源库哦:https://github.com/Kujiale-Mobile/Painter/,省去不必要的繁琐