为canvas绘制的图形设置点击事件

效果:

 
原理:
给canvas设置点击事件,点击时获取点击位置的信息,通过判断点击位置是否包含在图形中来执行对应的效果。
 
详解:
1.通过getBoundingClientRect方法获取canvas相对于可视区域的偏移量
2.canvas点击事件触发时使用clientX、clientY方法获取点击位置,计算可得到点击位置在canvas中的坐标
3.清空画布
4.重绘画布,在绘制完每个图形的时候都执行一次isPointInPath方法判断点击位置是否在该图形中,决定是否要执行onClick事件
 
代码:(react hook语法)
 
index.js
 1 import React, { useEffect, useRef, useState } from 'react';
 2 import { DrawImg } from './draw';
 3 import { MenuInfo } from './config';
 4 import styles from './index.less';
 5 
 6 const Home = () => {
 7     // canvas
 8     const meCanvas = useRef();
 9     // 画布
10     const ctx = useRef();
11     // canvas位置
12     const [cInfo, setCInfo] = useState({ top: 0, left: 0 });
13 
14     /* 获取canvas位置 */
15     useEffect(() => {
16         //使canvas铺满可视区域
17         meCanvas.current.width = document.documentElement.clientWidth;
18         meCanvas.current.height = document.documentElement.clientHeight;
19         //更新canvas位置
20         setCInfo(meCanvas.current.getBoundingClientRect())
21     }, [])
22 
23     /* 绘制图形 */
24     useEffect(() => {
25         ctx.current = meCanvas.current.getContext('2d');
26         const qbb = ctx.current;
27         qbb.strokeStyle = "#fff";
28         qbb.fillStyle = "#fff";
29         MenuInfo.forEach(i => {
30             DrawImg({
31                 ctx: qbb, ...i, onClick: () => {
32                     console.log(i.msg)
33                 }
34             })
35         })
36     }, [])
37 
38     /* 画布点击事件 */
39     const CanvasOnClick = (e) => {
40         ctx.current.clearRect(0, 0, meCanvas.current.width, meCanvas.current.height);
41         MenuInfo.forEach(i => {
42             DrawImg({
43                 ctx: ctx.current, ...i, onClick: () => {
44                     console.log(i.msg)
45                 }
46             }, { x: e.clientX - cInfo.left, y: e.clientY - cInfo.top })
47         })
48     }
49 
50     return <div>
51         <canvas onClick={CanvasOnClick} ref={meCanvas} className={styles.meCanvas} width={1000} height={1000}></canvas>
52     </div>
53 }
54 
55 export default Home;

 

draw.js
/* 绘制六边形 */
export const DrawImg = (ctxMsg, position) => {
    const { ctx, x = 50, y = 50, length = 50, onClick = () => { } } = ctxMsg;
    const meLength = Math.sqrt(Math.pow(length, 2) / 2);
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x + meLength, y - meLength);
    ctx.lineTo(x + 2 * meLength, y);
    ctx.lineTo(x + 2 * meLength, y + length);
    ctx.lineTo(x + meLength, y + length + meLength);
    ctx.lineTo(x, y + length);
    ctx.lineTo(x, y);

    if (position && ctx.isPointInPath(position.x, position.y)) {
        ctx.fill();
        ctx.stroke();
        onClick();
    } else {
        ctx.stroke();
    }
}

  

config.js
/* 菜单信息 */
export const MenuInfo = [
    { x: 100, y: 100, msg: 1 },
    { x: 200, y: 100, msg: 2 },
    { x: 300, y: 100, msg: 3 },
    { x: 400, y: 100, msg: 4 },
]

  

index.less
.meCanvas{
    background-color: black;
}

  

 
 
 
 
 
 
 

posted @ 2021-02-13 10:49  那一天的河川  阅读(5364)  评论(0)    收藏  举报