在React中用canvas对图片标注的实现

在审核业务中难免会有需要对图片进行标注的需求,本次用一个最小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对图片标注内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一个基于react的图片裁剪组件示例

    开始 写了一年多vue,感觉碰到了点瓶颈,学习下react找找感觉.刚好最近使用vue写了个基于cropperJS的图片裁剪的组件,便花费了几个晚上的功夫用react再写一遍.代码地址 项目是使用create-react-app来开发的,省去了很多webpack配置的功夫,支持eslint,自动刷新等功能,使用前npm install并npm start即可.推荐同样是新学习react的人也用用看. 项目写的比较简陋,自定义配置比较差,不过也是完成了裁剪图片的基本功能,希望可以帮助到初学reac

  • React中上传图片到七牛的示例代码

    之前有写过类似的一篇文章,有位同学突然找来解惑,发现自己采用了另外的一个方法,这里也分享下,希望对使用reactjs的同学有帮助. 逻辑思路是这样子的,在componentDidMount中实现更新dom的操作,异步加载需要的资源文件,然后在加载完后实现qiniu的初始化操作.这里就不需要在webpack或者其他打包工具中去引入qiniu的包文件,导致打完包的文件过大了. 我这里使用了nodejs的库scriptjs, const $S = require('scriptjs'); 可以实现异步

  • React Native使用fetch实现图片上传的示例代码

    本文介绍了React Native使用fetch实现图片上传的示例代码,分享给大家,具体如下: 普通网络请求参数是JSON对象 图片上传的请求参数使用的是formData对象 使用fetch上传图片代码封装如下: let common_url = 'http://192.168.1.1:8080/'; //服务器地址 let token = ''; //用户登陆后返回的token /** * 使用fetch实现图片上传 * @param {string} url 接口地址 * @param {J

  • react的滑动图片验证码组件的示例代码

    业务需求,需要在系统登陆的时候,使用"滑动图片验证码",来验证操作的不是机器人. 效果图 使用方式 在一般的页面组件引用即可.onReload这个函数一般是用来请求后台图片的. class App extends Component { state = { url: "" } componentDidMount() { this.setState({ url: getImage() }) } onReload = () => { this.setState({

  • 探究react-native 源码的图片缓存问题

    本文为xcode模拟器测试,rn版本0.44.3 突然想学习下RN是如何封装ios中的UIImage的,看着看着发现图片的缓存问题是个坑... 先看js端图片使用的三种方式,依次排序1.2.3 <Image source={{uri:url}} style={{width:200,height:200}}/> // 1. 加载远程图片 <Image source={{uri:'1.png'}} style={{width:50,height:50}}/> //2.加载xcode中图

  • react 项目中引入图片的几种方式

    img标签引入图片 因为react其实是通过js的reader函数渲染的页面,所以直接写src="路径"是无法引入图片 我们可以像引入模块一样引入图片 import img from './../../../../asset/img/user.png' 需要用下面的方式引入 <img src={require('../images/picture.png')} alt="标签"/> 背景图片引入 1 第一种就是常规的 新建一个css文件,然后就可以直接写

  • React Native 图片查看组件的方法

    React Native 图片查看组件:react-native-image-viewer,纯JS组件,小巧快速的图标查看组件.支持图片放大缩小,支持图片加载失败设置替代图片,支持将图片保存到本地等功能. 效果图 安装方法 npm i react-native-image-zoom-viewer --save 使用示例 const images = [ { url: 'https://avatars2.githubusercontent.com/u/7970947?v=3&s=460', },

  • react quill中图片上传由默认转成base64改成上传到服务器的方法

    使用react-quill富文本编辑器,里面处理图片是默认转成base64,提交到后台的时候文件太大,因此这里改写处理image的逻辑,改成上传到服务器. 具体代码如下: 配置1 import Quill from 'quill' import ReactQuill from 'react-quill' import 'react-quill/dist/quill.core.css' import 'react-quill/dist/quill.snow.css' import QuillEmo

  • 在React中用canvas对图片标注的实现

    在审核业务中难免会有需要对图片进行标注的需求,本次用一个最小demo来演示如何对图片进行矩形标注. 首先我们要理解canvas是一块画布,而这块画布需要在我们要标注的图片上层,图片和canvas外层的div用相对位置,内层的图片和canvas用绝对位置,即可保证canvas重叠于图片之上.如图: 我们来看下canvas的初始化,在img.canvas中都有ref属性,不同的是img的ref属性直接就是一个useRef引用,而canvas中的ref是一个回调函数.它在组件被加载或卸载时会立即执行,

  • vue下如何利用canvas实现在线图片标注

    目录 组件代码如下 在开发过程中遇到的问题 web端实现在线图片标注在此做下记录,功能类似微信截图时的标注,包含画线.框.箭头和文字输入,思路是利用canvas画布,先把要标注的图片使用drawImage方法画在画布上,然后定义画线.框.箭头和文字输入的方法调用 组件代码如下 <template>   <div class="draw">     <div class="drawTop" ref="drawTop"

  • JS移动端/H5同时选择多张图片上传并使用canvas压缩图片

    最近在做一个H5的项目,里边涉及到拍照上传图片的功能以及识别图片的功能,这里对识别图片的功能不做赘述,不属本文范畴.我在做完并上线项目后,同事跟我提了一个要求是可不可以同时选择多张图片上传,我做的时候的想法是如果给file表单加了 multiple 属性就没有办法调用手机的摄像头拍照了,如果不加,就无法同时选择多张图片,于是我就照实跟同事说了这个情况.但回头一想,单张图片可以上传,那多张图片呢?于是就有了本文的内容. HTML5定义了 FileReader 作为文件 API 的重要成员用于读取文

  • 一款简单的jQuery图片标注效果附源码下载

    为了提高用户体验度,在一些电商网站和家居网站上我们会看到,一张图片中显示多种商品,点击每个商品可以弹出对应商品的简单介绍,包括价格等等,设计非常的人性化,今天我们通过实例给大家分享使用jQuery插件来实现这一效果. 先给大家展示下效果图: 效果演示          源码下载 HTML 首先,我们加载jQuery库和easypin插件. <script src="jquery.min.js"></script> <script src="jqu

  • Vue使用Canvas绘制图片、矩形、线条、文字,下载图片

    1 前言 1.1 业务场景 图片储存在后台中,根据图片的地址,在vue页面中,查看图片,并根据坐标标注指定区域. 由于浏览器的机制,使用 window.location.href 下载图片时,并不会保存到本地,会在浏览器打开. 2 实现原理 2.1 绘制画布 <el-dialog title="查看图片" :visible.sync="dialogJPG" append-to-body> <canvas id="mycanvas"

  • Python tkinter实现图片标注功能(完整代码)

    .tkinter tkinter是Python下面向tk的图形界面接口库,可以方便地进行图形界面设计和交互操作编程.tkinter的优点是简单易用.与Python的结合度好.tkinter在Python 3.x下默认集成,不需要额外的安装操作:不足之处为缺少合适的可视化界面设计工具,需要通过代码来完成窗口设计和元素布局. Python tkinter实现图片标注代码,代码如下所述: #!/usr/bin/python # -*- coding: UTF-8 -*- import os impor

  • JavaScript html5 canvas实现图片上画超链接

    本文实例为大家分享了html5 canvas在图片上画超链接的具体代码,供大家参考,具体内容如下 1. html <canvas id="canvasFile" style="margin-top:15px;" width="500" height="400"></canvas> <input type="button" id="btnRedo" value

  • 快速解决Canvas.toDataURL 图片跨域的问题

    如题,在将页面的图片地址进行本地输出时(Html2Canvas.js),因不同源存在跨域问题,会出现toDataURL访问权限问题: [Redirect at origin 'http://sub1.xx.com' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested res

  • Js利用Canvas实现图片压缩功能

    最近做的APP项目涉及到手机拍照上传图片,因为手机拍照的图片通常都比较大,所以上传的时候就会很慢.为此,需要对图片进行压缩处理来优化上传功能.以下是具体实现: /* * 图片压缩 * img 原始图片 * width 压缩后的宽度 * height 压缩后的高度 * ratio 压缩比率 */ function compress(img, width, height, ratio) { var canvas, ctx, img64; canvas = document.createElement

  • js HTML5 canvas绘制图片的方法

    本文实例为大家分享了HTML5 canvas绘制图片的具体代码,供大家参考,具体内容如下 demo.js window.onload=function() { createcanvas(); drawImage(); } function createcanvas() { var CANVAS=document.getElementById('mycanvas'); context=CANVAS.getContext('2d'); } function drawImage() { var img

随机推荐