1
0
mirror of https://github.com/ialley-workshop-open/uni-halo.git synced 2026-06-12 21:29:31 +08:00

update: 优化文章详情海报图片在安卓下显示不完整问题

This commit is contained in:
小莫唐尼
2025-02-07 21:03:43 +08:00
parent 64c9a15d51
commit 27b3d31828
28 changed files with 4367 additions and 39 deletions
@@ -0,0 +1,377 @@
<template>
<view class="canvas-main">
<canvas :style="'width:'+width+'rpx;height:'+height+'rpx;'" class="canvas-item" disable-scroll="true"
canvas-id="canvasId" @error="error"></canvas>
</view>
</template>
<script>
export default {
props: {
//画布宽度(rpx)
width: {
type: Number,
default: 750
},
//画布高度(rpx)
height: {
type: Number,
default: 750
},
//生成的图片格式(jpg或png)
fileType: {
type: String,
default: 'png'
},
},
data() {
return {
pixelRatio: 0,
context: null,
canvasList: []
}
},
methods: {
async init(list) {
uni.showLoading({
title: '正在绘制...'
})
if (this.context) {
await this.clear()
this.canvasList = []
this.context = null
}
this.canvasList = JSON.parse(JSON.stringify(list))
const systemInfo = uni.getSystemInfoSync()
this.pixelRatio = systemInfo.pixelRatio
this.context = uni.createCanvasContext('canvasId', this)
this.start()
},
clear() {
return new Promise(async (resolve, reject) => {
await this.context.clearRect(0, 0, this.width, this.height)
resolve()
})
},
async start() {
await Promise.all(this.canvasList.map(async res => {
if (res.type == 'color') {
await this.drawBg(res)
} else if (res.type == 'image') {
await this.drawImage(res)
} else if (res.type == 'text') {
await this.drawText(res)
} else if (res.type == 'line') {
await this.drawLine(res)
}
}))
this.save()
},
drawBg(item) {
return new Promise(async (resolve, reject) => {
item.width = uni.upx2px(item.width)
item.height = uni.upx2px(item.height)
item.x = uni.upx2px(item.x)
item.y = uni.upx2px(item.y)
item.radius = uni.upx2px(item.radius)
item.lineWidth = uni.upx2px(item.lineWidth)
let gradient = ''
if (item.colorObj && item.colorObj.colorList) {
if (item.colorObj.colorList.length == 1) {
this.context.fillStyle = item.colorObj.colorList[0]
} else {
if (item.colorObj.direction == 1) {
gradient = this.context.createLinearGradient(0, 0, item.height, 0)
} else if (item.colorObj.direction == 2) {
gradient = this.context.createLinearGradient(0, 0, 0, item.height)
} else if (item.colorObj.direction == 3) {
gradient = this.context.createLinearGradient(0, 0, item.width, item.height)
} else if (item.colorObj.direction == 4) {
gradient = this.context.createLinearGradient(item.width, 0, 0, item.height)
}
gradient.addColorStop(0, item.colorObj.colorList[0])
gradient.addColorStop(1, item.colorObj.colorList[1])
this.context.fillStyle = gradient
}
} else {
this.context.fillStyle = '#FFFFFF'
}
this.context.save()
if (item.radius > 0) {
this.context.beginPath()
this.context.moveTo(item.x + item.radius, item.y)
this.context.arcTo(item.x + item.width, item.y, item.x + item.width, item.y +
item.radius, item.radius)
this.context.lineTo(item.x + item.width, item.y + item.height - item.radius)
this.context.arcTo(item.x + item.width, item.y + item.height, item.x + item
.width - item.radius, item.y + item.height, item.radius)
this.context.lineTo(item.x + item.radius, item.y + item.height)
this.context.arcTo(item.x, item.y + item.height, item.x, item.y + item
.height - item.radius, item.radius)
this.context.lineTo(item.x, item.y + item.radius)
this.context.arcTo(item.x, item.y, item.x + item.radius, item.y, item.radius)
this.context.closePath()
this.context.clip()
}
this.context.fillRect(item.x, item.y, item.width, item.height)
if (item.lineWidth) {
this.context.setLineDash([])
this.context.lineWidth = item.lineWidth
this.context.strokeStyle = item.lineColor
this.context.beginPath()
this.context.moveTo(item.x + item.radius, item.y)
this.context.arcTo(item.x + item.width, item.y, item.x + item.width, item.y +
item.radius, item.radius)
this.context.lineTo(item.x + item.width, item.y + item.height - item.radius)
this.context.arcTo(item.x + item.width, item.y + item.height, item.x + item
.width - item.radius, item.y + item.height, item.radius)
this.context.lineTo(item.x + item.radius, item.y + item.height)
this.context.arcTo(item.x, item.y + item.height, item.x, item.y + item
.height - item.radius, item.radius)
this.context.lineTo(item.x, item.y + item.radius)
this.context.arcTo(item.x, item.y, item.x + item.radius, item.y, item.radius)
this.context.closePath()
this.context.stroke()
}
this.context.restore()
await this.context.draw(true)
if (item.childs && item.childs.length > 0) {
await Promise.all(item.childs.map(async res => {
if (res.type == 'color') {
await this.drawBg(res)
} else if (res.type == 'image') {
await this.drawImage(res)
} else if (res.type == 'text') {
await this.drawText(res)
} else if (res.type == 'line') {
await this.drawLine(res)
}
}))
}
resolve()
})
},
drawImage(item) {
return new Promise(async (resolve, reject) => {
item.width = uni.upx2px(item.width)
item.height = uni.upx2px(item.height)
item.x = uni.upx2px(item.x)
item.y = uni.upx2px(item.y)
item.radius = uni.upx2px(item.radius)
item.lineWidth = uni.upx2px(item.lineWidth)
await this.getImageInfo(item.path).then(async res => {
this.context.save()
if (item.radius > 0) {
this.context.beginPath()
this.context.moveTo(item.x + item.radius, item.y)
this.context.arcTo(item.x + item.width, item.y, item.x + item.width,
item.y +
item.radius, item.radius)
this.context.lineTo(item.x + item.width, item.y + item.height - item
.radius)
this.context.arcTo(item.x + item.width, item.y + item.height, item.x +
item
.width - item.radius, item.y + item.height, item.radius)
this.context.lineTo(item.x + item.radius, item.y + item.height)
this.context.arcTo(item.x, item.y + item.height, item.x, item.y + item
.height - item.radius, item.radius)
this.context.lineTo(item.x, item.y + item.radius)
this.context.arcTo(item.x, item.y, item.x + item.radius, item.y, item
.radius)
this.context.closePath()
this.context.clip()
}
await this.context.drawImage(res, item.x, item.y, item.width, item
.height)
if (item.lineWidth) {
this.context.setLineDash([])
this.context.lineWidth = item.lineWidth
this.context.strokeStyle = item.lineColor
this.context.beginPath()
this.context.moveTo(item.x + item.radius, item.y)
this.context.arcTo(item.x + item.width, item.y, item.x + item.width,
item.y +
item.radius, item.radius)
this.context.lineTo(item.x + item.width, item.y + item.height - item
.radius)
this.context.arcTo(item.x + item.width, item.y + item.height, item.x +
item
.width - item.radius, item.y + item.height, item.radius)
this.context.lineTo(item.x + item.radius, item.y + item.height)
this.context.arcTo(item.x, item.y + item.height, item.x, item.y + item
.height - item.radius, item.radius)
this.context.lineTo(item.x, item.y + item.radius)
this.context.arcTo(item.x, item.y, item.x + item.radius, item.y, item
.radius)
this.context.closePath()
this.context.stroke()
}
this.context.restore()
await this.context.draw(true)
if (item.childs && item.childs.length > 0) {
await Promise.all(item.childs.map(async res => {
if (res.type == 'color') {
await this.drawBg(res)
} else if (res.type == 'image') {
await this.drawImage(res)
} else if (res.type == 'text') {
await this.drawText(res)
} else if (res.type == 'line') {
await this.drawLine(res)
}
}))
}
resolve()
})
})
},
drawText(item) {
return new Promise(async (resolve, reject) => {
item.width = uni.upx2px(item.width)
item.height = uni.upx2px(item.height)
item.x = uni.upx2px(item.x)
item.y = uni.upx2px(item.y)
item.fontSize = uni.upx2px(item.fontSize)
item.lineHeight = uni.upx2px(item.lineHeight)
await this.drawTextInfo(item.content, item.x, item.y, item.fontSize, item.color, item
.width, item.height, item.lineHeight, item.bold, true)
resolve()
})
},
drawLine(item) {
return new Promise(async (resolve, reject) => {
item.width = uni.upx2px(item.width)
item.startX = uni.upx2px(item.startX)
item.startY = uni.upx2px(item.startY)
item.endX = uni.upx2px(item.endX)
item.endY = uni.upx2px(item.endY)
this.context.setStrokeStyle(item.color)
this.context.setLineWidth(item.width)
this.context.setLineCap('round')
if (item.lineType == 'dash') this.context.setLineDash([item.width * 5, item.width * 5], 0)
else this.context.setLineDash([])
this.context.beginPath()
this.context.moveTo(item.startX, item.startY)
this.context.lineTo(item.endX, item.endY)
this.context.stroke()
this.context.closePath()
resolve()
})
},
drawTextInfo(text, x, y, fontSize, color, width, height, lineHeight, bold, ellipsis) {
return new Promise(async (resolve, reject) => {
this.context.setFillStyle(color)
if (bold) this.context.font = 'bold ' + fontSize + 'px Arial'
else this.context.font = fontSize + 'px Arial'
this.context.setTextBaseline('bottom')
let textArray = text.split('')
let line = ''
let lines = []
for (let i = 0; i < textArray.length; i++) {
let testLine = line + textArray[i]
let testWidth = this.context.measureText(testLine).width
if (testWidth > width) {
lines.push(line)
line = textArray[i]
} else {
line = testLine
}
}
lines.push(line)
let firstWidth = this.context.measureText(lines[0]).width
if (height >= lineHeight * lines.length) {
await Promise.all(lines.map(async (res, i) => {
let lineText = res
let lineHeights = lineHeight * (i + 1)
await this.context.fillText(lineText, x, y + lineHeights)
}))
} else {
let sNum = parseInt(height / lineHeight)
lines = lines.slice(0, sNum)
await Promise.all(lines.map(async (res, i) => {
let lineText = res
let lineHeights = lineHeight * (i + 1)
if (i == lines.length - 1) {
if (this.context.measureText('...').width < fontSize) {
lineText = lineText.substring(0, lineText.length - 1)
lineText += '...'
} else {
lineText = lineText.substring(0, lineText.length - 2)
lineText += '...'
}
}
await this.context.fillText(lineText, x, y + lineHeights)
}))
}
resolve()
})
},
getImageInfo(src) {
return new Promise(async (resolve, reject) => {
if (src.indexOf('http') == -1) {
setTimeout(() => {
resolve(src)
})
} else {
// #ifdef APP-PLUS
uni.getImageInfo({
src: src,
success: (res) => {
resolve(res.path)
},
fail(err) {
resolve(src)
}
})
// #endif
// #ifndef APP-PLUS
uni.downloadFile({
url: src,
success: (res) => {
if (res.statusCode === 200) resolve(res.tempFilePath)
},
fail: (err) => {
resolve(src)
}
})
// #endif
}
})
},
save() {
let timer = setTimeout(async () => {
await this.context.draw(true, setTimeout(() => {
uni.canvasToTempFilePath({
canvasId: 'canvasId',
fileType: this.fileType,
quality: 1,
width: this.width,
height: this.height,
destWidth: this.width * this.pixelRatio,
destHeight: this.height * this.pixelRatio,
success: (res) => {
uni.hideLoading()
this.$emit('change', res.tempFilePath)
},
fail: (err) => {
console.log('生成图片失败:', err)
}
}, this)
}, 500))
clearTimeout(timer)
}, 500)
},
error(e) {
console.log('错误信息:', e)
}
}
}
</script>
</script>
<style lang="scss" scoped>
.canvas-main {
position: fixed;
z-index: -999999 !important;
opacity: 0;
top: -5000rpx;
}
</style>