• react之每日一更(实现canvas拖拽,增、删、改拖拽模块大小功能)


    效果图:

    import React, { Component } from 'react';
    import scaleImage from './images/scale.png';
    import closeImage from './images/close.png';
    import maskImage from './images/mask.png';
    import { Button, message } from 'antd';
    
    class EidtImage extends Component {
      constructor(props) {
        super(props);
        this.state = {
          bounder: 7,
          image1: {
            img: undefined,                                    // 保存图片对象
            src: maskImage, // 图片路径
            x: 50,                                             // 图片左上角x坐标
            y: 100,                                             // 图片左上角y坐标
             100,                                        // 用来绘制的宽度(注意不是图片自身的宽度,图片会被压缩显示)
            height: 20,                                       // 用来绘制图片的高度
            drag: false,                                       // 是否处于拖拽状态
            scale: false,                                      // 是否处于缩放状态
            scaleDirection: '',                                // 缩放方向
            scaleIcon: scaleImage,
            closeIcon: closeImage,
            selected: true,                                     //拖拽模块是否处于选中转态,true为是
            closeMoudle: false,                                   //true:关闭遮层,false展示遮层
            imageUrl: ''                                          //画布背景图
          },
          imgUrl: '',
          cansText: {},                                        //画布对象
          canva: {},
        }
      }
    
      componentDidMount = () => {
        this.canvasInit();
      }
      // 画布初始化
      canvasInit = () => {
        let canvasId = this.refs.canvas.id;
        let canva = document.getElementById(canvasId);
        const cansText = canva.getContext("2d");
        const { imageUrl } = this.props;
        this.setState({
          cansText, canva, imageUrl
        }, () => {
          // 加载图片
          this.loadimage();
        })
    
      }
    
      //加载
      loadimage = () => {
        const obj = this.state.image1;
        const { cansText, canva, imageUrl } = this.state;
        let bgImage = new Image();
        bgImage.crossOrigin = "anonymous";//解决图片跨域
        bgImage.src = imageUrl;
        bgImage.onload = function () {
          let bgImageW = bgImage.width;
          let bgImageH = bgImage.height;
          canva.width = 180;
          canva.height = 180 * bgImageH / bgImageW;
          cansText.drawImage(bgImage, 0, 0, 180, 180 * bgImageH / bgImageW);
          if (obj.closeMoudle) return;
          let image = new Image();
          image.crossOrigin = "anonymous";//解决图片跨域
          image.src = obj.src;
          image.onload = function () {
            cansText.drawImage(image, obj.x, obj.y, obj.width, obj.height);
            obj.image = image;
            if (obj.selected) {
              // 虚线
              cansText.setLineDash([5, 5]);//定义虚线的长度和间隔
              cansText.strokeStyle = "#fff";
              cansText.strokeRect(obj.x, obj.y, obj.width, obj.height);
              //渲染伸缩图标
              let scaleIcon = new Image();
              scaleIcon.crossOrigin = "anonymous";
              scaleIcon.src = obj.scaleIcon;
              scaleIcon.onload = function () {
                cansText.drawImage(scaleIcon, obj.x - 8, obj.y + obj.height - 12, 20, 20);
              }
              // 关闭遮层图标
              let closeIcon = new Image();
              closeIcon.crossOrigin = "anonymous";
              closeIcon.src = obj.closeIcon;
              closeIcon.onload = function () {
                cansText.drawImage(closeIcon, obj.x + obj.width - 10, obj.y - 10, 20, 20)
              }
            }
    
          }
        }
      }
    
      // 监听鼠标按下事件
      onmousedown = (e) => {
        if (e) e.persist();
        let that = this;
        let { bounder, image1 } = that.state;
        let mousex = e ? e.nativeEvent.offsetX : 1000;
        let mousey = e ? e.nativeEvent.offsetY : 1000;
        let bottom = image1.y + image1.height;
        let top = image1.y;
        let left = image1.x;
        let right = image1.x + image1.width;
    
    
        //判断,是否关闭遮层
        if (right - 10 < mousex && mousex < right + 10 && top - 10 < mousey && mousey < top + 10) {
          image1.closeMoudle = true;
        }
    
    
        // 判断,当前拖拽模块是否选中状态
        if (right + 10 < mousex || mousex < left - 10 || bottom + 10 < mousey || mousey < top - 10) {
          image1.selected = false;
        } else {
          image1.selected = true;
        }
    
        // 判断是缩放还是拖拽,若点击位置和边线的差大于bounder则认为是拖拽,否则是缩放
        if ((left + bounder <= mousex && mousex <= right - bounder) && (top + bounder <= mousey && mousey <= bottom - bounder)) {
          image1.drag = true;
          image1.scale = false;
          image1.scaleDirection = '';
        } else if (0 <= mousex - left && mousex - left <= bounder) {
          image1.scaleDirection = 'left';
          image1.scale = true;
          image1.drag = false;
        } else if (0 <= right - mousex && right - mousex <= bounder) {
          image1.scaleDirection = 'right';
          image1.scale = false;
          image1.drag = true;
        }
    
        if (0 <= mousey - top && mousey - top <= bounder) {
          image1.scaleDirection += 'top';
          image1.scale = false;
          image1.drag = true;
        } else if (0 <= bottom - mousey && bottom - mousey <= bounder) {
          image1.scaleDirection += 'bottom';
          image1.scale = true;
          image1.drag = false;
        }
        this.loadimage();
      }
      // 鼠标弹起,重置所有事件参数
      onmouseup = (e) => {
        e.persist();
        const { image1 } = this.state;
        // body...
        image1.drag = false;
        image1.scale = false;
        image1.scaleDirection = '';
        this.setState({ image1 });
      }
      // 鼠标移动事件
      onmousemove = (e) => {
        e.persist();
        const { image1, cansText, canva, imageUrl } = this.state;
        // body...
        let mousex = e.nativeEvent.offsetX;
        let mousey = e.nativeEvent.offsetY;
        if (image1.drag) {
          // 画背景图
          let bgImage = new Image();
          bgImage.crossOrigin = "anonymous" //解决图片跨域
          bgImage.src = imageUrl;
          bgImage.onload = function () {
            let bgImageW = bgImage.width;
            let bgImageH = bgImage.height;
            canva.width = 180;
            canva.height = 180 * bgImageH / bgImageW;
    
            // 鼠标移出canvas区域
            if (mousex < 0 || mousex >= 180 || mousey >= canva.height - 5 || mousey <= 0) {
              image1.drag = false;
              image1.scale = false;
            };
            cansText.drawImage(bgImage, 0, 0, 180, 180 * bgImageH / bgImageW);
    
            if (image1.closeMoudle) return;
    
            // 移动图片
            if (e.movementX || e.movementY) {
              let tem_imgx = image1.x + e.movementX;
              let tem_imgy = image1.y + e.movementY;
              image1.x = tem_imgx;
              image1.y = tem_imgy;
              if (image1.x + image1.width >= 180) {
                image1.x = 180 - image1.width;
              }
              if (image1.y + image1.height >= 180 * bgImageH / bgImageW) {
                image1.y = 180 * bgImageH / bgImageW - image1.height;
              }
    
              if (image1.y <= 0) {
                image1.y = 0;
              }
              if (image1.x <= 0) {
                image1.x = 0;
              }
              if (image1.selected) {
                //渲染伸缩图标
                let scaleIcon = new Image();
                scaleIcon.crossOrigin = "anonymous";
                scaleIcon.src = image1.scaleIcon;
                scaleIcon.onload = function () {
                  cansText.drawImage(scaleIcon, image1.x - 8, image1.y + image1.height - 12, 20, 20);
                }
                // 关闭遮层图标
                let closeIcon = new Image();
                closeIcon.crossOrigin = "anonymous";
                closeIcon.src = image1.closeIcon;
                closeIcon.onload = function () {
                  cansText.drawImage(closeIcon, image1.x + image1.width - 10, image1.y - 10, 20, 20)
                }
                // 虚线
                cansText.setLineDash([5, 5]);//定义虚线的长度和间隔
                cansText.strokeStyle = "#fff";
                cansText.strokeRect(image1.x, image1.y, image1.width, image1.height);
              }
              // 清空画布
              cansText.clearRect(image1.x, image1.y, image1.width, image1.height);
    
              // 被拖拽的图片
              cansText.drawImage(image1.image, image1.x, image1.y, image1.width, image1.height);
            };
          }
    
        }
    
        //缩放
        if (image1.scale) {
          // 画背景图
          let bgImage = new Image();
          bgImage.crossOrigin = "anonymous"//解决图片跨域
          bgImage.src = imageUrl;
          bgImage.onload = function () {
            let bgImageW = bgImage.width;
            let bgImageH = bgImage.height;
            canva.width = 180;
            canva.height = 180 * bgImageH / bgImageW;
            cansText.drawImage(bgImage, 0, 0, 180, 180 * bgImageH / bgImageW);
            // 缩放图片
            if (e.movementX || e.movementY) {
              let movex = e.movementX;
              let movey = e.movementY;
              if (movex !== 0 || movey !== 0) {
                //根据x缩放方向判断固定点
                if (image1.scaleDirection.search('right') !== -1) {
                  image1.width += movex;
                } else if (image1.scaleDirection.search('left') !== -1) {
                  image1.x += movex;
                  image1.width -= movex;
                }
                if (image1.scaleDirection.search('bottom') !== -1) {
                  image1.height += movey;
                } else if (image1.scaleDirection.search('top') !== -1) {
                  image1.height -= movey;
                  image1.y += movey;
                }
                // 清除画布
                cansText.clearRect(image1.x, image1.y, image1.width, image1.height);
                // 伸缩图标
                //渲染伸缩图标
                let scaleIcon = new Image();
                scaleIcon.crossOrigin = "anonymous";
                scaleIcon.src = image1.scaleIcon;
                scaleIcon.onload = function () {
                  cansText.drawImage(scaleIcon, image1.x - 8, image1.y + image1.height - 12, 20, 20);
                }
    
                // 关闭遮层图标
                let closeIcon = new Image();
                closeIcon.crossOrigin = "anonymous";
                closeIcon.src = image1.closeIcon;
                closeIcon.onload = function () {
                  cansText.drawImage(closeIcon, image1.x + image1.width - 10, image1.y - 10, 20, 20)
                }
                // 虚线
                cansText.setLineDash([5, 5]);//定义虚线的长度和间隔
                cansText.strokeStyle = "#fff";
                cansText.strokeRect(image1.x, image1.y, image1.width, image1.height);
                // 被拖拽的图片
                cansText.drawImage(image1.image, image1.x, image1.y, image1.width, image1.height);
              };
            };
          }
        }
      }
    
      // 保存图片
      saveImage = () => {
        let that = this;
        let { canva, imgUrl } = that.state;
        // 在导出画布之前,把一些图标、虚线去掉;
        this.onmousedown();
        setTimeout(function () {
          imgUrl = canva.toDataURL('image/jpeg'); //转换图片为dataURL
          that.setState({
            imgUrl
          }, () => {
            let obj={};
            if(that.props.id==='imageUrlFront'){
              obj={imageUrlFront:that.state.imgUrl}
            }else if(that.props.id==='imageUrlLeft'){
              obj={imageUrlLeft:that.state.imgUrl}
            }else if(that.props.id==='imageUrlRight'){
              obj={imageUrlRight:that.state.imgUrl}
            }
            that.props.parent.getEidtImageUrl(that, obj)
            message.success('保存成功')
          })
        }, 100);
      }
      // 重新编辑
      reMake = () => {
        let {image1}=this.state;
        let newImage=Object.assign({},image1,{closeMoudle:false,selected:true}) 
        this.setState({
          image1:newImage
        },()=>{
          this.canvasInit();
        })
      }
    
      render() {
        return (
          <React.Fragment>
            <div className="canvas-container">
              <canvas onMouseUp={this.onmouseup} onMouseDown={this.onmousedown} onMouseMove={this.onmousemove} id={this.props.id} ref="canvas" style={{ backgroundColor: '#fff' }}>您的浏览器不支持画布标签</canvas>
              <Button type="primary" size="small" onClick={this.saveImage}>保存图片</Button>
              <Button type="default" size="small" style={{ marginLeft: '35px' }} onClick={this.reMake}>重新编辑</Button>
            </div>
          </React.Fragment>
        );
      }
    
    }
    
    export default EidtImage;
  • 相关阅读:
    快速提取某一文件夹下所有文件名称
    CFileFind类的使用总结
    FILE文件流的中fopen、fread、fseek、fclose的使用
    经典损失函数:交叉熵(附tensorflow)
    tensorboard使用
    Windows下 tensorboard出现ValueError:Invalid format string
    新建全色或者resize(毫无价值,只是做记录)
    创建一个任意大小的全色矩阵 python
    转移图片位置
    getpatch
  • 原文地址:https://www.cnblogs.com/nimon-hugo/p/12668081.html
Copyright © 2020-2023  润新知