小程序 canvas 绘制文本实现换行,设置字距
在使用 canvas 绘制文本的过程中,对于很长的文本,canvas 不能自动的进行换行处理,另外小程序无法像 web 端那样很方便的使用 svg,所以在此做一个简单的记录。
浅析
在实现之前简单的分析一下,要实现文本换行功能,在 canvas 中我们使用的是 fillText(text, x, y, maxWidth)
方法,
假设我们绘制的文本有最大的宽度,在超出这个宽度之后就进行换行,所以我们得知道绘制文本的宽度。
设置字距,如果是 css 那么就简单,直接使用 letter-spacing
即可,当然可以给 canvas 直接设置,
但是对于部分场景下可能操作起来不是那么方便,所以还在在绘制上面下文章,既然不直接设置,
那么就只有绘制一个字符就隔开一定间距再绘制另外一个字符,也就是逐字绘制。
实现
<template>
<view class="content">
<view class="ele-container">
<!-- 微信使用 canvas 2d -->
<!-- <canvas type="2d" id="nnCanvas"></canvas> -->
<!-- 微信不使用 canvas 2d -->
<canvas canvas-id="nnCanvas"></canvas>
<view
class="test-text"
:style="{
width: width + 'px',
fontSize: fontSize + 'px',
lineHeight: fontSize + lineHeight + 'px',
letterSpacing: letterSpacing + 'px'
}"
>
<text>{{ testText }}</text>
</view>
<view>
<button @click="handleFontSize">字号</button>
<button @click="handleLineHeight">行高</button>
<button @click="handleLetterSpacing">字距</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
ctx: null,
width: 200,
fontSize: 14,
lineHeight: 0,
letterSpacing: 0,
testText: ' 这是一段\n很长很长很长\r\n很长很长很\n\n长很长很长很长的 12314223asjedhweihdf hello world xxx文本 '
}
},
mounted() {
// // 微信使用 canvas 2d
// const _this = this
// const query = wx.createSelectorQuery()
// query.select('#nnCanvas')
// .fields({ node: true, size: true })
// .exec((res) => {
// let canvas = res[0].node
// _this.ctx = canvas.getContext('2d')
// _this.handleDrawText()
// })
// 微信不使用 canvas 2d
this.ctx = uni.createCanvasContext('nnCanvas')
this.handleDrawText()
},
methods: {
handleDrawText() {
// // 微信使用 canvas 2d
// this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
// 多个连续空格只保留一个
let tempText = this.testText.replace(/(^\s*)|(\s*$)/g, ' ').replace(/ +/g, ' ')
let { fontSize, letterSpacing } = this
let textLen = tempText.length
this.ctx.font = `${fontSize}px YaHei`
// 如果绘制的文本总宽度并没有超过最大宽度,那么直接绘制
if (
this.ctx.measureText(tempText).width +
textLen * letterSpacing < this.width
) {
this.ctx.fillText(tempText, 0, fontSize)
} else {
let strArray = []
let tempStr = ''
for (let i = 0; i < textLen; i++) {
let currStr = tempText[i]
// 判断当前字符是否是换行符,如果是,那么新增下一行
let isWrap = !/\r?\n/.test(currStr)
if (
isWrap &&
(
this.ctx.measureText(tempStr + currStr).width +
(tempStr.length + 1) * letterSpacing
) < this.width
) {
// 如果不是换行符且当前绘制的文本宽度加字距小于最大宽度,直接当前行字符串直接拼接
tempStr += currStr
} else {
// 否则就是当前行的宽度已经达到极限,进行换行
strArray.push(tempStr)
if (isWrap) {
// 如果不是换行符,直接新的一行开头就是这个字符
tempStr = currStr
} else {
// 否则,新的一行开头将换行符替换为空字符串
tempStr = ''
}
}
}
// 如果还有剩余结尾的字符串,直接就算作一行
if (tempStr != '') {
strArray.push(tempStr)
tempStr = ''
}
strArray.forEach((str, index) => {
// 逐行绘制,绘制的 y 坐标当前行行数加上字体大小加上行高近似的模拟
this.handleDrawOneLineText(str, (index + 1) * (fontSize + this.lineHeight))
})
// 微信不使用 canvas 2d
this.ctx.draw()
}
},
handleDrawOneLineText(str, y) {
let tempStr = ''
for (let i = 0, len = str.length; i < len; i++) {
// 逐字绘制,每行的y不变,单个字符的x是前面绘制文本的宽度加上每个字符的间距和
this.ctx.fillText(
str[i],
i * this.letterSpacing + (this.ctx.measureText(tempStr).width),
y
)
tempStr += str[i]
}
},
// 测试变化,方便查看效果
handleFontSize() {
if (this.fontSize < 20) {
this.fontSize += 1
} else {
this.fontSize -= 1
}
this.handleDrawText()
},
handleLineHeight() {
if (this.lineHeight < 5) {
this.lineHeight += 1
} else {
this.lineHeight -= 1
}
this.handleDrawText()
},
handleLetterSpacing() {
if (this.letterSpacing < 10) {
this.letterSpacing += 1
} else {
this.letterSpacing -= 1
}
this.handleDrawText()
}
}
}
</script>
<style lang="scss" scoped>
.test-text {
// 为了让效果看上去一致,所以使用这个属性,
// 不然单词和连续数字截断效果就不一样了
word-break: break-all
}
</style>
效果
可以看到上面 canvas 绘制的效果和下面标签渲染的效果差不到很多。文章来源:https://www.toymoban.com/news/detail-757759.html
最后
实现始终都是按照自己项目的需求来的,不同的项目,近似的一个需求可能实现的方式就稍微不同。文章来源地址https://www.toymoban.com/news/detail-757759.html
到了这里,关于小程序 canvas 绘制文本实现换行,设置字距的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!