实现效果
输入:使用组件设置文案,要求canvas 渲染效果与textarea内显示格式一致,文本溢出自动删除、有字符输入限制,支持文本对齐功能。
输出:canvas绘制
实现方式
功能点主要有
- 文案换行判断
- 文本对齐绘制
- 文本溢出截断
文本换行判断与绘制
换行的情况主要分为三种:回车换行、文本过长自动换行。对于回车换行,采用字符串查询即可确定换行位置;主要难点在文本过长自动换行,如何判断文本在canvas绘制会在哪一行,需要利用canvas的测量api来模拟换行。
ctx.measureText(text).width即可计算出文本绘制的像素长度。若溢出,择换行渲染(即直接filltext然后改变positionY += lineHeight)
文本对齐绘制
根据text-align属性判断对齐方式,对于不同的对齐方式,只需要计算开始绘制canvas的positionX即可
左对齐,直接偏移量置0,
右对齐,偏移量=外宽度-文本绘制长度
居中对齐,偏移量=(外宽度-文本绘制长度)/2
文本溢出截断
这里需要有行数计算,如何计算文本占用的行高,可以将文本内容绑定到 pre 标签,然后计算pre标签的高度,通过高度/行高确定行数,如果超过就将输入的字符通过watch功能,不断除去最后一个字母,直到满足文本内容在设定行数以内,即满足文本截断功能。
// 具体的watch实现根据对应框架应用即可
function watch(newVal) {
// 回车异常锁定
if (
newVal.slice(newVal.length - 1).charCodeAt() === 10 &&
this.getlines() + 1 > this.lines
) {
this.inputValue = newVal.slice(0, newVal.length - 1);
return;
}
// 越界逻辑
if (this.lines < this.getlines()) {
newVal = newVal.split('');
newVal.pop();
this.inputValue = newVal.join('');
return;
}
this.inputValue = (newVal + '').replace(/["*/\\?<>:|]/g, '');
}
canvas绘制示例
let drawMultipleText = function (ctx, styles, text) {
// 属性获取
const {
textAlign,
lineHeight,
height,
width,
left,
top,
fontSize
} = styles
ctx.fillStyle = '#999';
// 计算X偏移量函数
function calPositionX(text) {
let positionX;
switch (textAlign) {
// 右对齐
case 2:
positionX = left + width - ctx.measureText(text).width;
break;
// 居中对齐
case 1:
positionX = left + (width - ctx.measureText(text).width) / 2;
break;
// 左对齐
case 0:
default:
positionX = left;
}
return positionX;
}
let positionY = top + fontSize
let lines = Math.floor(height / lineHeight);
// 多行绘制计算
let str = text.split('');
let lineText = '';
let renderLine = 0;
for (let i = 0; i < str.length; i++) {
if (renderLine > lines) {
break;
}
// measureText 可计算绘制内容的宽度
let metric = ctx.measureText(lineText + str[i]);
if (metric.width < width) {
if (str[i].charCodeAt() === 10) {
// 回车换行
positionX = calPositionX(lineText);
ctx.fillText(lineText, positionX, positionY);
positionY = positionY + lineHeight;
lineText = '';
} else {
lineText += str[i];
}
if (i === str.length - 1) {
// 到达行尾,绘制结束的文本
positionX = calPositionX(lineText);
ctx.fillText(lineText, positionX, positionY);
}
} else {
// 绘制整行内容
positionX = calPositionX(lineText);
ctx.fillText(lineText, positionX, positionY);
renderLine++;
lineText = str[i];
positionY = positionY + lineHeight;
}
}
}