使用canvas绘制24小时折线图
-
- 首先将获取的数据中取得最高点的值,默认将盒子的高度赋值最高点的的canvas高,当然我们为了保持好看,可以将盒子高度*0.9避免折线与盒子每次都持平
-
- 将获取到的数据,每个时间点的值与下一个时间点的值进行对比,取最大的值作为canvas的高度
- 2.1 比如:如果要绘制一点的折线,如果1点的值大于等于两点的,则1点的canvas的高度取1点的值除以最大值乘以0.9,反之取两点的
- 将获取到的数据,每个时间点的值与下一个时间点的值进行对比,取最大的值作为canvas的高度
-
- 绘制折线,遍历获取到的数据将当前值和下一个值为0的跳过不需要绘制(
如果需要都连接没有断点的话不需要跳过,在这我这边不需要都连接),通过canvas的moveTo和lineTo绘制线条,fillStyle填充绘制前区域颜色
- 绘制折线,遍历获取到的数据将当前值和下一个值为0的跳过不需要绘制(
具体请看下列代码
<template>
<div id="index" class="home-box">
<div class="bottom-box">
<div class="bootom-bar-box">
<div
class="bootom-bar-item-box"
v-for="(item, index) in chartData"
:key="index"
>
<div class="bootom-bar-item-bt bootom-line-item-bt">
<canvas
:id="'canvas' + index"
:height="getLineHiehgt(item, index)"
></canvas>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'IndexPage',
data () {
return {
chartData: [
{
time: '00:00',
value: 0
},
{
time: '01:00',
value: 0
},
{
time: '02:00',
value: 0
},
{
time: '03:00',
value: 0
},
{
time: '04:00',
value: 1000
},
{
time: '05:00',
value: 2000
},
{
time: '06:00',
value: 2000
},
{
time: '07:00',
value: 3000
},
{
time: '08:00',
value: 4500
},
{
time: '09:00',
value: 6500
},
{
time: '10:00',
value: 6200
},
{
time: '11:00',
value: 6500
},
{
time: '12:00',
value: 8100
},
{
time: '13:00',
value: 6500
},
{
time: '14:00',
value: 5000
},
{
time: '15:00',
value: 5500
},
{
time: '16:00',
value: 4000
},
{
time: '17:00',
value: 3500
},
{
time: '18:00',
value: 2000
},
{
time: '19:00',
value: 1600
},
{
time: '20:00',
value: 0
},
{
time: '21:00',
value: 0
},
{
time: '22:00',
value: 0
},
{
time: '23:00',
value: 0
}
],
xData: [
0, 0, 0, 1000, 2000, 2000, 3000, 4500, 6500, 6200, 6500, 8100, 6500,
5000, 5500, 4000, 3500, 2000, 1600, 0, 0, 0, 0
],
maxBarValue: 0,
cuurentDate: new Date().getHours()
}
},
created () {
// 最高点
this.maxBarValue = Math.max.apply(null, this.xData)
},
methods: {
getLineHiehgt (item, index) {
if (this.chartData[index + 1]) {
if (this.chartData[index + 1].value >= this.chartData[index].value) {
return (this.chartData[index + 1].value / this.maxBarValue) * 288 * 0.9
} else {
return (item.value / this.maxBarValue) * 288 * 0.9
}
}
},
handleEqualsTime (item) {
return new Date().getHours() == item.time.split(':')[0]
},
handleJudgeTime (item) {
return new Date().getHours() < item.time.split(':')[0]
},
handleComputedBarHeight (arr) {
var maxObj = arr.reduce(function (prev, current) {
return prev.value > current.value ? prev : current
})
return maxObj.value
},
setCanvasLine () {
this.styleList = []
let cindex = 0
for (let index = 0; index < this.chartData.length; index++) {
if (this.chartData[index + 1]) {
if (
this.chartData[index].value == 0 &&
this.chartData[index + 1].value == 0
) {
continue
}
}
var canvas = document.getElementById('canvas' + index)
var canvasP = document.getElementById(
'canvas' + (index - 1 == -1 ? 0 : index - 1)
)
var hc = (this.chartData[index].value / this.maxBarValue) * 288* 3
var hp = this.chartData[index - 1]
? (this.chartData[index - 1].value / this.maxBarValue) * 288* 3
: 0
var hn = this.chartData[index + 1]
? (this.chartData[index + 1].value / this.maxBarValue) * 288* 3
: 0
console.log(canvasP, '99999')
var ctx = canvas.getContext('2d')
var w = canvas.width
ctx.imageSmoothingEnabled = true
ctx.scale(1,1);
console.log('hc=', hc, 'hp=', hp, 'hn=', hn, 'index=', index)
// 绘制直角梯形
ctx.beginPath()
if (hc < hn) {
if (hc == 0) {
ctx.moveTo(w / 2, hn / 2) // 左上角顶点
ctx.lineTo(w, 0) // 右上角顶点
ctx.lineTo(w, hn) // 右下角顶点
ctx.lineTo(0, hn) // 左下角顶点
} else {
ctx.moveTo(0, hn - hc) // 左上角顶点
ctx.lineTo(w, 0) // 右上角顶点
ctx.lineTo(w, hn) // 右下角顶点
ctx.lineTo(0, hn) // 左下角顶点
}
} else if (hc == hn) {
ctx.moveTo(0, 0) // 左上角顶点
ctx.lineTo(w, 0) // 右上角顶点
ctx.lineTo(w, hc) // 右下角顶点
ctx.lineTo(0, hc) // 左下角顶点
} else {
if (hn == 0) {
ctx.moveTo(0, 0) // 左上角顶点
ctx.lineTo(w / 2, hc / 2) // 右上角顶点
ctx.lineTo(w, hc) // 右下角顶点
ctx.lineTo(0, hc) // 左下角顶点
} else {
ctx.moveTo(0, 0) // 左上角顶点
ctx.lineTo(w, hc - hn) // 右上角顶点
ctx.lineTo(w, hc) // 右下角顶点
ctx.lineTo(0, hc) // 左下角顶点
}
}
ctx.closePath()
// 填充颜色
if (this.handleJudgeTime(this.chartData[index])) {
ctx.fillStyle = '#92772E'
} else if (this.handleEqualsTime(this.chartData[index])) {
ctx.fillStyle = '#FED666'
} else {
ctx.fillStyle = '#EBBD43'
}
ctx.fill()
}
}
},
mounted () {
this.$nextTick(() => {
this.setCanvasLine()
})
}
}
</script>
<style lang="scss">
.home-box {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.top-box {
padding: 10px;
height: 600px;
display: flex;
width: 100%;
}
.bottom-box {
flex: 1;
width: 100%;
display: flex;
flex-direction: column;
background: linear-gradient(180deg, #4c5864 0%, #5f6b65 100%);
.bottom-header-box {
display: flex;
align-items: center;
height: 80px;
width: 100%;
padding: 0 50px;
.bottom-header-title {
display: flex;
align-items: center;
.spanBg {
width: 21px;
height: 21px;
background: #2fc29e;
border-radius: 50%;
margin-right: 20px;
&.yellow {
background: #fac93e;
}
}
.label {
font-size: 15px;
font-weight: 600;
color: #ffffff;
line-height: 21px;
}
}
}
.bootom-bar-box {
flex: 1;
width: 100%;
display: flex;
.bootom-bar-item-box {
width: 4.17%;
height: 100%;
border: 1px solid #303e47;
border-left: 0;
border-bottom: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
&:last-child {
border-right: 0;
}
.bootom-bar-item-header {
height: 101px;
padding: 10px 10px 0;
}
&.bootom-bar-item-box-b {
.name {
color: #303e47;
}
.time {
color: #303e47;
}
.value {
color: #303e47;
}
.bootom-bar-item-bt {
.bar-box {
background: #0a8c6c;
}
}
}
&.bootom-bar-item-box-w {
background: #fff;
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.5);
.name {
color: #000;
}
.time {
color: #000;
}
.value {
color: #000;
}
.bootom-bar-item-bt {
.bar-box {
background: #3cffd1;
}
}
}
.name {
width: 100%;
height: 34px;
text-align: left;
font-size: 12px;
font-weight: 400;
color: #ffffff;
line-height: 17px;
padding-right: 10px;
margin-bottom: 5px;
display: flex;
flex-direction: column;
}
.time {
width: 100%;
text-align: left;
font-size: 20px;
font-weight: 400;
color: #ffffff;
line-height: 28px;
margin-bottom: 7px;
padding-right: 10px;
}
.value {
width: 100%;
padding-right: 10px;
text-align: right;
font-size: 12px;
font-weight: 400;
color: #ffffff;
line-height: 17px;
}
.bootom-bar-item-bt {
height: calc(100% - 101px - 10px);
width: 100%;
display: flex;
align-items: end;
.bar-box {
width: 100%;
background: #2fc29e;
}
&.bootom-line-item-bt {
display: flex;
justify-content: space-between;
position: relative;
.line {
position: absolute;
border-bottom: 2px solid black;
transform-origin: top left;
}
.line-box {
width: 1px;
height: 1px;
position: absolute;
left: 0;
}
.line-box1 {
width: 1px;
height: 1px;
position: absolute;
right: 0;
}
canvas {
width: 100%;
}
}
}
}
}
}
}
</style>