效果图:

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;

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

  1. HTML5之Canvas时钟(网页效果--每日一更)

    今天,带来的是使用HTML5中Canvas标签实现的动态时钟效果. 话不多说,先看效果:亲,请点击这里 众所周知,Canvas标签是HTML5中的灵魂,HTML5 Canvas是屏幕上的一个由Java ...

  2. CSS3之图片3D翻转效果(网页效果--每日一更)

    今天,带来的是纯CSS3的效果--图片3D翻转. 请看效果:亲,请点击这里 这个效果主要还是运用了CSS3的transform变形属性,与上个效果不同的是,这次并不是动画,所以没有采用animatio ...

  3. CSS3之绽放的花朵(网页效果--每日一更)

    今天,带来的是纯CSS3打造的效果--绽放的花朵. 先来看效果吧:亲,请点击这里 这是纯CSS3样式打造的效果,关键是采用了animation属性和transform属性.详细请看下面代码. HTML ...

  4. JQuery图片轮播滚动效果(网页效果--每日一更)

    今天,带来的是一个图片的轮播滚动效果! 先来看一下效果展示:亲,请点击这里 原理很简单,设置一个定时器,使图片列表在每隔一段时间后滚动一次.而循环效果,就是在每一滚动的时候,将第一张图片放到最后一张的 ...

  5. react拖拽(表格拖拽排序、普通拖拽排序以及树形拖拽排序)

    表格拖拽排序:组件地址:https://reactabular.js.org/#/drag-and-drop 拖动的排序是用React-DnD:React-DnD:http://react-dnd.g ...

  6. js 斐波那契数列的获取和曲线的实现(每日一更)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  7. js 每日一更(数组转换成前端更容易解析的树状结构)

    <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content ...

  8. react.js语法为了更好的兼容可以选以下这种方法配置即可

    首先下一个sublime text3 的编辑器: 支持大家使用正版,不过我是为了方便才所以这版本而已... 地址: http://sublimetext.iaixue.com/forum.php?mo ...

  9. Linux shell 常用命令大全 每日一更

    大一上学期学习了Linux的基本操作,已经很久没使用了,虚拟机也近半年没开(作为一个计算机类专业的少年真的不应该).为了补回这些知识和为将来的学习打下基础,现在每天更新一条shell命令及其子命令,欢 ...

随机推荐

  1. visual studio code的python编程中遇到的SyntaxError:invalid syntax问题的原因和解决办法

    一.问题重现描述 1.最开始,正常执行语句 2.当我在"终端窗口"输入python进入交互模式后,再选择默认的"在终端中运行python文件"运行代码报错 3. ...

  2. Morphological Image Processing

    目录 概 reflection and translation Erosion and Dilation Erosion 示例 skimage.morphology.erosion dilation ...

  3. MarkDown 使用方法

    MarkDown学习 标题的使用 ​ 在MarkDown中标题的使用,是用#+空格+标题名称,来进行编辑的.一个#就是一级标题, 两个#就是两级标题,以此类推,一定要加空格,否则无效 ### 三级标题 ...

  4. 编写Java程序,模拟文件操作过程中的异常处理

    返回本章节 返回作业目录 需求说明: 从控制中输入计算机磁盘中后缀名为".txt"的文件的完整物理路径. 如果该文件存在,则在控制台输出友好提示信息,告知用户该文件存在,如果文件不 ...

  5. minio + kkFileView 实现在线预览

    minio上传的pdf之类文件不支持预览,地址在浏览器访问时会直接下载,现在搭配kkFileView文件预览 1.minio查看之前的安装方式 2.kkFileView安装 docker方式 1.拉取 ...

  6. yum方式安装nginx

    1.添加CentOS 7 Nginx yum资源库 [root@localhost ~]# rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPM ...

  7. python中addict模块,设置和读取嵌套字典

    源码地址:   https://github.com/mewwts/addict/blob/master/README.md

  8. 【IntelliJ IDEA】代码模板

    psvm:main方法 sout:console输出 iter:foreach遍历 fori:for索引遍历

  9. js页面触发chargeRequest事件和Nginx获取日志信息

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6814836302966424072/ 承接上一篇文档<js页面触发pageView和event事件编写> ...

  10. hal 编码器做用户输入时捕获初值的设置

    uint16_t encoderDirection = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3); uint16_t encoderValue = __HA ...