html简单的图片裁剪,使用原生JS编写一个简单的图片裁剪器

作为一个前端开发人员,这次的这篇博客文章终于“正常”了。

这应该算是一个造轮子的实践,JS的图片开源裁剪器有很多,像使用JQuery库编写的cropper插件很多,在github上边的star数量也不少,现流行的前端框架也肯定有对应的图片裁剪器,都是可以选择的成熟的技术方案。但不是所有的情况都能适用,设计师的要求,本身项目的条件限制等等原因,有些时候,还是“自己动手,丰衣足食”啊!

因为用到了很多html5的特性,所以,这里编写的图片裁剪器,只能是适合于支持这些HTML5特性的浏览器才能够正常的使用。

需求描述

点击按钮选择图片,并进行展示;

展示区有一个正方形裁剪区,图片可以放大缩小;

在展示区,点击鼠标后拖拽,可对图片的位置进行调试,但展示图片不能越过裁剪区;

点击裁剪按钮,对位于裁剪区的图片进行裁剪,并展示裁剪后的图片;

HTML & CSS部分

首先,我们要编写一些基础的HTML代码:

SELECT IMAGE

缩小

放大

CROP

Image Show

添加样式。我这里是用了flex布局,如果不想用flex布局的话,可以选择其他的布局方式。

body {

display: flex;

justify-content: center;

flex-direction: column;

align-items: center;

}

#scissorsContainer {

display: flex;

justify-content: center;

flex-direction: column;

}

.btn {

padding: 8px;

font-size: 14px;

border: 1px solid #1976d2;

border-radius: 2px;

background: #ffffff;

text-align: center;

cursor: pointer;

}

.btn:hover {

background-color: #1976d2;

color: #ffffff;

}

#workArea {

width: 500px;

height: 500px;

position: relative;

margin: 16px 0;

overflow: hidden;

}

#overlay {

position: absolute;

width: 100%;

height: 100%;

background: #eeeeee;

display: flex;

justify-content: center;

align-items: center;

}

#overlayInner {

width: 300px;

height: 300px;

border: 100px solid gray;

opacity: 0.7;

z-index: 1;

}

#avatorImg {

width: auto;

height: auto;

border: none;

outline: none;

position: absolute;

}

#resizeBox {

display: flex;

justify-content: center;

align-items: center;

margin-bottom: 16px;

}

#resizeBox > div > button {

margin: 0 8px;

}

#imageShow {

width: 300px;

height: 300px;

}

设置全局变量

这里,我们设置一些JS代码里边需要的全局变量,具体的作用,下边的部分我们会介绍到的。

window.onload = function() {

// *** 定义全局变量 ***

// 全局需要的元素

window.workArea = document.querySelector('#workArea');

window.avatorImg = document.querySelector('#avatorImg');

window.imageShow = document.querySelector('#imageShow');

// 鼠标初始位置坐标数值

window.mouseStartX = 0;

window.mouseStartY = 0;

// 图片初始化后的尺寸记录

window.initLength = {

width: 0,

height: 0

};

// 图片原始尺寸记录

window.primitiveLength = {

width: 0,

height: 0

};

// 图片放大缩小的数值

window.resizeValue = 0;

// 图片呈现高度&宽度,需要根据HTML以及CSS部分的overlayInner的高宽度一致

window.showSide = document.querySelector('#overlayInner').clientWidth;

// 裁剪的图片类型

window.croppedImageType = 'image/png';

}

获取图片数据,并展示

我们在上边的HTML部分写了一个隐藏的input[type="file"],通过一个label标签来触发它,同时监听这个input元素,当它的值发生改变时,可以通过一个FileReader的对象获取到这个input的数据,并将它转换成base64格式的数据。

/**

* 图片选择元素的值发生变化后,重置图片裁剪区的样式

* @param {Object} e input数值变化事件

*/

function ImageInputChanged(e) {

var file = e.target.files[0];

var reader = new FileReader();

reader.onload = function(event) {

// 赋值给图片展示元素

avatorImg.src = event.target.result;

// 重置样式

avatorImg.style.width = 'auto';

avatorImg.style.height = 'auto';

avatorImg.style.top = 'auto';

avatorImg.style.left = 'auto';

}

reader.readAsDataURL(file);

}

图片展示区的数据发生变化

图片展示区的数据发生变化,我们在这里除了收集图片的原始信息以外,还对图片进行了初始化的像素调整。

function avatorImgChanged() {

if (avatorImg.offsetWidth >= avatorImg.offsetHeight) {

avatorImg.style.top = '100px';

initLength.width = showSide * avatorImg.offsetWidth / avatorImg.offsetHeight

initLength.height = showSide;

} else {

avator.style.left = '100px';

initLength.height = showSide * avatorImg.offsetWidth / avatorImg.offsetWidth;

initLength.width = showSide;

}

// 保存新的图片原始像素值

primitiveLength = {

width: avatorImg.offsetWidth,

height: avatorImg.offsetHeight

};

// 更新图片样式

avatorImg.style.width = initLength.width + 'px';

avatorImg.style.height = initLength.height + 'px';

}

图片的放大与缩小

在上边对应的HTML部分,我们添加了图片放大与缩小的按钮。

/**

* 图片放大

*/

function resizeUp() {

if (resizeValue <= 0) return;

resizeValue += 10;

resize();

}

/**

* 图片缩小

*/

function resizeDown() {

resizeValue -= 10;

resize();

}

/**

* 修改图片比例大小

*/

function resize() {

avatorImg.style.width = (resizeValue + 100) / 100 * initLength.width + 'px';

avatorImg.style.height = (resizeValue + 100) / 100 * initLength.height + 'px';

}

图片的拖拽

图片的拖拽,就是利用鼠标的三个事件来完成——mousedown,mousemove以及mouseup。我们在mousedown的时候,记录鼠标的初始位置,添加mousemove以及mouseup事件监听函数。

/**

* 监测鼠标点击,开始拖拽

* @param {Object} e 鼠标点击事件

*/

function startDrag(e) {

e.preventDefault();

if (avatorImg.src) {

// 记录鼠标初始位置

window.mouseStartX = e.clientX;

window.mouseStartY = e.clientY;

// 添加鼠标移动以及鼠标点击松开事件监听

workArea.addEventListener('mousemove', window.dragging, false);

workArea.addEventListener('mouseup', window.clearDragEvent, false);

}

}

图片的拖拽,我们这里做了一些限制,限制不让它拖拽出裁剪区。这主要是防止我们裁剪出不属于原图的空白区域。

/**

* 处理拖拽

* @param {Object} e 鼠标移动事件

*/

function dragging(e) {

// *** 图片不存在 ***

if (!avatorImg.src) return;

// *** 图片存在 ***

// X轴

let _moveX = avatorImg.offsetLeft + e.clientX - mouseStartX;

// 这里的100是HTML里边overlayInner的border属性的宽度

// 下边的400就是overlayInner元素的边长加上border的宽度之和

if (_moveX >= 100) {

avatorImg.style.left = '100px';

mouseStartX = e.clientX;

return;

} else if (_moveX <= 400 - avatorImg.offsetWidth) {

_moveX = 400 - avatorImg.offsetWidth;

}

avatorImg.style.left = _moveX + 'px';

mouseStartX = e.clientX;

// Y轴

let _moveY = avatorImg.offsetTop + e.clientY - mouseStartY;

if (_moveY >= 100) {

avatorImg.style.top = '100px';

mouseStartY = e.clientY;

return;

} else if (_moveY <= 400 - avatorImg.offsetHeight) {

_moveY = 400 - avatorImg.offsetHeight;

}

avatorImg.style.top = _moveY + 'px';

mouseStartY = e.clientY;

}

裁剪

/**

* 对图片进行裁剪

*/

function crop() {

if (!avatorImg.src) return;

let _cropCanvas = document.createElement('canvas');

// 计算边长

let _side = (showSide / avatorImg.offsetWidth) * primitiveLength.width;

_cropCanvas.width = _side;

_cropCanvas.height = _side;

// 计算截取时从原图片的原始长度的坐标

// 因为图片有可能会被放大/缩小,这时候,初始化时记录下来的primitiveLength信息就有用处了

let _sy = (100 - avatorImg.offsetTop) / avatorImg.offsetHeight * primitiveLength.height;

let _sx = (100 - avatorImg.offsetLeft) / avatorImg.offsetWidth * primitiveLength.width;

// 绘制图片

_cropCanvas.getContext('2d').drawImage(avatorImg, _sx, _sy, _side, _side, 0, 0, _side, _side);

// 保存图片信息

let _lastImageData = _cropCanvas.toDataURL(croppedImageType);

// 将裁剪出来的信息展示

imageShow.src = _lastImageData;

imageShow.style.width = showSide + 'px';

imageShow.style.height = showSide + 'px';

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值