最近工作项目上需要实现一个对图片进行多次剪切,并上传服务器的功能。要求可以在图片上增加用户交互,进行一些增删改查的操作
一. 图片的渲染,用canvas还是svg
svg的对象级别操作使得在图片中添加dom组件用于用户交互变得方便,但是svg不提供对图片像素级别的处理,无法获取特定位置的图片像素数据,因此图片的剪切后上传的功能需要使用canvas,canvas提供toDataURL的api可以获取指定位置的base64。因此使用svg和结合的方案,svg用于图片显示和剪切的操作,以及用户交互的dom操作,canvas用户获取剪切图片的数据
二. 具体实现
图片渲染
<svg ref={(e) => { this.myCanvas = e; }} id="svgId" xmlns="http://www.w3.org/2000/svg" width={finalWidth + 'px'} height={finalHeight + 'px'} viewBox={viewBox1}>
<image xlinkHref=“” id="img" width={finalWidth + 'px'} height={finalHeight + 'px'} x="0" y="0" style={{ transform:rotate(${this.state.rotation[this.state.showUrlIndex]}deg), transformOrigin: 'center' }}>
</image>
</svg>图片的剪切操作
对svg dom节点绑定三个鼠标操作事件,实现画矩形的操作:
svg.onmousedown = function () {
let ce = ev || event;
// 获取鼠标点击后的坐标
x1 = ce.offsetX;
y1 = ce.offsetY;
}
svg.onmousemove = function (ev) {
const nx1 = ce.offsetX;
const ny1 = ce.offsetY;
xOffset = nx1 - x1; // 相对鼠标一开始点下的x偏移
yOffset = ny1 - y1;
that.drawRect(svg, x1, y1, xOffset, yOffset, id); // 画矩形
};
svg.onmouseup = function (ev) {
svg.onmousemove = null;
};
drawRect = (svg, px, py, width, height, id) =>{
// 删除之前画的矩形(边画边删除,否则会出现层叠在一起的矩形)
let delRect = document.getElementById(id);
if (delRect != null) {
delRect.remove();
}
// 创建矩形
if (px >= 0 && py >= 0 && width >= 0 && height >= 0) {
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
// 画矩形
rect.setAttribute("id", id);
rect.setAttribute("x", px);
rect.setAttribute("y", py);
rect.setAttribute("width", width);
rect.setAttribute("height", height);
rect.setAttribute("style", "fill:rgb(0,0,0);stroke-width:1;stroke:rgb(255,0,255);fill-opacity:0;");
// 将绘制好的矩形添加到svg中
svg.appendChild(rect);
}
}
- 获取剪切数据,上传服务器
获取剪切数据主要使用canvas的toDataUrl功能
var tnCanvas = document.createElement('canvas');
var tnCanvasContext = tnCanvas.getContext('2d');
tnCanvas.width = imgWidth + 10; // imgWidth为剪切的小图片尺寸
tnCanvas.height = imgHeight + 10;
tnCanvasContext.drawImage(image, startX, startY, newWidth * ratio, newHeight * ratio, 0, lastHeight, newWidth, newHeight); // image为大图的image对象
const dataurl = tnCanvas.toDataURL(); // 将画布上小题的图片转成base64
this.dataURLtoFile(dataurl, number + '.png'); // base64 转为file 对象可上传至服务器