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

摘要:
呈现:importReact,{Component}来自“react”;importscaleImagefrom'./images/scale。png';importcloseImagefrom'./images/close。png';importmaskImagefrom'./images/mask。png';从“td”导入{Button,message};Ei类

效果图:

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

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;

免责声明:文章转载自《react之每日一更(实现canvas拖拽,增、删、改拖拽模块大小功能)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇AWS上的游戏服务:Lumberyard + Amazon GameLift + Twitch神经网络编程入门【转】下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

vue对比其他框架

对比其他框架React React 和 Vue 有许多相似之处,它们都有: 使用 Virtual DOM 提供了响应式(Reactive)和组件化(Composable)的视图组件。 将注意力集中保持在核心库,伴随于此,有配套的路由和负责处理全局状态管理的库。 性能简介 Vue 的性能是优于 React 的。如果你对此表示怀疑,请继续阅读。我们会解释为...

react 装饰器配置

React 装饰器配置 首先安装:@babel/plugin-proposal-decorators npm install -D @babel/plugin-proposal-decorators 根目录创建config-overrides.js const { override, addDecoratorsLegacy } = require...

钉钉小程序中canvas绘图模糊(环形进度条 )

在钉钉小程序中使用vantUI绘制的环形进度条在手机端查看时非常模糊有锯齿,解决方法: 将canvas的宽高扩大10倍再用zoom样式进行缩小。 绘制40x40像素的环形进度条代码: 在pages/index.axml中: // 在页面中设置环形进度条的size和进度条宽度为你想要的大小的10倍或更高 // 这里只设置了size <van-circl...

React Native Image多种加载图片方式

React-NativeImage加载图片方式解析 1.加载当前工程文件夹下图片 <Image style={styles.image} source={require('./TT2.jpg')} /> 2.加载当前应用沙盒文件内图片 分析: 假定图片存储在document文件夹下(document/TT1.jpg) 理论上这个加载方式和第一种...

要过年啦,用canvas做了个烟火效果

  声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢!   要过年了,过年想到的就是放烟火啦。。。。于是就用canvas写了个放烟火的效果,鼠标点击也会产生烟火,不过不要产生太多烟火哦,一个烟火散出的粒子是30到200个之间,当页面上的粒子数量达到一定的时候,页面就会很卡咯,我也没特意去优化神马的。以后有空再说吧。   直接上DEMO吧:放烟火 ...

第3章 从Flux到Redux

第3章 从Flux到Redux 3.1 Flux 单向数据流,React是用来替换Jquery的,Flux是以替换Backbone.js、Ember.js等MVC框架为主的。 actionTypes.js定义action类型; actions.js定义action构造函数,决定了这个功能模块可以接受的动作; reducer.js定义这个功能模块如何响应ac...