<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在稽核業務中難免會有需要對圖片進行標註的需求,本次用一個最小demo來演示如何對圖片進行矩形標註。
首先我們要理解canvas是一塊畫布,而這塊畫布需要在我們要標註的圖片上層,圖片和canvas外層的div用相對位置,內層的圖片和canvas用絕對位置,即可保證canvas重疊於圖片之上。如圖:
我們來看下canvas的初始化,在img、canvas中都有ref屬性,不同的是img的ref屬性直接就是一個useRef參照,而canvas中的ref是一個回撥函數。它在元件被載入或解除安裝時會立即執行,載入時ref回撥接收當前元件範例作為引數,解除安裝時ref回撥接收null作為引數。在initCanvas函數中,用canvas的ref參照承接了canvas節點,並且通過drawImage函數,初始化了一塊400*400的畫布,第一個引數為需要繪製到的上下文元素:
<img src={lancome} ref={imgInstance} className="App-logo" alt="logo" /> <canvas className="canvas" ref={initCanvas} width="400px" height="400px" />
const canvasRef = useRef(null); const imgInstance = useRef(null); const initCanvas = useCallback((node) => { canvasRef.current = node; const context = node.getContext('2d'); context.drawImage(imgInstance.current, 0, 0, 400, 400); }, []);
接下來,我們通過invalidLocations來儲存之前的標註位置資訊,addInvalidLocation函數是為了新增標註位置資訊。最需要注意的是我們在useEffect中所監聽的三個函數,startDraw、drawingDeal和drawingEnd。
滑鼠落下時,startDraw為起始點的x,y座標賦值,並且拖拽狀態位isDrawing置為true。滑鼠移動時,drawingDeal函數會邊通過clearRect函數更新畫布,邊根據滑鼠的最新位置通過highlightInvalid來更新標註,經過確定矩形位置大小,內容填充,描邊三個步驟來繪製出矩形。滑鼠擡起時,drawingEnd函數會通過addInvalidLocation函數新增標註位置,然後初始化引數。
const [invalidLocations, setInvalidLocations] = useState([]); const addInvalidLocation = useCallback((newMark) => { setInvalidLocations([...invalidLocations, newMark]); }, [invalidLocations]) const highlightInvalid = (context, x1, y1, x2, y2) => { context.beginPath(); context.rect(x1, y1, x2 - x1, y2 - y1); context.fillStyle = 'rgba(255, 0, 0, 0.2)'; context.fill(); context.strokeStyle = '#FF0070'; context.lineWidth = 1; context.stroke(); console.log('drawing', x2, y2); }; const clearRect = (drawContext) => { drawContext.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height); }; useEffect(() => { const canvasElem = canvasRef.current; let x = 0; let y = 0; let isDrawing = false; const drawContext = canvasRef.current.getContext('2d'); let canvasRect; const lastCursorPosition = { x: 0, y: 0, }; const startDraw = (e) => { console.log(e.type, 'start'); canvasRect = canvasRef.current.getBoundingClientRect(); x = e.clientX - canvasRect.left; y = e.clientY - canvasRect.top; if (x < 0) x = 0; if (y < 0) y = 0; isDrawing = true; }; const drawingDeal = (e) => { console.log(e.type, 'move'); if (isDrawing) { const x1 = e.clientX - canvasRect.left; const y1 = e.clientY - canvasRect.top; clearRect(drawContext); highlightInvalid(drawContext, x, y, x1, y1); lastCursorPosition.x = x1; lastCursorPosition.y = y1; } }; const drawingEnd = () => { if (isDrawing) { if (lastCursorPosition.x && lastCursorPosition.y) { const width = lastCursorPosition.x - x + 1; const height = lastCursorPosition.y - y + 1; addInvalidLocation({ x, y, width, height }); lastCursorPosition.x = 0; lastCursorPosition.y = 0; } clearRect(drawContext); isDrawing = false; x = 0; y = 0; } }; canvasElem.addEventListener('mousedown', startDraw); canvasElem.addEventListener('mousemove', drawingDeal); canvasElem.addEventListener('mouseup', drawingEnd); return () => { canvasElem.removeEventListener('mousedown', startDraw); canvasElem.removeEventListener('mousemove', drawingDeal); canvasElem.removeEventListener('mouseup', drawingEnd); }; }, [invalidLocations, addInvalidLocation]);
在新增完標註位置之後,模板中我們通過迭代返回絕對定位的div來實現已經標註過的矩形。
<div className="img-wrap"> <img src={lancome} ref={imgInstance} className="App-logo" alt="logo" /> <canvas className="canvas" ref={initCanvas} width="400px" height="400px" /> {invalidLocations && invalidLocations.map((location, index) => { const { width, height, x, y } = location; return <div key={`${width}_${height}_${x}_${y}`} tabIndex={-1} className={'remark'} style={{ width: `${width}px`, height: `${height}px`, left: `${x}px`, top: `${y}px` }} ></div> })} </div>
最後效果:
到此這篇關於在React中用canvas對圖片標註的實現 的文章就介紹到這了,更多相關React canvas對圖片標註內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45