vue+canvas實(shí)現(xiàn)數(shù)據(jù)實(shí)時(shí)從上到下刷新瀑布圖效果(類似QT的)
話不多說(shuō)了,先上一張Demo圖,實(shí)現(xiàn)的功能有:左側(cè)圖例、右側(cè)瀑布圖、鼠標(biāo)移入彈出當(dāng)前坐標(biāo)對(duì)應(yīng)的數(shù)據(jù)信息(有優(yōu)化的空間,大家自由發(fā)揮)。
圖例使用到的插件
這里推薦使用安裝npm插件colormap
瀑布圖主體內(nèi)容
這里不多做解釋了,都是一些原生標(biāo)簽還有vue綁定的事件,可以根據(jù)實(shí)際項(xiàng)目情況自己封裝成組件,我這里是寫在一起的。
<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> <!--鼠標(biāo)移入彈出框--> <div ref="tip" class="tip"></div> </div> </div> </div> </div> </template>
這里是用到的Data數(shù)據(jù)
- colormap:顏色庫(kù)
- legend:圖例
- waterFall:瀑布圖
- waterFallList:瀑布圖源數(shù)據(jù)
- waterFallIndex:瀑布圖定時(shí)器用到的計(jì)數(shù)標(biāo)識(shí)
- waterFallCopyList:瀑布圖二維數(shù)組(用來(lái)顯示數(shù)據(jù)做的臨時(shí)儲(chǔ)存)
- waterFallIntervals:瀑布圖定時(shí)器
- waterFallWidth:瀑布圖的寬度(后端返回的數(shù)據(jù)length)
- waterFallHeight:瀑布圖定高度(也可以理解成渲染次數(shù) 例如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 } },
下面是具體的方法,寫的比較粗略,大家湊活看吧,覺(jué)得有用的大家拿走,不足之處自由發(fā)揮修改
方法調(diào)用這就不解釋了,離開頁(yè)面銷毀定時(shí)器。
mounted() { let dx = this dx.setColormap() dx.createLegendCanvas() dx.queryChartList() }, destroyed() { let dx = this clearInterval(dx.waterFallIntervals) },
創(chuàng)建顏色庫(kù)
這個(gè)地方具體看上面插件的官網(wǎng)有詳細(xì)的介紹
setColormap() { let dx = this let colormap = require('colormap') dx.colormap = colormap({ colormap: 'jet', nshades: 150, format: 'rba', alpha: 1, }) },
創(chuàng)建圖例
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) },
創(chuàng)建瀑布圖
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) } },
返回?cái)?shù)據(jù)對(duì)應(yīng)的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) },
鼠標(biāo)移入瀑布圖
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 = '數(shù)值:' + 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' } },
鼠標(biāo)移出瀑布圖
waterFallLeave() { let dx = this dx.$refs.tip.style.display = 'none' },
瀑布圖假數(shù)據(jù)模擬
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; }
到這里這個(gè)Demo基本就是可以運(yùn)行的,不會(huì)有任何報(bào)錯(cuò),代碼寫的不是很高級(jí),我本人也是個(gè)初級(jí)的小菜鳥,也是第一次寫文章,希望大佬可以給出一些更好的建議我也會(huì)好好學(xué)習(xí)的,也希望那些遇到類似這個(gè)需求沒(méi)什么思路的小伙伴可以借鑒我的踩坑之旅,可以更快的成長(zhǎng)起來(lái)。
到此這篇關(guān)于vue+canvas實(shí)現(xiàn)數(shù)據(jù)實(shí)時(shí)從上到下刷新瀑布圖效果(類似QT的)的文章就介紹到這了,更多相關(guān)vue+canvas實(shí)時(shí)刷新瀑布圖 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vue2.0/3.0雙向數(shù)據(jù)綁定的實(shí)現(xiàn)原理詳解
- 關(guān)于vuex強(qiáng)刷數(shù)據(jù)丟失問(wèn)題解析
- Vue 如何追蹤數(shù)據(jù)變化
- vue 數(shù)據(jù)(data)賦值問(wèn)題的解決方案
- Vue 重置data的數(shù)據(jù)為初始狀態(tài)操作
- Vue組件傳值過(guò)程中丟失數(shù)據(jù)的分析與解決方案
- SpringBoot+Vue實(shí)現(xiàn)數(shù)據(jù)添加功能
- 手寫Vue2.0 數(shù)據(jù)劫持的示例
- vue 數(shù)據(jù)雙向綁定的實(shí)現(xiàn)方法
- Vue中避免濫用this去讀取data中數(shù)據(jù)
- 用vue設(shè)計(jì)一個(gè)數(shù)據(jù)采集器
相關(guān)文章
Vue 頁(yè)面跳轉(zhuǎn)不用router-link的實(shí)現(xiàn)代碼
這篇文章主要介紹了 Vue 頁(yè)面跳轉(zhuǎn)不用router-link的實(shí)現(xiàn)代碼,文中給大家介紹了vue router-link跳轉(zhuǎn)傳值示例,需要的朋友可以參考下2018-04-04解決基于 keep-alive 的后臺(tái)多級(jí)路由緩存問(wèn)題
這篇文章主要介紹了解決基于 keep-alive 的后臺(tái)多級(jí)路由緩存問(wèn)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12vue新建項(xiàng)目并配置標(biāo)準(zhǔn)路由過(guò)程解析
這篇文章主要介紹了vue新建項(xiàng)目并配置標(biāo)準(zhǔn)路由過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12vue computed的set方法無(wú)效問(wèn)題及解決
這篇文章主要介紹了vue computed的set方法無(wú)效問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11vite打包出現(xiàn)"default"?is?not?exported?by?"no
這篇文章主要給大家介紹了關(guān)于vite打包出現(xiàn)"default"?is?not?exported?by?"node_modules/...問(wèn)題解決的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11vue3+vite+TS中使用element-plus按需引入ElLoading、ElMessage樣式失效解決
在項(xiàng)目中使用elementui確實(shí)是很方便的一件事,下面這篇文章主要給大家介紹了關(guān)于vue3+vite+TS中使用element-plus按需引入ElLoading、ElMessage樣式失效解決的相關(guān)資料,需要的朋友可以參考下2023-02-02vue按需加載組件webpack require.ensure的方法
本篇文章主要介紹了vue按需加載組件webpack require.ensure的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12