jQuery.cropper是一款使用简单且功能强大的图片剪裁jQuery插件。该图片剪裁插件支持图片放大缩小,支持图片旋转,支持触摸屏设备,支持canvas,并且支持跨浏览器使用。
官网:https://github.com/fengyuanchen/cropper
使用方法
使用该图片剪裁插件首先要引入必要的js和css文件。
<script src="/path/to/jquery.js"></script><!-- jQuery is required -->
<link href="/path/to/cropper.css" rel="stylesheet">
<script src="/path/to/cropper.js"></script>
HTML结构
可以将图片或canvas直接包裹到一个块级元素中。
<!-- Wrap the image or canvas with a block element -->
<div class="container">
<img src="picture.jpg">
</div>
调用插件
可以使用$.fn.cropper方法来初始化该图片剪裁插件。
var options = { aspectRatio: 4 / 3,//设置裁切框的宽高比。默认情况下,裁剪框是自由比例。 preview: '.img-preview', crop: function (e) { $dataX.html(Math.round(e.x)); $dataY.html(Math.round(e.y)); $dataHeight.html(Math.round(e.height)); $dataWidth.html(Math.round(e.width)); $dataRotate.html(e.rotate); $dataScaleX.html(e.scaleX); $dataScaleY.html(e.scaleY); var _$dataWH = reductionTo(Math.round(e.width), Math.round(e.height)); $dataWH.html(_$dataWH[0] + '/' + _$dataWH[1]); } }; // 初始化函数 $image.cropper(options); $image.cropper({ built: function () { } });
参数
-
你可以通过$().cropper(options)方法来设置参数。如果你想改变全局默认参数,可以使用$.fn.cropper.setDefaults(options)方法。
-
aspectRatio:类型:Number,默认值NaN。设置剪裁容器的比例。
-
crop:类型:Function,默认值null。当改变剪裁容器或图片时的事件函数。
-
preview:类型:String(jQuery选择器),默认值''。添加额外的元素(容器)的预览。注意:
-
最大宽度是剪裁容器的初始化宽度
-
最大高度是剪裁容器的初始化高度
-
如果你设置了aspectRatio参数,确保预览容器具有相同的比例
-
strict:类型:Boolean,默认值true。在strict模式中,canvas不能小于容器,剪裁容器不能再canvas之外。
-
responsive:类型:Boolean,默认值true。是否在窗口尺寸改变的时候重置cropper。
-
checkImageOrigin:类型:Boolean,默认值true。默认情况下,插件会检测图片的源,如果是跨域图片,图片元素会被添加crossOrigin class,并会为图片的url添加一个时间戳来使getCroppedCanvas变为可用。添加时间戳会使图片重新加载,以使跨域图片能够使用getCroppedCanvas。在图片上添加crossOrigin class会阻止在图片url上添加时间戳,及图片的重新加载。
-
background:类型:Boolean,默认值true。是否在容器上显示网格背景。
-
modal:类型:Boolean,默认值true。是否在剪裁框上显示黑色的模态窗口。
-
guides:类型:Boolean,默认值true。是否在剪裁框上显示虚线。
-
highlight:类型:Boolean,默认值true。是否在剪裁框上显示白色的模态窗口。
-
autoCrop:类型:Boolean,默认值true。是否在初始化时允许自动剪裁图片。
-
autoCropArea:类型:Number,默认值0.8(图片的80%)。0-1之间的数值,定义自动剪裁区域的大小。
-
dragCrop:类型:Boolean,默认值true。是否允许移除当前的剪裁框,并通过拖动来新建一个剪裁框区域。
-
movable:类型:Boolean,默认值true。是否允许移动剪裁框。
-
resizable:类型:Boolean,默认值true。是否允许改变剪裁框的大小。
-
zoomable:类型:Boolean,默认值true。是否允许放大缩小图片。
-
mouseWheelZoom:类型:Boolean,默认值true。是否允许通过鼠标滚轮来缩放图片。
-
touchDragZoom:类型:Boolean,默认值true。是否允许通过触摸移动来缩放图片。
-
rotatable:类型:Boolean,默认值true。是否允许旋转图片。
-
minContainerWidth:类型:Number,默认值200。容器的最小宽度。
-
minContainerHeight:类型:Number,默认值100。容器的最小高度。
-
minCanvasWidth:类型:Number,默认值0。canvas 的最小宽度(image wrapper)。
-
minCanvasHeight:类型:Number,默认值0。canvas 的最小高度(image wrapper)。
-
build:类型:Function,默认值null。build.cropper事件的简写方式。
-
built:类型:Function,默认值null。built.cropper事件的简写方式。
-
dragstart:类型:Function,默认值null。dragstart.cropper事件的简写方式。
-
dragmove:类型:Function,默认值null。dragmove.cropper事件的简写方式。
-
dragend:类型:Function,默认值null。dragend.cropper事件的简写方式。
-
zoomin:类型:Function,默认值null。zoomin.cropper事件的简写方式。
-
zoomout:类型:Function,默认值null。zoomout.cropper事件的简写方式。
eg:
//index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="css/cropper.css"> <link rel="stylesheet" href="css/main.css"> </head> <body> <div class="wrapper"> <!--用块元素(容器)包装图像或画布元素--> <div class="img-container"> <img id="image" src="images/picture.jpg" alt=""> </div> <div class="img-preview-container"> <h1>预览区域</h1> <div class="img-preview"> <img src="" alt=""> </div> </div> <div class="text-container"> <div class="param-container"> <div class="param"> <div class="name">X:</div> <div class="value" id="dataX"></div> <div class="unit">px</div> </div> <div class="param"> <div class="name">Y:</div> <div class="value" id="dataY"></div> <div class="unit">px</div> </div> <div class="param"> <div class="name">Width:</div> <div class="value" id="dataWidth"></div> <div class="unit">px</div> </div> <div class="param"> <div class="name">Height:</div> <div class="value" id="dataHeight"></div> <div class="unit">px</div> </div> <div class="param"> <div class="name">Rotate:</div> <div class="value" id="dataRotate"></div> <div class="unit">deg</div> </div> <div class="param"> <div class="name">ScaleX:</div> <div class="right-value" id="dataScaleX"></div> </div> <div class="param"> <div class="name">ScaleY:</div> <div class="right-value" id="dataScaleY"></div> </div> <div class="param"> <div class="name">W/H:</div> <div class="right-value" id="dataWH"></div> </div> </div> </div> <div class="btn-container" id="ratio_container"> <div class="btn" data-ratio="16/9">16/9</div> <div class="btn" data-ratio="4/3">4/3</div> <div class="btn" data-ratio="1">1/1</div> <div class="btn" data-ratio="2/3">2/3</div> <div class="btn" data-ratio="">Free</div> </div> <div class="btn-container" id="move_container"> <div class="btn" data-movex="0" data-movey="-10">上移</div> <div class="btn" data-movex="0" data-movey="10">下移</div> <div class="btn" data-movex="-10" data-movey="0">左移</div> <div class="btn" data-movex="10" data-movey="0">右移</div> </div> <div class="btn-container" id="zoom_container"> <div class="btn" data-zoom="0.1">放大</div> <div class="btn" data-zoom="-0.1" data-movey="10">缩小</div> </div> <div class="btn-container" id="rotate_container"> <div class="btn" data-rotate="45">顺时针旋转</div> <div class="btn" data-rotate="-45" data-movey="10">逆时针旋转</div> </div> <div class="btn-container" id="scale_container"> <div class="btn" data-scale="x">左右翻转</div> <div class="btn" data-scale="y" data-movey="10">上下翻转</div> </div> <div class="btn-container"> <div class="btn" id="enable">可用</div> <div class="btn" id="disable">冻结</div> <div class="btn" id="reset1">重置1</div> <div class="btn" id="reset2">重置2</div> <div class="btn" id="clear">清空</div> <div class="btn" id="destroy">销毁</div> <div class="btn"> <input class="input-upload" id="upload" type="file"> 上传图片 </div> </div> <div class="btn-container"> <div class="btn" id="replace">修改图片地址</div> </div> <div class="btn-container"> <div class="btn" id="getCroppedCanvas">裁剪:get Cropped Canvas</div> </div> <div class="btn-container"> <div class="btn" id="submit">提交</div> </div> <img src="" id="test" width="500px" height="500px" alt=""> <div class="fixed-canvas hiddle"> <div class="fixed-bg"></div> <div class="canvas-container"> <h1>裁剪区域</h1> <div class="canvas" id="canvas"> </div> <div class="btn-container" id="modal_canvas_btn"> <a class="btn" href="javascript:;" >取消</a> <a class="btn" id="download" href="javascript:;" download="images/picture.jpg">下载</a> </div> </div> </div> </div> <script src="js/jquery-3.2.1.js"></script> <script src="js/cropper.js"></script> <script src="js/main.js"></script> </body> </html>
//main.css *{margin: 0;padding: 0;outline: none} *:active{-webkit-tap-highlight-color: rgba(0,0,0,0)} a{text-decoration: none} .disabled{pointer-events: none;opacity:.65} h1{font-size: 18px;margin-bottom: 20px} .hiddle{display: none!important;} .wrapper{margin: 20px auto;min-width: 1200px} .img-container{margin-left: 20px;display: inline-block;width: 600px;height: 342px;overflow: hidden;} .img-preview-container{margin-left: 10px;display: inline-block;vertical-align: top} .img-preview-container .img-preview{width: 300px;height: 171px;overflow: hidden;border: 1px #ccc solid} .img-preview-container img{border: 1px #aaa solid} .fixed-canvas{position: fixed;left: 50%;top:20px; width: 600px;margin-left: -300px;border:1px #aaa solid;border-radius: 6px;} .fixed-canvas .fixed-bg{position: fixed;left: 0%;top:0%;right:0;bottom:0;background: rgba(0,0,0,.6);z-index:1} .fixed-canvas .canvas-container{background: #fff;padding: 30px 20px;width: 100%;height: 100%;position: relative;z-index: 2;border-radius: 6px;box-sizing: border-box} .fixed-canvas .canvas-container .canvas{width: 456px;border: 1px #ccc solid} .fixed-canvas .canvas-container .canvas canvas{width: 100%} /*限制图像宽度以避免容器溢出*/ .img-container img{max-width: 100%} /*这个规则很重要,请不要忽略这个*/ .text-container{display: inline-block;padding-left: 20px} .text-container .param-container{vertical-align: top} .param-container .param{display: inline-block;margin: 10px;width: 202px;height:33px;border: 1px #aaa solid;border-radius: 6px;box-sizing: border-box;font-size: 0} .param-container .param .name,.param-container .param .value,.param-container .param .unit,.param-container .param .right-value{display: inline-block;height:100%;box-sizing: border-box;text-align: center;color:#495057;vertical-align: top;font-size: 16px;line-height: 31px} .param-container .param .name,.param-container .param .unit{background: #ccc} .param-container .param .name{width: 80px} .param-container .param .value{width: 80px} .param-container .param .unit{width: 40px} .param-container .param .right-value{width: 120px;} .btn-container{margin: 20px;display: inline-block;height: 33px;background: #007bff;border-radius: 6px} .btn-container .btn{position: relative;padding: 0 20px;display: inline-block;height: 100%;vertical-align: top;color: #fff;line-height: 33px;cursor: pointer;overflow: hidden} .input-upload{position: absolute;top: 0;left: 0;bottom: 0;right: 0;display: inline-block;border: 1px red solid;opacity: 0;}
//main.js $(function () { 'use strict'; var $image = $('#image'); var $download = $('#download'); var $dataX = $('#dataX'); var $dataY = $('#dataY'); var $dataHeight = $('#dataHeight'); var $dataWidth = $('#dataWidth'); var $dataRotate = $('#dataRotate'); var $dataScaleX = $('#dataScaleX'); var $dataScaleY = $('#dataScaleY'); var $dataWH = $('#dataWH'); var options = { aspectRatio: 4 / 3,//设置裁切框的宽高比。默认情况下,裁剪框是自由比例。 preview: '.img-preview', crop: function (e) { $dataX.html(Math.round(e.x)); $dataY.html(Math.round(e.y)); $dataHeight.html(Math.round(e.height)); $dataWidth.html(Math.round(e.width)); $dataRotate.html(e.rotate); $dataScaleX.html(e.scaleX); $dataScaleY.html(e.scaleY); var _$dataWH = reductionTo(Math.round(e.width), Math.round(e.height)); $dataWH.html(_$dataWH[0] + '/' + _$dataWH[1]); } }; // 初始化函数 $image.cropper(options); $image.cropper({ built: function () { } }); // 修改裁剪比例函数 $('#ratio_container .btn').click(function (event) { event.stopPropagation(); var dataRatio = $(this).attr('data-ratio'); $image.cropper('destroy').cropper({'aspectRatio': dataRatio}); }); // 移动函数 $('#move_container .btn').click(function (event) { event.stopPropagation(); var dataMovex = parseInt($(this).attr('data-movex')); var dataMovey = parseInt($(this).attr('data-movey')); $image.cropper('move', dataMovex, dataMovey) }); // 移动函数 $('#move_container .btn').click(function (event) { event.stopPropagation(); var dataMovex = parseInt($(this).attr('data-movex')); var dataMovey = parseInt($(this).attr('data-movey')); $image.cropper('move', dataMovex, dataMovey) }); // Keyboard $(document.body).on('keydown', function (e) { if (!$image.data('cropper') || this.scrollTop > 300) { return; } switch (e.which) { case 37: e.preventDefault(); $image.cropper('move', -1, 0); break; case 38: e.preventDefault(); $image.cropper('move', 0, -1); break; case 39: e.preventDefault(); $image.cropper('move', 1, 0); break; case 40: e.preventDefault(); $image.cropper('move', 0, 1); break; } }); // 放大缩小 $('#zoom_container .btn').click(function (event) { event.stopPropagation(); var dataZoom = $(this).attr('data-zoom'); $image.cropper('zoom', dataZoom); }); // 旋转 $('#rotate_container .btn').click(function (event) { event.stopPropagation(); var dataRotate = $(this).attr('data-rotate'); $image.cropper('rotate', dataRotate); }); // 翻转 var scalexVal = 1; var scaleyVal = 1; $('#scale_container .btn').click(function (event) { event.stopPropagation(); var dataScale = $(this).attr('data-scale'); if (dataScale == 'x') { scalexVal = -scalexVal; $image.cropper('scaleX', scalexVal); } else if (dataScale == 'y') { scaleyVal = -scaleyVal; $image.cropper('scaleY', scaleyVal); } }); // enable():使cropper可用。 $('#enable').click(function (event) { event.stopPropagation(); $image.cropper('enable'); }); // disable():冻结cropper。 $('#disable').click(function (event) { event.stopPropagation(); $image.cropper('disable'); }); // reset():重置剪裁区域的图片到初始状态。 $('#reset1').click(function (event) { event.stopPropagation(); $image.cropper('crop'); $image.cropper('destroy').cropper({'preview': '.img-preview'}); }); $('#reset2').click(function (event) { event.stopPropagation(); $image.cropper('reset'); $image.cropper('destroy').cropper({'preview': '.img-preview'}); }); // clear():清空剪裁区域。 $('#clear').click(function (event) { event.stopPropagation(); $image.cropper('clear'); }); // destroy():销毁剪裁函数。 $('#destroy').click(function (event) { event.stopPropagation(); $image.cropper('destroy'); }); //上传图片 $('#upload').change(function (event) { var files = this.files; if (files && files.length) { var file = files[0]; if (/.(gif|jpg|jpeg|png|GIF|JPG|PNG)$/.test(file.name)) { var uploadedImageURL = window.URL.createObjectURL(file); $image.cropper('destroy').attr('src', uploadedImageURL).cropper(options); $download.attr('download', uploadedImageURL); $('#upload').val(''); } else { alert('请选择正确的图片格式!'); } } }); //修改图片地址 var imgUrl = 'images/picture.jpg'; $('#replace').click(function (event) { event.stopPropagation(); imgUrl = (imgUrl == 'images/picture_new.jpg' ? 'images/picture.jpg' : 'images/picture_new.jpg'); $image.cropper('replace', imgUrl); $download.attr('download', imgUrl); }); // 输出裁剪好的图片 $('#getCroppedCanvas').click(function (event) { event.stopPropagation(); var imgurl = $image.cropper("getCroppedCanvas"); $("#canvas").html(imgurl); $download.attr('href', imgurl.toDataURL()); $('.fixed-canvas').removeClass('hiddle'); }); //点击取消或者下载之后 $('#modal_canvas_btn .btn').click(function (event) { $('.fixed-canvas').addClass('hiddle'); }); // 获取数据 $('#getData').click(function (event) { event.stopPropagation(); var getData = $image.cropper("getData") console.log(getData); }); //提交裁剪好的图片到后台 $('#submit').click(function (event) { var imgData = $image.cropper("getCroppedCanvas").toDataURL(); // console.log(imgData); $.ajax({ url: '', dataType: 'json', type: "POST", data: {"image": imgData}, success: function () { console.log('Upload success'); }, error: function () { console.log('Upload error'); } }); }); }); function destory() { $image.cropper('destroy').cropper(options); } //m,n为正整数的分子和分母 function reductionTo(m, n) { var arr = []; if (!isInteger(m) || !isInteger(n)) { // console.log('m和n必须为整数'); arr[0] = 0; arr[1] = 0; return arr; } else if (m <= 0 || n <= 0) { // console.log('m和n必须大于0'); arr[0] = 0; arr[1] = 0; return arr; } var a = m; var b = n; (a >= b) ? (a = m, b = n) : (a = n, b = m); if (m != 1 && n != 1) { for (var i = b; i >= 2; i--) { if (m % i == 0 && n % i == 0) { m = m / i; n = n / i; } } } arr[0] = m; arr[1] = n; return arr; } //判断一个数是否为整数 function isInteger(obj) { return obj % 1 === 0 }