vue+canvas实现数据实时从上到下刷新瀑布图效果(类似QT的)

作者:Carl323 时间:2024-05-09 09:16:28 

话不多说了,先上一张Demo图,实现的功能有:左侧图例、右侧瀑布图、鼠标移入弹出当前坐标对应的数据信息(有优化的空间,大家自由发挥)。

vue+canvas实现数据实时从上到下刷新瀑布图效果(类似QT的)

图例使用到的插件

这里推荐使用安装npm插件colormap

瀑布图主体内容

这里不多做解释了,都是一些原生标签还有vue绑定的事件,可以根据实际项目情况自己封装成组件,我这里是写在一起的。


<template>
   <div>
       <div class="content">
           <div class="neirong">
               <!--图例-->
               <div class="legend">
                   <canvas ref="legend"></canvas>
               </div>
               <!--瀑布图-->
               <div class="waterFall" ref="waterFallContent"
                    @mousemove="waterFallMove($event)"
                    @mouseleave="waterFallLeave"
               >
                   <canvas ref="waterFall"></canvas>
                   <!--鼠标移入弹出框-->
                   <div ref="tip" class="tip"></div>
               </div>
           </div>
       </div>
   </div>
</template>

这里是用到的Data数据

  • colormap:颜色库

  • legend:图例

  • waterFall:瀑布图

  • waterFallList:瀑布图源数据

  • waterFallIndex:瀑布图定时器用到的计数标识

  • waterFallCopyList:瀑布图二维数组(用来显示数据做的临时储存)

  • waterFallIntervals:瀑布图定时器

  • waterFallWidth:瀑布图的宽度(后端返回的数据length)

  • waterFallHeight:瀑布图定高度(也可以理解成渲染次数 例如30次渲染完成)

  • maxNum:图例最大值

  • minNum:图例最小值


<script>
   export default {
       name: "index",
       data() {
           return {
               colormap: [],
               legend: null,
               waterFall: null,
               waterFallList: [],
               waterFallIndex: 0,
               waterFallCopyList: [],
               waterFallIntervals: null,
               waterFallWidth: 0,
               waterFallHeight: 0,
               maxNum: 10,
               minNum: 0
           }
       },

下面是具体的方法,写的比较粗略,大家凑活看吧,觉得有用的大家拿走,不足之处自由发挥修改

方法调用这就不解释了,离开页面销毁定时器。


mounted() {
           let dx = this
           dx.setColormap()
           dx.createLegendCanvas()
           dx.queryChartList()
       },
       destroyed() {
           let dx = this
           clearInterval(dx.waterFallIntervals)
       },

创建颜色库

这个地方具体看上面插件的官网有详细的介绍


setColormap() {
     let dx = this
     let colormap = require('colormap')
     dx.colormap = colormap({
         colormap: 'jet',
         nshades: 150,
         format: 'rba',
         alpha: 1,
  })
},

创建图例


createLegendCanvas() {
               let dx = this
               let legendRefs = dx.$refs.legend
               dx.legend = legendRefs.getContext('2d')
               let legendCanvas = document.createElement('canvas')
               legendCanvas.width = 1
               let legendCanvasTemporary = legendCanvas.getContext('2d')
               const imageData = legendCanvasTemporary.createImageData(1, dx.colormap.length)
               for (let i = 0; i < dx.colormap.length; i++) {
                   const color = dx.colormap[i]
                   imageData.data[imageData.data.length - i * 4 + 0] = color[0]
                   imageData.data[imageData.data.length - i * 4 + 1] = color[1]
                   imageData.data[imageData.data.length - i * 4 + 2] = color[2]
                   imageData.data[imageData.data.length - i * 4 + 3] = 255
               }
               legendCanvasTemporary.putImageData(imageData, 0, 0)
               dx.legend.drawImage(legendCanvasTemporary.canvas,
               0, 0, 1, dx.colormap.length, 50, 0, 200, dx.legend.canvas.height)
           },

创建瀑布图


createWaterFallCanvas() {
               let dx = this
               let waterFall = dx.$refs.waterFall
               dx.waterFall = waterFall.getContext('2d')
               waterFall.width = dx.waterFallWidth
               waterFall.height = dx.$refs.waterFallContent.offsetHeight
           },

绘制单行图像


rowToImageData(data) {
               let dx = this
               if (dx.$refs.waterFallContent !== undefined) {
                   let canvasHeight = Math.floor(dx.$refs.waterFallContent.offsetHeight / dx.waterFallHeight)
                   let imgOld = dx.waterFall.getImageData(0, 0, dx.waterFallWidth, canvasHeight * dx.waterFallIndex + 1)
                   const imageData = dx.waterFall.createImageData(data.length, 1)
                   for (let i = 0; i < imageData.data.length; i += 4) {
                       const cindex = dx.colorMapData(data[i / 4], 0, 130)
                       const color = dx.colormap[cindex]
                       imageData.data[i + 0] = color[0]
                       imageData.data[i + 1] = color[1]
                       imageData.data[i + 2] = color[2]
                       imageData.data[i + 3] = 255
                   }
                   for (let i = 0; i < canvasHeight; i++) {
                       dx.waterFall.putImageData(imageData, 0, i)
                   }
                   dx.waterFall.putImageData(imgOld, 0, canvasHeight)
               }
           },

返回数据对应的Colormap颜色


colorMapData(data, outMin, outMax) {
               let dx = this
               if (data <= dx.minNum) {
                   return outMin
               } else if (data >= dx.maxNum) {
                   return outMax
               }
               return Math.round(((data - dx.minNum) / (dx.maxNum - dx.minNum)) * outMax)
           },

鼠标移入瀑布图


           waterFallMove(event) {
               let dx = this
               let dataWidth = (dx.$refs.waterFallContent.offsetWidth / dx.waterFallWidth).toFixed(2)
               let dataHeight = (dx.$refs.waterFallContent.offsetHeight / dx.waterFallHeight).toFixed(2)
               let x = Math.floor(event.offsetX / dataWidth)
               let y = Math.floor(event.offsetY / dataHeight)
               try {
                   dx.$refs.tip.innerHTML = '数值:' + JSON.parse(JSON.stringify(dx.waterFallCopyList[y][x]))
                   let xx = event.offsetX + 5
                   let yy = event.offsetY - 20
                   if (event.offsetX > 1300) {
                       xx = event.offsetX - 160
                       yy = event.offsetY - 20
                   }
                   dx.$refs.tip.style.position = 'absolute'
                   dx.$refs.tip.style.left = xx + 'px'
                   dx.$refs.tip.style.top = yy + 'px'
                   dx.$refs.tip.style.display = 'block'
               } catch (e) {
                   dx.$refs.tip.style.display = 'none'
               }
           },

鼠标移出瀑布图


waterFallLeave() {
               let dx = this
               dx.$refs.tip.style.display = 'none'
           },

瀑布图假数据模拟


queryChartList() {
               let dx = this
               dx.waterFallWidth = 1500
               dx.waterFallHeight = 30
               let data = []
               for (let i = 0; i < 1500; i++) {
                   data.push(Math.floor(Math.random() * (20 - 1)) + 1)
               }
               if (dx.waterFall === null) {
                   dx.createWaterFallCanvas(data.length)
               }
               dx.rowToImageData(data)
               dx.waterFallCopyList.unshift(data)
               dx.waterFallIndex++
               if (dx.waterFallIndex > dx.waterFallHeight) {
                   dx.waterFallCopyList.pop()
               }
               dx.waterFallIntervals = setTimeout(() => {
                   dx.queryChartList()
               }, 1000)
           },

样式代码


.neirong {
       width: 1800px;
       height: 100%;
       margin: 80px auto;
       display: flex;
       justify-content: center;
   }

.legend {
       width: 25px;
       height: 500px;
   }

canvas {
       width: 100%;
       height: 100%;
   }

.waterFall {
       width: 1500px;
       height: 500px;
       position: relative;
   }

.tip {
       pointer-events: none;
       display: none;
       background-color: #0404049e;
       border-radius: 10px;
       color: #fff;
       padding: 10px;
       box-sizing: border-box;
   }

到这里这个Demo基本就是可以运行的,不会有任何报错,代码写的不是很高级,我本人也是个初级的小菜鸟,也是第一次写文章,希望大佬可以给出一些更好的建议我也会好好学习的,也希望那些遇到类似这个需求没什么思路的小伙伴可以借鉴我的踩坑之旅,可以更快的成长起来。

来源:https://juejin.cn/post/6947886319179677703

标签:vue,canvas,实时刷新,瀑布图
0
投稿

猜你喜欢

  • pytest框架之fixture详细使用详解

    2022-01-22 01:47:19
  • Python 如何截取字符函数

    2023-02-08 11:39:04
  • eWebEditor不支持IE,IE8,IE7,火狐,遨游的解决方法

    2011-06-06 07:57:00
  • 利用Python爬取微博数据生成词云图片实例代码

    2023-03-20 15:49:59
  • JavaScript 自定义事件之我见

    2024-04-10 10:50:01
  • python TKinter弹出式菜单的实例方法

    2023-03-25 05:59:54
  • 使用SQL2000将现有代码作为Web服务提供

    2009-02-19 17:20:00
  • python re模块findall()函数实例解析

    2022-07-07 13:38:40
  • php中支持多种编码的中文字符串截取函数!

    2023-09-27 02:08:15
  • python中如何使用正则表达式提取数据

    2023-12-09 17:24:21
  • MySQL里实现类似SPLIT的分割字符串的函数

    2024-01-22 15:41:54
  • python对csv文件追加写入列的方法

    2022-11-14 01:56:29
  • Django1.9 加载通过ImageField上传的图片方法

    2022-11-17 10:07:12
  • adonet基础示例分享(adonet连接数据库)

    2024-01-15 23:15:44
  • 浅析PHP中json_encode与json_decode的区别

    2023-07-04 04:46:46
  • 利用Google Ajax Library API加速常用js类库的载入

    2008-06-17 17:44:00
  • Python八皇后问题解答过程详解

    2021-09-09 18:06:17
  • python调用cmd命令行制作刷博器

    2023-07-26 15:18:35
  • Python入门教程(二)Python快速上手

    2023-10-16 08:54:09
  • phpmyadmin 数据导入导出问题

    2007-08-06 15:23:00
  • asp之家 网络编程 m.aspxhome.com