最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue+canvas实现数据实时从上到下刷新瀑布图效果(类似QT的)

    正文概述 掘金(Carl323)   2021-04-06   655

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

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

    图例使用到的插件

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

    瀑布图主体内容

    1. 这里不多做解释了,都是一些原生标签还有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>
    
    1. 这里是用到的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
                }
            },
    
    1. 下面是具体的方法,写的比较粗略,大家凑活看吧,觉得有用的大家拿走,不足之处自由发挥修改

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

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


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

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    请问可以发下完整的demo么,最近项目正好要做瀑布图,有偿求助,谢谢了
    我的邮箱是2944115311@qq.com
    回复(0)

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元