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坐标
        width: 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;

 

posted @ 2020-04-09 17:05  KG-work-space  阅读(1073)  评论(0编辑  收藏  举报