以下是我封装的canvas方法,和使用实例
<script setup lang="ts">
import { watch, getCurrentInstance, onMounted, reactive, ref, CSSProperties } from 'vue'
import Circle from './canvas'
let cricle: Circle
const props = defineProps<{
circleParam: {
percentage: number | string
treatmentMode: string
pressureUnit: string
}
}>()
const size = reactive({
width: 0,
height: 480,
})
watch(
() => props.circleParam,
() => {
updateDrawings()
},
{
deep: true,
// immediate: true,
}
)
onMounted(() => {
const instance = getCurrentInstance() as any
const info = uni.createSelectorQuery().in(instance).select('.circle')
info
.boundingClientRect(function (data) {
size.width = data['width'] * 2
const context = uni.createCanvasContext('circleCanvas', instance) //canvas组建封装,需要后加个this
const { width, height } = size
cricle = new Circle('circleCanvas', context, { width: width / 2, height: height / 2 })
updateDrawings()
})
.exec(function (_res) {
// 注意:exec方法必须执行,即便什么也不做,否则不会获取到任何数据
})
})
function updateDrawings() {
const value = props.circleParam.percentage
cricle.drawProgressValue(value === '--' ? 0 : (+props.circleParam.percentage / 20) * 100)
drawProgressInfo()
cricle.draw()
}
/**
* @description: 绘制圆环信息
*/
function drawProgressInfo() {
const { width } = size
const { treatmentMode, percentage, pressureUnit } = props.circleParam
cricle.paintFont(width / 4, 70, '治疗压力', 16)
cricle.paintFont(width / 4, 120, percentage, 'bold 48', '#292B3F', {
textAlign: 'center',
textBaseline: 'middle',
})
cricle.paintFont(width / 4, 160, pressureUnit, 'bold 16')
cricle.paintFont(width / 4, 200, treatmentMode, '20', '#4AC596')
}
const canvasStyle = ref<CSSProperties>()
function canvasDisplay(value: 'show' | 'hidden') {
if (value === 'hidden') {
canvasStyle.value = {
position: 'absolute',
top: '-500px',
}
} else {
canvasStyle.value = {}
}
}
defineExpose({
canvasDisplay,
})
</script>
<template>
<view class="circle" style="height: 480rpx">
<div :style="canvasStyle">
<canvas
v-if="size.width"
style="height: 480rpx; margin: 0 auto"
:style="{ widht: size.width + 'rpx' }"
canvas-id="circleCanvas"></canvas>
</div>
</view>
</template>
<style lang="scss" scoped>
.circle {
width: 100%;
text-align: center;
}
</style>
export default class Circle {
private context
size: {
width: number
height: number
}
BASEFONTCOLOR = '#B4B5BF'
BASEBGCOLOR = '#EBEBEB'
radius = 100
CANVASID: string
constructor(canvasId, context, size) {
this.CANVASID = canvasId
this.context = context
this.size = size
this.drawBackground()
}
drawBackground() {
const { width, height } = this.size
const [startAngle, endAngle] = this.scopePI()
this.drawBGRing(width / 2, height / 2, this.radius, startAngle, endAngle)
this.drawBGFont()
}
draw() {
const _that = this
this.context.draw(false, () => {
uni.canvasToTempFilePath(
{
canvasId: _that.CANVASID,
success: function (res) {
console.log('res', res)
return res.tempFilePath
},
fail: function (err) {
console.log('err', err)
},
complete: (com) => {
console.log('com', com)
},
},
_that
)
})
}
scopePI() {
return [(3 / 4) * Math.PI, (1 / 4) * Math.PI]
}
drawBGRing(x, y, radius, start, end, color = this.BASEBGCOLOR, LineWidth = 12) {
const ctx = this.context
ctx.beginPath()
ctx.setLineWidth(LineWidth)
ctx.strokeStyle = color
ctx.lineCap = 'round'
ctx.arc(x, y, radius, start, end, false)
ctx.stroke()
ctx.closePath()
}
drawBGFont() {
const { width, height } = this.size
const [startAngle, endAngle] = this.scopePI()
const minTextX = width / 2 + this.radius * Math.cos(startAngle)
const minTextY = height / 2 + this.radius * Math.sin(endAngle)
const maxTextX = width / 2 + this.radius * Math.cos(endAngle)
const maxTextY = height / 2 + this.radius * Math.sin(startAngle)
this.paintFont(minTextX + 20, minTextY + 20, 0, 14)
this.paintFont(maxTextX - 20, maxTextY + 20, 20, 14)
}
paintFont(x, y, text, fontSize, color = this.BASEFONTCOLOR, otherAttr: any = null) {
const ctx = this.context
ctx.beginPath()
ctx.font = (fontSize ?? '20') + 'px Arial'
ctx.fillStyle = color
ctx.textAlign = 'center'
if (otherAttr !== null) {
Object.keys(otherAttr).forEach((key) => {
ctx[key] = otherAttr[key]
})
}
ctx.closePath()
ctx.fillText(text, x, y)
}
/**
* @description: 绘制值
* @param {*} percentage 百分比值
*/
async drawProgressValue(percentage) {
const { width, height } = this.size
const [startAngle, endAngle] = this.scopePI()
this.clearReact()
this.drawBGRing(width / 2, height / 2, this.radius, startAngle, endAngle)
this.drawBGFont()
// 计算当前进度的结束角度
const totalAngle = 2 * Math.PI - startAngle + endAngle // 完整的角度跨度
const progressEndAngle = startAngle + (percentage / 100) * totalAngle // 计算进度结束角度
// 创建渐变
const gradient = this.context.createLinearGradient(0, height / 2, width / 2, height / 2)
gradient.addColorStop(0, '#4AC596') // 起始颜色
gradient.addColorStop(1, '#82D2E3') // 结束颜色
// 绘制进度条
if (percentage > 0) {
this.drawBGRing(
width / 2,
height / 2,
this.radius,
startAngle,
progressEndAngle,
gradient,
12
)
}
}
clearReact() {
const ctx = this.context
const { width, height } = this.size
ctx.clearRect(0, 0, width, height)
}
}
0 个回复