用vue canvas画一个能源电表和设备的监测图

发布于:2025-05-23 ⋅ 阅读:(25) ⋅ 点赞:(0)

先上图片!

为了记录下,智能电表,以及智能设备的监测。

正常数据应该从后端来,我为了本地展示,把数据搬前端来,后端代码就不传了。

上代码:

TreeCanvas.vue

<template>
    <div class="tree-container" ref="container" @wheel.prevent="handleWheel">
        <canvas ref="canvas" @mousedown="startDragging" @mousemove="onMouseMove" @mouseup="stopDragging"
            @mouseleave="stopDragging"></canvas>
    </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'

const canvas = ref(null)
const ctx = ref(null)
const container = ref(null)

// 树形数据结构
const treeData = {
    id: 1,
    name: '别墅总电表',
    type: 1,
    children: [
        {
            id: 2,
            name: 'F-1健身房',
            type: 2,
            error: 0,
            children: [
                {
                    id: 4,
                    name: '电表-器械区',
                    type: 1,
                    children: [
                        {
                            id: 8,
                            name: '跑步机',
                            type: 2,
                            error: 0,
                        }, {
                            id: 9,
                            name: '划船机',
                            type: 2,
                            error: 1,
                        },
                        {
                            id: 100,
                            name: '动感单车',
                            type: 2,
                            error: 0,
                        },

                    ]
                },
                {
                    id: 7,
                    name: '电表-娱乐圈',
                    type: 1,
                    children: [
                        {
                            id: 10,
                            name: '豪华影音室',
                            type: 2,
                            error: 0,
                            children: [
                                {
                                    id: 11,
                                    name: '电表03',
                                    type: 1,
                                    error: 0,
                                    children: [
                                        {
                                            id: 12,
                                            name: 'ktv运行设备',
                                            type: 2,
                                            error: 0,
                                        },
                                        {
                                            id: 13,
                                            name: '电竞房运行设备',
                                            type: 2,
                                            error: 0,
                                        }
                                    ]
                                }
                            ]
                        },
                    ]
                }
            ]
        },
        {
            id: 3,
            name: 'F-2',
            type: 2,
            error: 0,
        },
        {
            id: 5,
            name: 'F- -1宝马充电桩',
            type: 2,
            error: 1,
        }
    ]
}

let scale = 1
let offsetX = 0
let offsetY = 0
let isDragging = false
let lastX = 0
let lastY = 0
let deviceImg = null
let deviceImgd2 = null
let deviceImgd3 = null

async function loadDeviceImage() {
    //加载3种图片
    // 1 创建 Image 对象
    const image = new Image()
    // 2 引入图片
    image.src = require('@/assets/d.png')
    deviceImg = image


    // 1 创建 Image 对象
    const imaged2 = new Image()
    // 2 引入图片
    imaged2.src = require('@/assets/d2.png')
    deviceImgd2 = imaged2


    // 1 创建 Image 对象
    const imaged3 = new Image()
    // 2 引入图片
    imaged3.src = require('@/assets/d3.png')
    deviceImgd3 = imaged3

    console.log(deviceImgd2, deviceImgd3)
}



function drawTree(node, x, y, level) {
    const imgWidth = 25
    const imgHeight = 25
    const hGap = 200
    // const vGap = 200
    console.log('drawTree方法')
    console.log(node)
    // Draw current node
    if (deviceImg) {
        if (node.type == 1) {
            ctx.value.drawImage(deviceImgd3, x - imgWidth / 2, y - imgHeight / 2, imgWidth, imgHeight)
        } else if (node.type == 2) {
            if (node.error == 1) {
                ctx.value.drawImage(deviceImg, x - imgWidth / 2, y - imgHeight / 2, imgWidth, imgHeight)
            } else if (node.error == 0) {
                ctx.value.drawImage(deviceImgd2, x - imgWidth / 2, y - imgHeight / 2, imgWidth, imgHeight)
            }

        }

    }

    ctx.value.fillStyle = '#000'
    ctx.value.font = '12px sans-serif'
    ctx.value.textAlign = 'center'
    //  node.id;
    var text = ""
    if (node.error == 1) {
        text = node.name + "异常"
    } else {
        text = node.name
    }

    ctx.value.fillText(text, x, y + imgHeight / 2 + 15)

    // if (node.children && node.children.length > 0) {
    //     let totalHeight = (node.children.length - 1) * vGap
    //     let startY = y - totalHeight / 2

    //     node.children.forEach((child, i) => {
    //         const childX = x + hGap
    //         const childY = startY + i * vGap

    //         // Draw line to child
    //         ctx.value.beginPath()
    //         ctx.value.moveTo(x, y)
    //         ctx.value.lineTo(childX, childY)
    //         ctx.value.stroke()

    //         drawTree(child, childX, childY, level + 1)
    //     })
    // }

    if (node.children && node.children.length > 0) {
        let angleStep = Math.PI / (node.children.length + 1) // 角度步长
        for (let i = 0; i < node.children.length; i++) {
            let angle = -(Math.PI / 2) + (i + 1) * angleStep // 计算角度
            let childX = x + hGap * Math.cos(angle) // 根据角度计算新位置
            let childY = y + hGap * Math.sin(angle)

            // Draw line to child
            ctx.value.beginPath()
            ctx.value.moveTo(x, y)
            ctx.value.lineTo(childX, childY)
            ctx.value.stroke()

            drawTree(node.children[i], childX, childY, level + 1)
        }
    }
}

function draw() {
    const canvasEl = canvas.value
    const containerEl = container.value

    const devicePixelRatio = window.devicePixelRatio || 1
    const rect = containerEl.getBoundingClientRect()
    canvasEl.width = rect.width * devicePixelRatio
    canvasEl.height = rect.height * devicePixelRatio
    canvasEl.style.width = `${rect.width}px`
    canvasEl.style.height = `${rect.height}px`

    ctx.value = canvasEl.getContext('2d')
    ctx.value.setTransform(scale * devicePixelRatio, 0, 0, scale * devicePixelRatio, offsetX * devicePixelRatio, offsetY * devicePixelRatio)
    // ctx.value.clearRect(0, 0, canvasEl.width, canvasEl.height)
    ctx.value.clearRect(0, 0, canvasEl.width, canvasEl.height)
    console.log('draw方法')


    if (deviceImg) {
        drawTree(treeData, 100, rect.height / 2, 0)
    }
}

function handleWheel(e) {
    const zoomFactor = 1.1
    if (e.deltaY < 0) {
        scale *= zoomFactor
    } else {
        scale /= zoomFactor
    }

    draw()
}

function startDragging(e) {
    isDragging = true
    lastX = e.clientX
    lastY = e.clientY
}

function stopDragging() {
    isDragging = false
}

function onMouseMove(e) {
    if (!isDragging) return
    const dx = e.clientX - lastX
    const dy = e.clientY - lastY

    offsetX += dx
    offsetY += dy

    lastX = e.clientX
    lastY = e.clientY

    draw()
}

function resizeHandler() {
    draw()
}

onMounted(async () => {
    await loadDeviceImage()
    draw()
    window.addEventListener('resize', resizeHandler)
})

onBeforeUnmount(() => {
    window.removeEventListener('resize', resizeHandler)
})
</script>

<style scoped>
.tree-container {
    width: 100%;
    height: 600px;
    overflow: hidden;
    border: 1px solid #ccc;
    background-color: #f9f9f9;
}

canvas {
    display: block;
    cursor: grab;
}
</style>

引用的话,就在想用的地方,直接引组件用。


网站公告

今日签到

点亮在社区的每一天
去签到