Vue+canvas realizes the effect of refreshing waterfall chart from top to bottom in real time (similar to QT)

Vue+canvas realizes the effect of refreshing waterfall chart from top to bottom in real time (similar to QT)

Without further ado, here is a demo picture. The functions implemented are: legend on the left, waterfall chart on the right, and data information corresponding to the current coordinates popping up when the mouse is moved (there is room for optimization, please feel free to play with it).

Plugins used in the illustration

It is recommended to install the npm plugin colormap

Waterfall chart body

I won’t explain it here. They are all native tags and vue-bound events. You can encapsulate them into components according to the actual project situation. I have written them together here.

<template>
    <div>
        <div class="content">
            <div class="neirong">
                <!--Legend-->
                <div class="legend">
                    <canvas ref="legend"></canvas>
                </div>
                <!--Waterfall Chart-->
                <div class="waterFall" ref="waterFallContent"
                     @mousemove="waterFallMove($event)"
                     @mouseleave="waterFallLeave"
                >
                    <canvas ref="waterFall"></canvas>
                    <!--Move the mouse into the pop-up box-->
                    <div ref="tip" class="tip"></div>
                </div>
            </div>
        </div>
    </div>
</template>

Here is the Data used

  • colormap: color library
  • legend: legend
  • waterFall: Waterfall Chart
  • waterFallList: waterfall chart source data
  • waterFallIndex: The counting index used by the waterfall chart timer
  • waterFallCopyList: waterfall chart two-dimensional array (used for temporary storage of display data)
  • waterFallIntervals: waterfall timer
  • waterFallWidth: width of the waterfall chart (length of data returned by the backend)
  • waterFallHeight: The height of the waterfall (can also be understood as the number of renderings, for example, 30 renderings are completed)
  • maxNum: maximum value of the legend
  • minNum: minimum value of the legend
<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
            }
        },

The following is a specific method. It is written roughly. Please read it carefully. If you find it useful, please take it away. If there are any shortcomings, you can modify it freely.

I won't explain the method call here, leaving the page will destroy the timer.

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

Create a color library

For details, please refer to the official website of the above plug-in for detailed introduction.

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

Creating a Legend

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)
            },

Creating a waterfall chart

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

Draw a single line image

 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)
                }
            },

Returns the Colormap color corresponding to the data

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)
            },

Move the mouse into the waterfall chart

            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 = 'Value:' + 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'
                }
            },

Move the mouse out of the waterfall chart

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

Waterfall chart fake data simulation

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)
            },

Style Code

.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;
    }

At this point, the Demo can basically run without any errors. The code is not very advanced. I am also a beginner and this is my first time writing an article. I hope the big guys can give me some better suggestions and I will study hard. I also hope that friends who encounter similar requirements and have no ideas can learn from my experience of stepping into the pit and grow faster.

This is the end of this article about how vue+canvas achieves real-time data refresh from top to bottom waterfall chart effect (similar to QT). For more related vue+canvas real-time refresh waterfall chart content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of the implementation principle of Vue2.0/3.0 two-way data binding
  • Analysis on the problem of data loss caused by forced refresh of vuex
  • How does Vue track data changes?
  • Solution to Vue data assignment problem
  • Vue resets data to its initial state
  • Analysis and solution of data loss during Vue component value transfer
  • SpringBoot+Vue realizes data adding function
  • Handwritten Vue2.0 data hijacking example
  • Vue data two-way binding implementation method
  • Avoid abusing this to read data in data in Vue
  • Design a data collector with vue

<<:  Detailed explanation of how to solve the conflict of project URLs caused by setting the default path of Tomcat

>>:  Mysql 5.7.18 Using MySQL proxies_priv to implement similar user group management

Recommend

Python Flask WeChat applet login process and login api implementation code

1. Let’s take a look at the effect first Data ret...

Use native js to simulate the scrolling effect of live bullet screen

Table of contents 1. Basic principles 2. Specific...

Nginx content cache and common parameter configuration details

Use scenarios: The project's pages need to lo...

Sample code of uniapp vue and nvue carousel components

The vue part is as follows: <template> <...

Drop-down menu implemented by HTML+CSS3+JS

Achieve results html <div class="containe...

Some questions about hyperlinks

I am very happy to attend this episode of potato ...

Detailed code examples of seven methods for vertical centering with CSS

When we edit a layout, we usually use horizontal ...

How to use boost.python to call c++ dynamic library in linux

Preface Recently I started using robot framework ...

How to implement scheduled backup of MySQL database

1. Create a shell script vim backupdb.sh Create t...

The difference and use of json.stringify() and json.parse()

1. Differences between JSON.stringify() and JSON....

The most commonly used HTML tags to create web pages

1. Optimization of commonly used HTML tags HTML s...

3D tunnel effect implemented by CSS3

The effect achievedImplementation Code html <d...

How to set a fixed IP address in CentOS7 virtual machine

Since my development environment is to install Ce...

Teach you how to build the vue3.0 project architecture step by step

Table of contents Preface: 1. Create a project wi...