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;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM