canvas-事件交互

一花一世界,一樹一菩提javascript

canvas事件交互

canvas本質上是一張位圖,全部這張圖片是支持鼠標的各類事件的,但對於其畫布上的內容,並不支持dom事件,和svg這個是最大的區別css

常見的dome事件有

onclick, ondbclick, onmouseover, onmouseout, onmouseleave, onmousedown, onmouseup, (還有幾個拖拽的事件,這裏就不說了)java

echarts 全部的事件 const MOUSE_EVENT_NAMES = [ 'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove','mousedown', 'mouseup', 'globalout', 'contextmenu']canvas

下面我以一個簡單的列子,演示一下canvas事件交互

實現一個簡單的餅圖hover效果markdown

根據前面幾個文章咱們首先畫一個簡單的餅圖echarts

1.畫一個簡單的餅圖,而且記錄下每一個扇形的數據,包括屬性,開始角度,半徑,顏色,等等dom

tm1333.gif

// hover 爲鼠標移動上去是的效果


data() {
        return {
            canvas: null,
            ctx: null,
            isFill: false,
            isShowHover: false,
            hoverstyle: {
                left: 300,
                top: 300
            },
            hoverItem: {
                item: {}
            },
            allArcs: [],
            r: 150,
            count: [
                {
                    name: '腳盆雞',
                    num: 30
                },
                {
                    name: '棒子',
                    num: 60
                },
                {
                    name: '長鼻象',
                    num: 50
                },
                {
                    name: '小兔子',
                    num: 99
                },
                {
                    name: '鷹醬',
                    num: 99
                },
                {
                    name: '毛熊',
                    num: 80
                }
            ],
            colors: ['#eeeeee', 'HotPink', 'green', 'red', 'blue', '#d4d4d5']
        }
    },

// 初始化數據
initcanvas() {
            if (this.count && this.count.length > 0) {
                let allcount = this.count.reduce((a, b) => {
                    return a + b.num
                }, 0)
                console.log(allcount)
                let newdegree = 0
                this.count.forEach((p, index) => {
                    let jd = (p.num / allcount) * 2 * Math.PI
                    this.allArcs.push({
                        item: p,
                        startdegree: newdegree,
                        enddegree: jd + newdegree,
                        fillStyle: this.colors[index]
                    })
                    newdegree += jd
                })
            }
        },
        
        

複製代碼
  1. 給該canvas添加鼠標事件
addlistenCanvas() {
            // 事件綁定(這裏有一個要注意的,我這裏用了bind方法,是爲了將「mousedownEvent」方法內的this指向切換到Canvas)
            this.canvas.addEventListener('mousemove', this.mousehoverEvent.bind(this)) // 點擊事件

            // 事件綁定(這裏有一個要注意的,我這裏用了bind方法,是爲了將「mousedownEvent」方法內的this指向切換到Canvas)
            this.canvas.addEventListener('click', this.mouseClickEvent.bind(this))
        },
複製代碼

3.當鼠標hover時重新處理餅圖的數據svg

mousehoverEvent(e) {
            let _self = this
            let fn = function() {
                _self.changeallArcs(e)
                _self.drawarc()
            }
            throttle(fn, 100)
        },
        changeallArcs(e) {
            const _self = this
            const x = e.layerX // 相對於畫布的x偏移量
            const y = e.layerY // 相對於畫布的y偏移量
            // 判斷點的位置是否在餅圖裏面
            console.log(x, y)
            let t = (x - 300) * (x - 300) + (y - 300) * (y - 300)
            if (t < (_self.r * _self.r)) {
                _self.allArcs.forEach(p => {
                    let degree = Math.atan2((x - 300), -(y - 300))
                    console.log(degree)
                    if (degree <= Math.PI / 2) {
                        degree = (3 * Math.PI) / 2 + degree
                    } else {
                        degree = degree - Math.PI / 2
                    }
                    if (p.startdegree < degree && degree < p.enddegree) {
                        p.hover = true
                        _self.hoverItem = p
                        _self.isShowHover = true
                    } else {
                        p.hover = false
                    }
                })
                _self.hoverstyle = {
                    left: x + 20,
                    top: y + 10
                }
            } else {
                _self.allArcs.forEach(p => {
                    p.hover = false
                })
                _self.hoverItem = {}
                _self.isShowHover = false
            }
        },
複製代碼

4 重新畫整個餅圖調用的方法ui

drawarc() {
            this.ctx.clearRect(0, 0, 600, 600)
            this.allArcs.forEach((p, index) => {
                if (p.hover) {
                    this.ctx.beginPath()
                    this.ctx.shadowColor = 'rgba(0, 0, 0, 0.55)'
                    this.ctx.shadowOffsetX = '-5'
                    this.ctx.shadowOffsetY = '5'
                    this.ctx.shadowBlur = '10'
                    this.ctx.moveTo(300, 300)
                    this.ctx.arc(300, 300, this.r + 6, p.startdegree, p.enddegree, false)
                    this.ctx.closePath()
                    this.ctx.fillStyle = p.fillStyle
                    this.ctx.fill()
                } else {
                    this.ctx.beginPath()
                    this.ctx.shadowColor = 'none'
                    this.ctx.shadowOffsetX = '0'
                    this.ctx.shadowOffsetY = '0'
                    this.ctx.shadowBlur = '0'
                    this.ctx.moveTo(300, 300)
                    this.ctx.arc(300, 300, this.r, p.startdegree, p.enddegree, false)
                    this.ctx.closePath()
                    this.ctx.fillStyle = p.fillStyle
                    this.ctx.fill()
                }
            })
        },

複製代碼

5.完整的代碼this

<template>
    <div class="main-c"> <h1>建立HTML5 canvas事件交互</h1> <div class="mycanvas"> <canvas id="tutorial" width="600px" height="600px" ref="canvas" style="border: 1px solid #999;"></canvas> <div class="canvashover" v-if="isShowHover" :style="{ left: '0px', top: '0px', transform: `translate(${hoverstyle.left}px, ${hoverstyle.top}px)` }"> <ul> <span>名稱:</span >{{ hoverItem.item.name }} </ul> <ul> <span>戰鬥力:</span >{{ hoverItem.item.num }} </ul> </div> </div> <br /> </div> </template> <script> import throttle from '../../utils/debounce.js' /** @type {HTMLCanvasElement} */ export default { name: 'HTML5canvas', data() { return { canvas: null, ctx: null, isFill: false, isShowHover: false, hoverstyle: { left: 300, top: 300 }, hoverItem: { item: {} }, allArcs: [], r: 150, count: [ { name: '腳盆雞', num: 30 }, { name: '棒子', num: 60 }, { name: '長鼻象', num: 50 }, { name: '小兔子', num: 99 }, { name: '鷹醬', num: 99 }, { name: '毛熊', num: 80 } ], colors: ['#eeeeee', 'HotPink', 'green', 'red', 'blue', '#d4d4d5'] } }, mounted() { // 獲取canvas元素 this.canvas = document.getElementById('tutorial') // 獲取繪製二維上下文 this.ctx = this.canvas.getContext('2d') this.initcanvas() this.drawarc() this.addlistenCanvas() }, methods: { initcanvas() { if (this.count && this.count.length > 0) { let allcount = this.count.reduce((a, b) => { return a + b.num }, 0) console.log(allcount) let newdegree = 0 this.count.forEach((p, index) => { let jd = (p.num / allcount) * 2 * Math.PI this.allArcs.push({ item: p, startdegree: newdegree, enddegree: jd + newdegree, fillStyle: this.colors[index] }) newdegree += jd }) } }, drawarc() { this.ctx.clearRect(0, 0, 600, 600) this.allArcs.forEach((p, index) => { if (p.hover) { this.ctx.beginPath() this.ctx.shadowColor = 'rgba(0, 0, 0, 0.55)' this.ctx.shadowOffsetX = '-5' this.ctx.shadowOffsetY = '5' this.ctx.shadowBlur = '10' this.ctx.moveTo(300, 300) this.ctx.arc(300, 300, this.r + 6, p.startdegree, p.enddegree, false) this.ctx.closePath() this.ctx.fillStyle = p.fillStyle this.ctx.fill() } else { this.ctx.beginPath() this.ctx.shadowColor = 'none' this.ctx.shadowOffsetX = '0' this.ctx.shadowOffsetY = '0' this.ctx.shadowBlur = '0' this.ctx.moveTo(300, 300) this.ctx.arc(300, 300, this.r, p.startdegree, p.enddegree, false) this.ctx.closePath() this.ctx.fillStyle = p.fillStyle this.ctx.fill() } }) }, addlistenCanvas() { // 事件綁定(這裏有一個要注意的,我這裏用了bind方法,是爲了將「mousedownEvent」方法內的this指向切換到Canvas) this.canvas.addEventListener('mousemove', this.mousehoverEvent.bind(this)) // 點擊事件 // 事件綁定(這裏有一個要注意的,我這裏用了bind方法,是爲了將「mousedownEvent」方法內的this指向切換到Canvas) this.canvas.addEventListener('click', this.mouseClickEvent.bind(this)) }, mousehoverEvent(e) { let _self = this let fn = function() { _self.changeallArcs(e) _self.drawarc() } throttle(fn, 100) }, changeallArcs(e) { const _self = this const x = e.layerX // 相對於畫布的x偏移量 const y = e.layerY // 相對於畫布的y偏移量 // 判斷點的位置是否在餅圖裏面 console.log(x, y) let t = (x - 300) * (x - 300) + (y - 300) * (y - 300) if (t < (_self.r * _self.r)) { _self.allArcs.forEach(p => { let degree = Math.atan2((x - 300), -(y - 300)) console.log(degree) if (degree <= Math.PI / 2) { degree = (3 * Math.PI) / 2 + degree } else { degree = degree - Math.PI / 2 } if (p.startdegree < degree && degree < p.enddegree) { p.hover = true _self.hoverItem = p _self.isShowHover = true } else { p.hover = false } }) _self.hoverstyle = { left: x + 20, top: y + 10 } } else { _self.allArcs.forEach(p => { p.hover = false }) _self.hoverItem = {} _self.isShowHover = false } }, mouseClickEvent(e) { const x = e.layerX // 相對於畫布的x偏移量 const y = e.layerY // 相對於畫布的y偏移量 // 判斷點的位置是否在餅圖裏面 this.changeallArcs(e) let object = this.allArcs.find(p => p.hover) console.log(object) this.$message.info(`當前點擊點的座標是x:${x},y:${y},當前點擊的對象是名稱:${object.item.name},戰鬥力:${object.item.num}`) } } } </script> <style scoped lang="scss"> .main-c { padding: 15px; h1 { font-size: 18px; line-height: 36px; } h3 { padding-top: 10px; } .tutor { border: 0px solid #eee; position: relative; z-index: 1; } h4 { position: absolute; top: 23px; font-size: 28px; font-weight: bold; } #tutorial2 { border: 1px solid #999; } .mycanvas { position: relative; .canvashover { position: absolute; border: 1px solid #eee; background-color: #eee; opacity: 0.9; box-shadow: 1px 1px 1px 1px 1px; padding: 10px; border-radius: 5px; transition: 1s; span { padding: 5px 0px; } } } } </style> 複製代碼
相關文章
相關標籤/搜索