这是一个适用于 vue2 的利用 canvas 绘制的简易心电图组件
代码简陋,能实时响应数据变化(非深度监听,需要更新对象)
xy轴提示文字可以隐藏 为了绘制完整性,绘制时会忽略页面 %50 部分的宽
左侧文字宽 50px 底部文字高 20 px
请在设置组件宽高时尽量将宽度设置为50的倍数,将高度设置为50的倍数+20,非此规则的宽高将不会用来绘制图
使用方式:
<ecg
:height="240"
:width="750"
:tip="true" //是否显示xy轴文字
:maxV="500" //最大电压
:ecgData="[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -240, -230]"
></ecg>
页面 ecg.vue
<template id="ecg">
<div
ref="ecgContent"
class="ecgContent"
id="ecgContent"
:style="{ width: width + 2 + 'px', height: height + 'px' }"
>
<canvas ref="ecgCanvas" id="ecgCanvas" v-if="show"></canvas>
</div>
</template>
<script>
export default {
data() {
return {
ecgList:[],
show: true,
canvas: null,
}
},
props: {
tip: {
type: Boolean,
default: () => {
return true
},
},
width: {
type: Number,
default: 240,
},
height: {
type: Number,
default: 750,
},
ecgData: {
type: Array,
default: () => {
return []
},
},
maxV:{
type:Number,
default:500
},
},
async mounted() {
this.ecgList = this.ecgData
this.init()
},
watch: {
ecgData(val) {
this.ecgList = val
if (this.canvas) {
this.$nextTick(()=>{
this.draw()
})
}
},
},
methods: {
init() {
if (!this.$refs.ecgCanvas) {
setTimeout(() => {
this.init()
}, 50)
return
}
let canvas = (this.canvas = this.$refs.ecgCanvas)
canvas.width = Math.floor(this.width / 50) * 50 + 2
canvas.height = this.height
this.$nextTick(() => {
setTimeout(() => {
console.log(this.width, this.height)
this.draw()
}, 100)
})
},
draw() {
var canvas = this.canvas
if (canvas.getContext) {
var ctx = canvas.getContext('2d')
var offsetx = 50
var offsety = 1
var width = this.width
var height = this.height
var gridWidth = Math.floor(width / 50) * 50
var gridHeight = Math.floor((height - 20) / 50) * 50
if (!this.tip) {
offsetx = 1
gridHeight = Math.floor(height / 50) * 50
}
ctx.fillStyle = 'rgba(255,255,255,1)'
ctx.fillRect(offsetx, offsety, width, height)
var d = 10
for (var i = 0; i <= gridWidth / d; i++) {
if (i % 5 == 0) {
ctx.strokeStyle = 'rgba(63, 169, 252,.6)'
ctx.lineWidth = 2
} else {
ctx.strokeStyle = 'rgba(63, 169, 252,.3)'
ctx.lineWidth = 1
}
ctx.beginPath()
ctx.moveTo(i * d + offsetx, offsety)
ctx.lineTo(i * d + offsetx, gridHeight + offsety)
ctx.stroke()
}
for (var j = 0; j <= gridHeight / d; j++) {
if (j % 5 == 0) {
ctx.strokeStyle = 'rgba(63, 169, 252,.6)'
ctx.lineWidth = 2
} else {
ctx.strokeStyle = 'rgba(63, 169, 252,.3)'
ctx.lineWidth = 1
}
ctx.beginPath()
ctx.moveTo(offsetx, j * d + offsety)
ctx.lineTo(gridWidth + offsetx, j * d + offsety)
ctx.stroke()
}
if (this.tip) {
ctx.font = '15px Arial'
ctx.fillStyle = 'rgb(0,0,0)'
ctx.fillText('time/ms', offsetx + width / 2 - 50, gridHeight + 20)
ctx.fillText('1.0mv', 0, 11)
ctx.fillText('0', 20, gridHeight / 2 + 5)
ctx.fillText('-1.0mv', 0, gridHeight)
}
this.drawLine(gridHeight / 2)
}
},
drawLine(zero) {
var context = this.canvas.getContext('2d')
//线条颜色为绿色
context.strokeStyle = '#f03e3e'
//线条粗细为2
context.strokeWidth = 2
// 起始位置
let x = 50
if(!this.tip){
x = 1
}
context.moveTo(x, Math.floor(Math.floor(this.height / 15) / 2) * 15)
context.beginPath()
/**for循环 */
let gap = (this.width - 2) / this.ecgList.length
console.log(gap)
if(gap > 1){
gap = 1
}
for (let i = 0; i < this.ecgList.length; i++) {
let after = this.getPoiont(this.ecgList[i], zero)
context.lineTo(x, after)
x += gap
}
context.stroke()
context.closePath()
},
getPoiont(value, zero) {
let point = zero
let max = this.maxV
let bl = point / max
if (value > 0) {
point = zero - value * bl
} else if (value < 0) {
point = zero + -value * bl
}
return point
},
},
}
</script>
<style>
.ecgContent {
width: 100%;
height: 100%;
}
#ecgCanvas {
width: 100%;
height: 100%;
}
</style>
参考于大佬文章:
csdn作者:涛哥带你学编程 文章:canvas绘制心电图(js读取csv心电数据文件)-