canvas画图,时间轴刻度标签

该博客展示了一段使用Vue.js实现的时间轴,用于显示不同时间段内的关键事件和对应的状态,如获取资质、年检、备案和事前变更。通过计算日期间距调整时间轴刻度,用不同颜色区分事件类型,并绘制了相应的标签和信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在时间轴上显示对应时间段的标签(状态)

在这里插入图片描述


<template>
  <div class="line_body">
    <canvas id="line" height="300"> </canvas>
  </div>
</template>
<script>
export default {
  data() {
    return {
      lineList: [
        {
          time: '2020/02/08',
          info: '获取资质',
        },
        {
          time: '2020/07/08',
          info: '获取资质',
        },
        {
          time: '2020/12/08',
          info: '备案',
        },
        {
          time: '2020/12/09',
          info: '备案',
        },
        {
          time: '2021/03/08',
          info: '年检',
        },
        {
          time: '2021/04/15',
          info: '事前变更',
        },
        {
          time: '2021/08/15',
          info: '事前变更',
        },
        {
          time: '2022/03/12',
          info: '备案',
        },
        {
          time: '2022/03/13',
          info: '备案',
        },
        {
          time: '2022/03/20',
          info: '备案',
        },
      ],
    };
  },
  mounted() {
    this.initLine();
  },
  methods: {
    toTimeStamp(dateString) {
      // dateString例如:'2022-03-05'
      // 例如返回:1646611200000
      return new Date(dateString) - 0;
    },
    getDistanceDays(date1, date2) {
      // date1例如:'2022-03-05',date2例如:'2022-03-06'
      const dateTimeStamp1 = this.toTimeStamp(date1);
      const dateTimeStamp2 = this.toTimeStamp(date2);
      let max = '';
      let min = '';
      if (dateTimeStamp1 > dateTimeStamp2) {
        max = dateTimeStamp1;
        min = dateTimeStamp2;
      } else {
        max = dateTimeStamp2;
        min = dateTimeStamp1;
      }
      // 例如返回:'1'
      return (max - min) / (24 * 60 * 60 * 1000);
    },
    drawText(t, x, y, w, context) {
      const chr = t.split('');
      let temp = '';
      const row = [];

      context.fillStyle = 'white';
      context.textBaseline = 'middle';
      context.font = "20px '微软雅黑'";

      for (let a = 0; a < chr.length; a += 1) {
        if (context.measureText(temp).width < w) {
          console.log(2222);
        } else {
          row.push(temp);
          temp = '';
        }
        temp += chr[a];
      }

      row.push(temp);

      for (let b = 0; b < row.length; b += 1) {
        context.fillText(row[b], x, y + (b + 1) * 20);
      }
    },
    initLine() {
      const canvas = document.getElementById('line');
      // if (canvas.width < window.innerWidth) {
      //   canvas.width = window.innerWidth;
      // }
      // 刻度长度一天
      let count = 0;
      let num = 0;
      // 防止挤压 最短几天
      const jyNum = 8;
      const unitLen = 5;
      const len = this.lineList.length;
      const canvasLen = this.getDistanceDays(this.lineList[0].time, this.lineList[len - 1].time);
      //   this.lineList.forEach((item, index) => {
      //     const num = this.getDistanceDays(this.lineList[index].time, this.lineList[index + 1].time);

      //     console.log(count);
      //   });
      for (let j = 0; j < this.lineList.length; j += 1) {
        if (j === this.lineList.length - 1) {
          num = 100;
        } else {
          num = this.getDistanceDays(this.lineList[j].time, this.lineList[j + 1].time);
        }
        // 判断数据中有多少小于 8 天的数据,防止挤压
        if (num < jyNum) {
          count += 1;
        }
      }

      canvas.width = canvasLen * unitLen + 200 + count * 120;

      // if (canvas.height < window.innerHeight) {
      //   canvas.height = 250;
      //   // window.innerHeight
      // }
      // 获得 2d 上下文对象
      const ctx = canvas.getContext('2d');
      //   let daylinelen = 0;
      let i = 0;
      let lastDaylen = 100;
      let days = 0;
      for (i = 0; i < this.lineList.length; i += 1) {
        // 直线
        ctx.beginPath();
        if (i === this.lineList.length - 1) {
          days = 100;
        } else {
          days = this.getDistanceDays(this.lineList[i].time, this.lineList[i + 1].time);
        }

        if (i === 0) {
          ctx.moveTo(100, 225);
          ctx.lineTo(days * unitLen + 100, 225);
        } else {
          ctx.moveTo(lastDaylen, 225);
          ctx.lineTo(days * unitLen, 225);
        }

        // 每个月约120 每天小刻度为40
        ctx.lineWidth = 2;
        ctx.strokeStyle = '#ccc';
        ctx.stroke();

        // 刻度
        ctx.beginPath();
        if (i === 0) {
          ctx.moveTo(100, 215);
          ctx.lineTo(100, 230);
        } else {
          ctx.moveTo(lastDaylen, 215);
          ctx.lineTo(lastDaylen, 230);
        }
        // ctx.moveTo(lastDaylen, 215); // x,y
        // 日期刻度
        ctx.lineWidth = 5;
        ctx.strokeStyle = 'black';
        ctx.stroke();

        // 刻度下日期
        ctx.beginPath();
        ctx.fillStyle = 'black';
        ctx.font = "16px '微软雅黑'";
        if (i === 0) {
          ctx.fillText(this.lineList[i].time, 50, 260, 100); // 绘制 "空心" 文字
        } else {
          ctx.fillText(this.lineList[i].time, lastDaylen - 50, 260, 100); // 绘制 "空心" 文字
        }
        ctx.stroke();
        // info Tag 标签
        ctx.beginPath();

        // eslint-disable-next-line default-case
        switch (this.lineList[i].info) {
          case '获取资质':
            ctx.fillStyle = 'rgb(250, 200, 88)';
            break;
          case '年检':
            ctx.fillStyle = 'rgb(250, 200, 88)';
            break;
          case '备案':
            ctx.fillStyle = 'rgb(84, 112, 198)';
            break;
          case '事前变更':
            ctx.fillStyle = 'rgb(145, 204, 117)';
            break;
        }
        // ctx.fillStyle = 'rgb(250, 200, 88)';
        const x = 100;
        const y = 20;
        if (i === 0) {
          ctx.fillRect(60, 70, 80, 120);
        } else {
          ctx.fillRect(lastDaylen - 40, 70, 80, 120);
        }
        ctx.stroke();

        ctx.beginPath();
        ctx.lineWidth = 1;
        if (i === 0) {
          ctx.moveTo(95, 190);
          ctx.lineTo(100, 196);
          ctx.lineTo(105, 190);
          ctx.lineTo(95, 190);

          //   ctx.fillText(`获取\n 资质`, 70, 150, 70);
          this.drawText(this.lineList[i].info, 80, 100, 40, ctx);
        } else {
          ctx.moveTo(lastDaylen - 5, 190);
          ctx.lineTo(lastDaylen, 196);
          ctx.lineTo(lastDaylen + 5, 190);
          ctx.lineTo(lastDaylen - 5, 190);
          this.drawText(this.lineList[i].info, lastDaylen - 20, 100, 40, ctx);
        }
        // eslint-disable-next-line default-case
        switch (this.lineList[i].info) {
          case '获取资质':
            ctx.fillStyle = 'rgb(250, 200, 88)';
            ctx.strokeStyle = 'rgb(250, 200, 88)';
            break;
          case '年检':
            ctx.fillStyle = 'rgb(250, 200, 88)';
            ctx.strokeStyle = 'rgb(250, 200, 88)';
            break;
          case '备案':
            ctx.fillStyle = 'rgb(84, 112, 198)';
            ctx.strokeStyle = 'rgb(84, 112, 198)';
            break;
          case '事前变更':
            ctx.fillStyle = 'rgb(145, 204, 117)';
            ctx.strokeStyle = 'rgb(145, 204, 117)';
            break;
        }
        ctx.fill();
        ctx.stroke();
        ctx.closePath();
        if (days < jyNum) {
          lastDaylen += 120;
        } else {
          lastDaylen += days * unitLen;
        }
      }
    },
  },
};
</script>
<style scoped>
.line_body {
  width: 100%;
  overflow: auto;
}
::-webkit-scrollbar {
  width: 200px !important;
  height: 40px;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值