使用canvas绘制24小时折线图

使用canvas绘制24小时折线图

    1. 首先将获取的数据中取得最高点的值,默认将盒子的高度赋值最高点的的canvas高,当然我们为了保持好看,可以将盒子高度*0.9避免折线与盒子每次都持平
    1. 将获取到的数据,每个时间点的值与下一个时间点的值进行对比,取最大的值作为canvas的高度
      • 2.1 比如:如果要绘制一点的折线,如果1点的值大于等于两点的,则1点的canvas的高度取1点的值除以最大值乘以0.9,反之取两点的
    1. 绘制折线,遍历获取到的数据将当前值和下一个值为0的跳过不需要绘制(如果需要都连接没有断点的话不需要跳过,在这我这边不需要都连接),通过canvas的moveTo和lineTo绘制线条,fillStyle填充绘制前区域颜色

具体请看下列代码

<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>

如果折线图要求某些条件下线条颜色粗细不一致,则请看这篇文章https://blog.csdn.net/weixin_46328739/article/details/132280175
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Android 上绘制折线图,可以使用 Canvas 和 Paint 类来实现。 首先,你需要创建一个自定义 View 组件,并在其 onDraw() 方法中实现绘图逻辑。在绘制折线图时,你需要先计算出每个数据点的坐标,然后使用 Path 类绘制连接这些点的线条。 下面是一个简单的示例代码,实现了一个基本的折线图绘制: ```java public class LineChartView extends View { private List<Float> mData = new ArrayList<>(); public LineChartView(Context context) { super(context); } public LineChartView(Context context, AttributeSet attrs) { super(context, attrs); } public LineChartView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setData(List<Float> data) { mData = data; invalidate(); // 通知 View 进行重新绘制 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 设置画笔颜色和样式 Paint paint = new Paint(); paint.setColor(Color.BLUE); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(5); // 计算每个数据点的坐标 int width = getWidth(); int height = getHeight(); float xInterval = width / (mData.size() - 1); float yInterval = height / Collections.max(mData); Path path = new Path(); for (int i = 0; i < mData.size(); i++) { float x = i * xInterval; float y = height - mData.get(i) * yInterval; if (i == 0) { path.moveTo(x, y); } else { path.lineTo(x, y); } } // 绘制折线图 canvas.drawPath(path, paint); } } ``` 在 Activity 中,你可以通过调用 setData() 方法来设置折线图的数据,并将自定义 View 组件添加到布局中: ```java List<Float> data = new ArrayList<>(); data.add(10f); data.add(20f); data.add(50f); data.add(30f); data.add(40f); LineChartView lineChartView = new LineChartView(this); lineChartView.setData(data); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); linearLayout.addView(lineChartView, layoutParams); ``` 上述代码会在 LinearLayout 中添加一个折线图,其中数据为 [10, 20, 50, 30, 40]。你可以根据自己的需求来修改上述代码,实现更加复杂的折线图绘制

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值