1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
| import React, { useCallback, useEffect, useMemo, useState } from 'react'; import Konva from "konva"; import { useRedux } from '@/hooks/useRedux';
let stage; // 定义画布 let layer; // 图层 let grids; // 网格 let mousedown = false; let startPos: { x: number, y: number } | null; // 鼠标点击当前的坐标(坐标对标格子的下标) const count = 25; // 总共 x,y分别都是25个格子 const itemW = 20; // 每个网格的宽度 const itemH = 20; // 每个网格的高度 let detectAreaData: any = []; // 整个检测区域 // detectAreaData是这样的一个结构 // [[true,true,false...25个],...]25个 // 就是总共从0开始,一共25个下标,每个下标又是一个数组,数组里是25个true/false
interface IProps { drawing: boolean; // 是否开启绘制模式 }
export interface ISelectGridData { x: number; y: number; }
export const PreviewSettingBox: React.FC<IProps> = (props) => { const { drawing } = props; const canvasContainerRef = React.useRef<HTMLDivElement>(null); const [selectGridData, setSelectGridData] = useState<ISelectGridData[]>();
const handleRender = useCallback(() => { const data: { x:number;y:number }[] = []; for (let x = 0; x < count; x++) { for (let y = 0; y < count; y++) { if (detectAreaData?.length > 0 && detectAreaData[x][y] === true) { // 为true就是画上的 grids[x][y].attrs.stroke = "red"; grids[x][y].attrs.fill = "rgba(255,0,0,0.3)"; grids[x][y].attrs.zIndex = 399; data.push({ x,y }); } else { grids[x][y].attrs.stroke = "rgba(0,0,0,0.3)"; grids[x][y].attrs.fill = null; grids[x][y].attrs.zIndex = 0; } } } setSelectGridData(data); layer.draw(); }, [])
// 根据鼠标的坐标去判断选中还是取消区域 const selectGridRect = useCallback((x1: number, y1: number, x2: number, y2: number) => { for (let x = 0; x < count; x++) { for (let y = 0; y < count; y++) { if (x >= x1 && x <= x2 && y >= y1 && y <= y2) { detectAreaData[x][y] = true; } else { detectAreaData[x][y] = false; } } } handleRender(); }, [handleRender])
// 为每个网格添加鼠标的监听事件 or 移除事件 const updateDrawCanvas = useCallback(() => { for (let x = 0; x < count; x++) { for (let y = 0; y < count; y++) { grids[x][y].removeEventListener("mousemove"); grids[x][y].removeEventListener("click"); grids[x][y].on("mousemove", (e) => { if (mousedown) { if (e.evt.which === 1) { if (!startPos) { startPos = { x, y }; } else { selectGridRect(startPos.x, startPos.y, x, y); } } } }); if (detectAreaData?.length > 0 && detectAreaData[x][y] === true) { grids[x][y].attrs.stroke = "red"; grids[x][y].attrs.fill = "rgba(255,0,0,0.3)"; grids[x][y].attrs.zIndex = 399; } else { grids[x][y].attrs.stroke = "rgba(0,0,0,0.3)"; grids[x][y].attrs.fill = null; grids[x][y].attrs.zIndex = 0; } } } layer.draw(); }, [selectGridRect])
const initStage = useCallback(() => { if (stage) { stage.destroy(); } stage = new Konva.Stage({ container: canvasContainerRef.current!, width: 500, height: 500, dragBoundFunc: (pos) => { return pos; }, }); stage.on("mousedown", () => { mousedown = true; // 只有在鼠标点击的那一刻,才开始监听画布 }); stage.on("mouseup", () => { mousedown = false; startPos = null; }); stage.on("mouseleave", () => { mousedown = false; }); }, [])
const initGrids = useCallback(() => { if (layer) { layer.destroy(); } layer = new Konva.Layer(); grids = new Array<Array<Konva.Rect>>(); for (let x = 0; x < count; x++) { // 初始化网格 grids[x] = []; detectAreaData[x] = []; for (let y = 0; y < count; y++) { detectAreaData[x][y] = []; const gridItem = new Konva.Rect({ ...{ x: x * itemW, y: y * itemH, width: itemW, height: itemH, }, name: "rect", strokeWidth: 1, draggable: false, stroke: "rgba(0,0,0,0.3)", fill: "white" }); grids[x].push(gridItem); layer.add(gridItem); } } stage.add(layer); layer.draw(); }, [])
useEffect(() => { if (drawing) { initStage(); initGrids(); } }, [drawing, initGrids, initStage])
useEffect(() => { if (drawing && detectAreaData?.length > 0) { updateDrawCanvas(); } }, [drawing, updateDrawCanvas])
return useMemo(() => { return ( <div className='canvas-wrap' id="canvas-wrap"> { drawing && <div ref={canvasContainerRef} style={{ width: "100%", height: "100%" }}></div> } { selectGridData?.length && <div> { selectGridData.map((item) => { return <p>x:{item.x}, y:{item.y}</p> }) } </div> } </div> ) }, [drawing, selectGridData]) };
|