vue+canvas实现数据实时从上到下刷新瀑布图效果(类似QT的)
作者:Carl323 发布时间:2024-05-09 09:16:28
标签:vue,canvas,实时刷新,瀑布图
话不多说了,先上一张Demo图,实现的功能有:左侧图例、右侧瀑布图、鼠标移入弹出当前坐标对应的数据信息(有优化的空间,大家自由发挥)。
图例使用到的插件
这里推荐使用安装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.js是中国人创造出来的,简单易用,所以必须要支持一下Vue采用的MVVM设计模式也就是说model和view绑定 mode
- 1.虚拟环境它是一个虚拟化的概念,从电脑独立开辟出来的环境。通俗的来讲,虚拟环境就是借助虚拟机来把一部分内容独立出来,我们把这部分独立出来的
- 主要介绍了SQL删除语句DROP、TRUNCATE、 DELETE 的区别,帮助大家更好的理解和学习sql语句,感兴趣的朋友可以了解下DRO
- 准确地说, 这个标题是有问题的, go gin只能给浏览器返回操作cookie的指令, 真正执行cookie操作的是浏览器。 但广泛地来讲,
- 0. 学习目标栈和队列是在程序设计中常见的数据类型,从数据结构的角度来讲,栈和队列也是线性表,是操作受限的线性表,它们的基本操作是线性表操作
- 一、layui下拉复选实现的背景:实现一个管理员拥有多个权限二、 具体实现://依赖资源<link rel="stylesh
- 最近在处理语音检索相关的事。 其中用到语音识别,调用的是讯飞与百度的api,前者使用js是实现,后者用python3实现(因为自己使用pyt
- 近年,不论是正在快速增长的直播,远程教育以及IM聊天场景,还是在常规企业级系统中用到的系统提醒,对websocket的需求越来越大,对web
- 假设通过爬虫获得了一个自媒体.txt想要从这些关键词中提取流量最大的关键词可以通过如下算法实现:from smoothnlp.algorit
- 本文实例讲述了flask框架jinja2模板与模板继承。分享给大家供大家参考,具体如下:jinja2模板from werkzeug.cont
- 今天的文章来自 盏茶作酒 同学。他在老电脑中发现了一个加密的 zip 文件,于是用 Python 破解了文件密码。在破解的过程中出现了内存爆
- 一、安装github:https://github.com/kubernetes-client/python安装pip install ku
- 多版本并发控制Multiversion Concurrency Control大部分的MySQL的存储 引擎,比如InnoDB,Falcon
- 系列最后一篇来说说Python中的类与对象,Python这门语言是无处不对象,如果你曾浅要了解过Python,你应该听过Python是一种面
- 本文实例讲述了Python使用循环神经网络解决文本分类问题的方法。分享给大家供大家参考,具体如下:1、概念1.1、循环神经网络循环神经网络(
- python程序结构python“一切皆对象”,这是接触python听到最多的总结了。在python中最基层的单位应该就是对象了,对象需要靠
- 1.先停止mysqld.exe的进程2.打开cmd进入到你mysql的bin目录下输入此命令:mysqld --skip-grant-tab
- 今天要介绍的是,如何生成一个"继承"多个对象的实例。 比如,现在有一个"动物"对象的构造函数, fu
- 项目中大量用到图片加载,由于图片太大,加载速度很慢,因此需要对文件进行统一压缩第一种 一:安装包python -m pip ins
- python 批量添加的button 使用同一点击事件根据传递的参数进行区分。def clear_text():print '我只是