Canvas坐标系
原点位于左上角,X轴向右为正,Y轴向下为正。
绘制图片到canvas
drawImage,参考www.w3school.com.cn/html5/canva…
注意,图片需要先加载完成,才能绘制到canvas,建议采用以下方法
var bgImg = new Image();
bgImg.src = 'images/background.jpg';
bgImg.onload = function(){
// 图片加载完成后方可绘制
ctx1.drawImage(bgImg,0,0,绘制宽度,绘制高度);
}
在canvas中剪裁
本处例子为将图片裁剪为一个圆
ctx.save(); // 保存裁剪之前的Canvas状态,用于结束裁剪后恢复
var d = 2 * r;
var cx = x + r;
var cy = y + r;
ctx.arc(cx, cy, r, 0, 2 * Math.PI); // 绘制裁剪路径
ctx.clip(); // 将当前路径设置为裁剪路径
ctx.drawImage(img, x, y, d, d); // 绘制被裁剪图片
ctx.restore(); // 恢复裁剪前Canvas状态,结束裁剪
绘制文字到canvas
ctx.font = `normal normal 11px "sans-serif"`; // 文字样式
ctx.fillStyle = "#ffffff"; // 文字颜色
ctx.fillText(words, 起点X坐标, 起点Y坐标); //
canvas绘制多行文字
需要自己处理换行、溢出等状况,给一个例子:
// 绘制N行文字,第二行开始填满canvas宽度,可设置左右padding,第一行可设置起点坐标。第二行溢出部分以省略号结尾。
/**
*
* @param ctx 2d上下文对象
* @param text 绘制文本
* @param x 坐标轴x位置
* @param y 坐标轴y位置
* @param options 包含 maxWidth 最大宽度,lineHeight 文字行高,row 限制行数,textIndent 首行缩进,fontSize 文字大小
*/
function textEllipsis(ctx, text, x, y, options) {
ctx.save();
if (
typeof text !== 'string' ||
typeof x !== 'number' ||
typeof y !== 'number'
) {
return;
}
let defaultOpt = {
maxWidth: 100, // 输出多行文字最大高度
lineHeight: 14, // 行高
row: 1000, // 最多行数
textIndent: 0, // 首行缩进
fontSize: 14, // 字体大小
};
let params = Object.assign({}, defaultOpt, options);
// 分割文本
let textArr = text.split('');
// 文本最终占据高度
let textHeight = 0;
// 每行显示的文字
let textOfLine = '';
// 控制行数
let limitRow = params.row;
let rowCount = 0;
// 循环分割的文字数组
for (let i = 0; i < textArr.length; i++) {
// 获取单个文字或字符
let singleWord = textArr[i];
// 连接文字
let connectText = textOfLine + singleWord;
// 计算接下来要写的是否是最后一行
let isLimitRow = limitRow ? rowCount === limitRow - 1 : false;
// 最后一行则显示省略符,否则显示连接文字
let measureText = isLimitRow ? connectText + '...' : connectText;
console.log(measureText);
// 设置字体并计算宽度,判断是否存在首行缩进
ctx.font = `normal 500 ${params.fontSize}px "sans-serif"`;
let width = ctx.measureText(measureText).width; // 文字宽度
// 首行需要缩进满足条件
let conditionIndent = params.textIndent && rowCount === 0; // 判断是否需要缩进
let measureWidth = conditionIndent ? width + params.textIndent : width; // 根据缩进情况设置行数
// 大于限制宽度且已绘行数不是最后一行,则写文字
// 大于宽度限制表示可以绘制
if (measureWidth > params.maxWidth && i > 0 && rowCount !== limitRow) {
// 如果是最后一行,显示计算文本
measureText = measureText.slice(0, -4) + '...'; // 删除最后一个字符
let canvasText = isLimitRow ? measureText : textOfLine;
let xPos = conditionIndent ? x + params.textIndent : x; // 行首X轴坐标
// 写文字
ctx.fillStyle = '#000';
console.log(666666666666);
ctx.fillText(canvasText, xPos, y);
// 下一行文字
textOfLine = singleWord;
// 记录下一行位置
y += params.lineHeight;
// 计算文本高度
textHeight += params.lineHeight;
rowCount++; // 绘制文字后行数加1
if (isLimitRow) {
// 行数到达限制
break;
}
} else {
// 不大于最大宽度,继续拼接
textOfLine = connectText;
}
}
if (rowCount !== limitRow) {
// 单行文字走这边
let xPos = params.textIndent && rowCount === 0 ? x + params.textIndent : x;
ctx.fillStyle = '#000';
console.log('989898989898');
ctx.fillText(textOfLine, xPos, y);
}
// 计算文字总高度
let textHeightVal = rowCount < limitRow ? params.lineHeight : textHeight;
ctx.restore();
return textHeightVal;
}
canvas设置底色
先绘制边框,再使用fill方法进行填充,给出一个绘制圆角矩形的例子:
// canvasContext, x坐标,y坐标,宽度,高度,圆角半径
function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
ctx.save();
ctx.lineWidth = 1;
if (typeof stroke === 'undefined') {
stroke = true;
}
if (typeof radius === 'undefined') {
radius = 5;
}
if (typeof radius === 'number') {
radius = { tl: radius, tr: radius, br: radius, bl: radius };
} else {
var defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 };
for (var side in defaultRadius) {
radius[side] = radius[side] || defaultRadius[side];
}
}
// 绘制边框
ctx.beginPath();
ctx.moveTo(x + radius.tl, y); // 第一段弧线的起点
ctx.lineTo(x + width - radius.tr, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); // 圆角
ctx.lineTo(x + width, y + height - radius.br);
ctx.quadraticCurveTo(
x + width,
y + height,
x + width - radius.br,
y + height
);
ctx.lineTo(x + radius.bl, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
ctx.lineTo(x, y + radius.tl);
ctx.quadraticCurveTo(x, y, x + radius.tl, y);
ctx.closePath();
if (fill) {
// 填充底色
ctx.fillStyle = '#F74B57';
ctx.fill();
}
if (stroke) {
// 填充边框颜色
ctx.strokeStyle = '#F74B57';
ctx.stroke();
}
ctx.restore();
}
保存Canvas到本地
function exportCanvasAsPNG(id, fileName) {
var canvasElement = document.getElementById(id);
var MIME_TYPE = "image/png";
var imgURL = canvasElement.toDataURL(MIME_TYPE);
var blob = dataURLtoBlob(imgURL);
var objURL = URL.createObjectURL(blob);
var link = document.createElement("a");
link.download = fileName + ".png";
link.href = objURL;
link.click();
function dataURLtoBlob(dataurl: string) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
}