前言:公司新项目需要做小程序,一步一步摸着坑,走到上线,感觉收获颇多,其中一处就是用原生组件canvas 绘制海报图,并保存到系统相册的案例,现在将案例分享出来,和大家一同探讨。
针对以上问题,可以先进行思索,是否脑中有方法可以解决。那我就不卖关子,列位看官,拿好水杯,姿势摆好,开始秀操作。
function drawCircleImg(ctx, src, x, y, width, heigth) {
ctx.save(); // 先保存状态 已便于画完圆再用
ctx.beginPath(); //开始绘制
//先画个圆
ctx.strokeStyle = "rgba(255,255,255,0)";
ctx.arc(x + width / 2, y + heigth / 2, width / 2, 0, Math.PI * 2, false);
ctx.stroke();
ctx.clip(); // 这步不能丢
ctx.drawImage(src, x, y, width, heigth);
ctx.restore(); // 恢复画布不能忘记
}
/**
* 获取文本折行
* @param {Object} obj
* @return {Array} arrTr
*/
function getTextLine(obj, ctx) {
const { size, text, width } = obj;
const arrText = text.split("");
const arrTr = [];
let line = "";
ctx.setFontSize(size);
for (let i = 0; i < arrText.length; i++) {
const testLine = line + arrText[i];
const metrics = ctx.measureText(testLine);
const textWidth = metrics.width;
if (textWidth > width && i > 0) {
arrTr.push(line);
line = arrText[i];
} else {
line = testLine;
}
if (i == arrText.length - 1) {
arrTr.push(line);
}
}
return arrTr;
}
/**
* 多余文字省略,居中显示文本
* @param {Object} obj
* @param {Object} ctx 画布
* @param {Number} W 整体宽度
* @param {Number} width 限定文本长度,超出 显示省略号
*/
function ellipsisText(obj, ctx, W, width = 120) {
const { text, size } = obj;
const tr = getTextLine({ text, size, width }, ctx);
let txt = tr[0];
if (tr.length > 1) {
txt += '...'
}
ctx.setFontSize(size);
const metrics = ctx.measureText(txt).width;
obj.x = Math.floor((W - metrics) / 2);
obj.text = txt;
drawText(obj, ctx)
}
/**
* 绘制单行文本
* @param {Object} obj
*/
function drawText(obj, ctx) {
const { color, size, align, baseline, text, x, y, bold } = obj;
ctx.save();
ctx.fillStyle = color;
ctx.setFontSize(size);
ctx.setTextAlign(align);
ctx.setTextBaseline(baseline);
ctx.fillText(text, x, y);
if (bold) {
ctx.fillText(text, x, y - 0.5);
ctx.fillText(text, x - 0.5, y);
}
ctx.fillText(text, x, y);
if (bold) {
ctx.fillText(text, x, y + 0.5);
ctx.fillText(text, x + 0.5, y);
}
ctx.restore();
}
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath()
ctx.fillStyle = '#fff';
ctx.lineJoin = 'round';
// 左上角圆弧
ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)
ctx.moveTo(x + r, y)
ctx.lineTo(x + w - r, y)
ctx.lineTo(x + w, y + r)
// 右上角圆弧
ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)
ctx.lineTo(x + w, y + h - r)
ctx.lineTo(x + w - r, y + h)
// 右下角圆弧
ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)
ctx.lineTo(x + r, y + h)
ctx.lineTo(x, y + h - r)
// 左下角圆弧
ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)
ctx.lineTo(x, y + r)
ctx.lineTo(x + r, y)
ctx.fill()
ctx.closePath()
}
// 一行文本不同颜色
function diffColor(title, pxToRpx, ctx) {
textWrap(title, ctx);
const metrics = ctx.measureText(title.text);
const w = metrics.width;
const fix = ctx.measureText('一等奖:');
const sub = ctx.measureText(title.stock);
if (w + 10 + sub.width > title.width) {
drawText({
x: title.x + fix.width,
y: title.y + 4 * pxToRpx + title.height,
color: '#B0B0B0',
size: 22 * pxToRpx,
align: "left",
baseline: "top",
text: title.stock,
bold: false,
}, ctx);
return 14 * pxToRpx + title.height + 22 * pxToRpx;
} else {
drawText({
x: title.x + w + 10,
y: title.y + 4 * pxToRpx,
color: '#B0B0B0',
size: 22 * pxToRpx,
align: "left",
baseline: "top",
text: title.stock,
bold: false,
}, ctx);
return title.height + 4 * pxToRpx;
}
}
/**
* 文本换行
* @param {Object} obj
*/
function textWrap(obj, ctx) {
const { x, y, height, color, size, align, baseline, bold, maxRow } = obj;
const tr = getTextLine(obj, ctx);
const row = tr.length;
const minRow = Math.min(row, maxRow);
// const txtHeightArr = [];
// txtHeightArr.push(minRow * height);
for (let i = 0; i < minRow; i++) {
if (i < minRow) {
let txt = {
x,
y: y + i * height,
color,
size,
align,
baseline,
text: tr[i],
bold
};
if (i == minRow - 1 && row > maxRow) {
txt.text = txt.text.substring(0, txt.text.length - 2) + "......";
}
drawText(txt, ctx);
}
}
}
已上源码我已上传至github地址
若感兴趣可关注公众号 ruanjianxiaoyu 后台留言,可相互探讨学习。