【前端】JavaScript实现图片裁剪

作者:邹峰立,微博:zrunker,邮箱:zrunker@yahoo.com,微信公众号:书客创作,个人平台:www.ibooker.cc

本文选自书客创作平台第43篇文章。阅读原文

书客创作

Web端图片裁剪的应用其实是非常常见的,例如上传图片或者上传封面的时候,往往都会要求先裁剪,后上传。那么究竟该如何去实现图片裁剪功能呢?

分析

首先先看一下最终效果图:


裁剪效果图

在图中,实现了以下几个功能:

  1. 能够切换待裁剪图片。
  2. 能够实现图片裁剪相关功能,如拖动裁剪框,改变裁剪框的大小等。
  3. 能够时时预览裁剪效果。
  4. 点击保存按钮,能够获取图片裁剪相关信息。

分析1:如何实现切换裁剪图片?

待裁剪图片是选择的本地图片,对于本地文件的选择可以通过input type=file标签。

<input id="imgFile" type="file" name="imgFile">

图片选择之后将选择的图片同步到待裁剪图片的显示位置(即裁剪框所在位置),从而达到切换裁剪图片。

分析2:如何实现裁剪布局?

仔细观察裁剪效果图,可以发现待裁剪图片,被选中的那一部分是明亮的而其他属于灰色。那么如何去实现这样的效果呢?

可以将这一部分分三层,每一层都堆叠在前一层的上面。第一层是灰色层,这里用图片(即真正待裁剪图片)显示,设置其透明度,使之不为全透明。第二层也是图片(即真正待裁剪图片),背景全透明,但是只显示图片跟裁剪框一样的大小部分,这里需要用到clip。第三层是裁剪框,根据裁剪框的大小修改第二层图片要显示大小,从而达到裁剪视觉效果。

分析3:如何实现预览?

预览效果的实现,其实跟裁剪效果的实现一样,但是只需要一层即可,这一层只放置图片(即真正待裁剪图片)。在裁剪过程中,根据裁剪框的大小,位置来设置预览图片的要显示的大小,位置。

分析4:点击保存按钮,如何获取图片裁剪的相关信息?

其实图片裁剪的相关信息即裁剪框的信息。这里只需要知道,裁剪框的大小(宽高)和裁剪框相对于待裁剪图片的位置(如果把待裁剪图片的左上角设为原点,那么裁剪框左上角相对于原点的x和y坐标)。

真正进行裁剪的是后台进行裁剪,而前端只是模拟一个效果。后台获取这些参数之后,可以对图片进行相应的裁剪处理。

实现

一、布局实现

在body体中,需要实现两部分,一部分是用来实现图片裁剪,另一部分是用来实现图片上传的form表单。

<body>
    <%-- 裁剪图片布局 --%>
    <div id="crop_image">
        <div id="crop_image_top">
            <h4>编辑图片</h4>
            <!-- <a>X</a> -->
        </div>

        <div id="crop_image_content">
            <%-- 裁剪部分 --%>
            <div id="cropBox">
                <img id="cropimg1" alt="" src="images/test.jpg">
                <img id="cropimg2" alt="" src="images/test.jpg">
                <%-- 裁剪框 --%>
                <div id="mainBox">
                    <div id="left-up" class="minBox left-up"></div>
                    <div id="up" class="minBox up"></div>
                    <div id="right-up" class="minBox right-up"></div>
                    <div id="left" class="minBox left"></div>
                    <div id="right" class="minBox right"></div>
                    <div id="left-down" class="minBox left-down"></div>
                    <div id="down" class="minBox down"></div>
                    <div id="right-down" class="minBox right-down"></div>
                </div>
            </div>
            <%-- 预览部分 --%>
            <div id="preview">
                <img id="cropimg3" alt="" src="images/test.jpg">
            </div>
        </div>
        
        <div id="crop_image_bottom">
            <input class="btn" type="button" value="取消">
            <input id="submitBtn" class="btn" type="button" value="确定" onclick="saveCropImage()">
        </div>
    </div>

    <!-- 上传图片表单 -->
    <form id="uploadForm" action="">
        <div id="uploadImage">
            <img id="cropimg4" alt="" src="images/test.jpg">
            <a href="javascript:;" class="addImage">
                <span>上传图片</span>
                <input id="imgFile" type="file" name="imgFile">
            </a>
        </div>
    </form>
</body>

注:裁剪框实现,是通过一个大的div(mainBox)和8个小的div(上,下,左,右,左上,左下,右上,右下)组成。通过设置大的div来整体控制裁剪框的大小。通过操作大的div内部8个小div来实现裁剪效果。

裁剪框

设置样式,这里为了方便,把样式写在布局文件里面,所以在header里面添加。这里给出的样式代码,只是正对body体里面布局内容的样式。

<style type="text/css">
#crop_image {
    float: left;
    width: 55%;
    background-color: #333;
    user-select: none;
    margin: 3% 20%;
    border: 1px solid #DEDEDE;
    -webkit-border-radius: 6px;
    -moz-border-radius: 6px;
    border-radius: 6px;
    -webkit-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
    box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
}

#crop_image_top,#crop_image_bottom {
    float: left;
    width: 96%;
    padding: 2%;
    background-color: white;
}
/* 底部 */
#crop_image_bottom {
    text-align: right;
}

#crop_image_bottom input {
    height: 30px;
    padding: 5px 15px;
    border-radius: 3px;
    border: none;
    margin-left: 20px;
    outline: none;
}

#submitBtn {
    background-color: #40aff2;
    color: white;
    cursor: pointer;
}

#submitBtn:HOVER {
    background-color: #409ff2;
}
/* 顶部 */
#crop_image_top h4 {
    margin: 0;
    padding: 0;
    font-weight: normal;
}
/* 裁剪部分 */
#crop_image_content {
    float: left;
    position: relative;
    text-align: center;
    width: 92%;
    margin: 4%;
}

#cropBox {
    position: relative;
}

#crop_image_content #cropimg1 {
    opacity: 0.5;
    position: absolute;
    top: 0;
    left: 0;
}

#crop_image_content #cropimg2 {
    position: absolute;
    top: 0;
    left: 0;
    clip: rect(0, 150px, 150px, 0);
}

#crop_image_content #mainBox {
    border: 1px solid white;
    position: absolute;
    top: 0;
    left: 0;
    width: 150px;
    height: 150px;
    cursor: move;
}

.minBox {
    position: absolute;
    height: 8px;
    width: 8px;
    background-color: white;
}

.left-up {
    top: -4px;
    left: -4px;
    cursor: nw-resize;
}

.up {
    left: 50%;
    margin-left: -4px;
    top: -4px;
    cursor: n-resize;
}

.right-up {
    right: -4px;
    top: -4px;
    cursor: ne-resize;
}

.left {
    top: 50%;
    margin-top: -4px;
    left: -4px;
    cursor: w-resize;
}

.right {
    top: 50%;
    margin-top: -4px;
    right: -4px;
    cursor: w-resize;
}

.left-down {
    bottom: -4px;
    left: -4px;
    cursor: sw-resize;
}

.down {
    bottom: -4px;
    left: 50%;
    margin-left: -4px;
    cursor: s-resize;
}

.right-down {
    bottom: -4px;
    right: -4px;
    cursor: se-resize;
}
/* 预览框 */
#preview {
    position: absolute;
    top: 0;
}

#preview #cropimg3 {
    position: absolute;
}

/* 上传图片区域 */
#uploadForm {
    float: left;
    margin: -2% 20% 5% 20%;
}

#uploadImage {
    position: relative;
    width: 372px;
    height: 202px;
    background-color: #40aff2;
    text-align: center;
}

#uploadImage #cropimg4 {
    position: absolute;
    height: 100%;
    width: 100%;
    padding: 0;
    margin: 0;
    top: 0;
    left: 0;
}

#uploadImage .addImage {
    display: inline-block;
    position: relative;
    min-width: 80px;
    height: 40px;
    overflow: hidden;
    padding: 0 30px;
    margin: 81px auto;
    border: none;
    background-color: #F3F3F3;
    color: #555;
    font: 14px/40px 'MicroSoft Yahei', 'Simhei';
    cursor: pointer;
    text-align: center;
    text-decoration: none;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
}

#uploadImage .addImage:HOVER {
    background-color: #DEDEDE;
}

#uploadImage #imgFile
    {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 140px;
    height: 40px;
    cursor: pointer;
    cursor: hand;
    border: none;
    font-size: 0;
    padding: 0;
    /* older safari/Chrome browsers */
    -webkit-opacity: 0;
    /* Netscape and Older than Firefox 0.9 */
    -moz-opacity: 0;
    /* Safari 1.x (pre WebKit!) 老式khtml内核的Safari浏览器*/
    -khtml-opacity: 0;
    /* IE9 + etc...modern browsers */
    opacity: 0;
    /* IE 4-9 */
    filter:alpha(opacity=0);
    /*This works in IE 8 & 9 too*/
    -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
    /*IE4-IE9*/
    filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
}

#uploadImage #imgFile::-webkit-file-upload-button {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 140px;
    height: 40px;
    cursor: pointer;
    cursor: hand;
    border: none;
    font-size: 0;
    padding: 0;
    /* older safari/Chrome browsers */
    -webkit-opacity: 0;
    /* Netscape and Older than Firefox 0.9 */
    -moz-opacity: 0;
    /* Safari 1.x (pre WebKit!) 老式khtml内核的Safari浏览器*/
    -khtml-opacity: 0;
    /* IE9 + etc...modern browsers */
    opacity: 0;
    /* IE 4-9 */
    filter:alpha(opacity=0);
    /*This works in IE 8 & 9 too*/
    -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
    /*IE4-IE9*/
    filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
}
</style>

注:1、opacity属性是用来设置透明度,取值范围0~1。2、clip属性是用来设置控件要显示的位置、大小、样式等,如clip: rect(0, 150px, 150px, 0);表示控件显示矩形,矩形上右下左相对于主控件坐标分别是0,150,150,0。3、cursor表示鼠标样式,如cursor: nw-resize;表示南西可更改大小的鼠标样式。

二、图片裁剪功能实现

1、裁剪框位置变化:当鼠标按下裁剪框的时候,裁剪框就可以根据鼠标移动的位置变化而变化。

当裁剪框移动的时候,裁剪框的大小未发生变化,变化的只是裁剪框的坐标或者说是相对于浏览器左侧和上侧的距离或者说是鼠标在x轴或者y轴上的变化。

裁剪框位置变化图

所以对于裁剪框变化处理,就相当于重新设置裁剪框到浏览器上侧和左侧的距离。

上侧距离变化值 = y轴坐标 - 裁剪框到浏览器顶部的距离。

左侧距离变化值 = x轴坐标 - 裁剪框到浏览器左边的距离。

例如向上移动:

var mainBoxElem = document.getElementById("mainBox");// 裁剪框
var y = e.clientY;// 鼠标y坐标
var mainY = getPosition(mainBoxElem).top;// 裁剪框相对于屏幕上边的距离
var addHeight = mainY - y;// 增加的高度
mainBoxElem.style.top = mainBoxElem.offsetTop - addHeight + "px";// 裁剪框相对于父控件的距离

问题:裁剪框移动范围设置。

裁剪框只能在自己的父控件内进行位置变化,这就相对于鼠标在x轴的变化,不能小于裁剪框父控件左侧到浏览器左侧距离,不能大于裁剪框父控件右侧到浏览器左侧距离。鼠标在y轴上变化,不能小于裁剪框父控件上侧到浏览器上侧距离,不能大于裁剪框父控件下侧到浏览器上侧距离。

2、裁剪框大小变化:裁剪框可以往任意方向进行拉伸或缩放。

这里只分析裁剪框内部id为right的div点击之后,向左或向右移动的处理,其他div的处理方式与其略同。裁剪框的大小变化跟鼠标的移动有关,所以该处理过程应该放在鼠标移动事件内。

window.onmousemove = function(e) {}

A. 鼠标向右移动,实际上就相当于将裁剪框的宽度增加。
这个难点是在计算裁剪框增加的宽度。当鼠标移动的时候,可以知道鼠标在x轴位置,同时可以通过元素.offsetLeft可以知道裁剪框相对于浏览器左侧的距离,然后用x轴位置 - 裁剪框相对于浏览器其左侧距离 - 裁剪框最初宽度 = 裁剪框新增宽度。

裁剪框的宽度增加分析图
var mainBoxElem = document.getElementById("mainBox");// 裁剪框
var x = e.clientX;// 鼠标x坐标
var widthBefore = mainBoxElem.offsetWidth - 2;// 裁剪框变化前的宽度,2为裁剪框边框
var addWidth = x - mainBoxElem.offsetLeft- widthBefore;// 鼠标移动后,裁剪框增加的宽度
var width = widthBefore + addWidth;
mainBoxElem.style.width = width + "px";// 裁剪框变化后,设置宽度

B. 鼠标向左移动,实际上就相当于将裁剪框的宽度减少,或者说裁剪框增加的宽度为负值。

裁剪框增加宽度= 鼠标x轴坐标 - (裁剪框相对于浏览器左侧距离 + 裁剪框原宽度)。

var x = e.clientX;// 鼠标x坐标
var widthBefore = mainBoxElem.offsetWidth -2;// 裁剪框变化前的宽度
var addWidth = mainBoxElem.offsetLeft - x;// 鼠标移动后,裁剪框增加的宽度
var width = widthBefore + addWidth;
mainBoxElem.style.width = width + "px";// 裁剪框变化后,设置宽度

问题1:无论裁剪框增加多少,最终裁剪框都是在其父控件范围内进行变化。

解决:在进行裁剪框大小变化的时候,判断设置的宽度或者高度不能超过父控件的宽度或者高度。

问题2:无论裁剪框减少多少,都不可能将裁剪框的高或者宽减少到小于0的值。

解决:在设置裁剪框大小变化的时候,判断设置的宽度或者高度不能等于0。

综合以上分析,对该剪裁相关js代码进行整理和封装为clip-image.js。

// 实现图片裁剪功能
window.onload = function() {
    document.onselectstart=new Function('event.returnValue=false;');
    // 裁剪框拖动
    $("#mainBox").draggable({containment: 'parent', drag: setChoice});
    
    // 获取裁剪框移动范围
    var cropimgElem = document.getElementById("cropimg1");
    var cropimgElemWidth = cropimgElem.clientWidth;
    var cropimgElemHeight = cropimgElem.clientHeight;
    var cropimgElemPosition = getPosition(cropimgElem);
    var minX = cropimgElemPosition.left;// 待裁剪的图片最小x坐标
    var maxX = cropimgElemPosition.left + cropimgElemWidth;// 待裁剪的图片最大x坐标
    var minY = cropimgElemPosition.top;// 待裁剪的图片最小y坐标
    var maxY = cropimgElemPosition.top + cropimgElemHeight;// 待裁剪的图片最大y坐标
    
    // 动态设置父控件的宽度和高度
    var cropBox = document.getElementById("cropBox");
    cropBox.style.width = cropimgElemWidth + "px";
    cropBox.style.height = cropimgElemHeight + "px";
    // 预览框设置
    var preview = document.getElementById("preview");
    preview.style.width = cropimgElemWidth + "px";
    preview.style.height = cropimgElemHeight + "px";
    preview.style.left = cropimgElemWidth + 10 + "px";
    
    // 裁剪框内相关元素
    var mainBoxElem = document.getElementById("mainBox");// 裁剪框
    var rightElem = document.getElementById("right");
    var upElem = document.getElementById("up");
    var leftElem = document.getElementById("left");
    var downElem = document.getElementById("down");
    var leftUpElem = document.getElementById("left-up");
    var rightUpElem = document.getElementById("right-up");
    var leftDownElem = document.getElementById("left-down");
    var rightDownElem = document.getElementById("right-down");
    
    var ifKeyDown = false;// 鼠标按下事件
    var contact = "";// 表示被按下触点
    // 鼠标按下事件
    rightElem.onmousedown = function(e) {
        e.stopPropagation();
        ifKeyDown = true;
        contact = "right";
    };
    upElem.onmousedown = function(e) {
        e.stopPropagation();
        ifKeyDown = true;
        contact = "up";
    };
    leftElem.onmousedown = function(e) {
        e.stopPropagation();
        ifKeyDown = true;
        contact = "left";
    };
    downElem.onmousedown = function(e) {
        e.stopPropagation();
        ifKeyDown = true;
        contact = "down";
    };
    leftUpElem.onmousedown = function(e) {
        e.stopPropagation();
        ifKeyDown = true;
        contact = "left-up";
    };
    rightUpElem.onmousedown = function(e) {
        e.stopPropagation();
        ifKeyDown = true;
        contact = "right-up";
    };
    leftDownElem.onmousedown = function(e) {
        e.stopPropagation();
        ifKeyDown = true;
        contact = "left-down";
    };
    rightDownElem.onmousedown = function(e) {
        e.stopPropagation();
        ifKeyDown = true;
        contact = "right-down";
    };
    // 鼠标松开事件
    window.onmouseup = function(e) {
        ifKeyDown = false;
        contact = "";
    };
    // 鼠标移动事件
    window.onmousemove = function(e) {
        e.stopPropagation();
        if (ifKeyDown == true) {
            switch (contact) {
                case "right":
                    rightMove(e);
                    break;
                case "up":
                    upMove(e);
                    break;
                case "left":
                    leftMove(e);
                    break;
                case "down":
                    downMove(e);
                    break;
                case "left-up":
                    leftMove(e);
                    upMove(e);
                    break;
                case "right-up":
                    rightMove(e);
                    upMove(e);
                    break;
                case "left-down":
                    leftMove(e);
                    downMove(e);
                    break;
                case "right-down":
                    rightMove(e);
                    downMove(e);
                    break;
                default:
                    break;
            }
            setChoice();
        }
    };
    
    setChoice();// 初始化选择区域可见
    
    // 右边移动
    function rightMove(e) {
        var x = e.clientX;// 鼠标x坐标
//      if(x > getPosition(cropimgElem).left + cropimgElem.offsetWidth){
//          x = getPosition(cropimgElem).left + cropimgElem.offsetWidth;
//      }
        if (x > maxX || x < minX) {
            return;
        }
        var widthBefore = mainBoxElem.offsetWidth -2;// 裁剪框变化前的宽度
        var addWidth = x - getPosition(mainBoxElem).left - widthBefore;// 鼠标移动后,裁剪框增加的宽度
        var width = widthBefore + addWidth;
        if (width < 1) {
            return;
        }
        mainBoxElem.style.width = width + "px";// 裁剪框变化后,设置宽度
    };

    // 上边移动
    function upMove(e) {
        var y = e.clientY;// 鼠标y坐标
//      if(y < getPosition(cropimgElem).top){
//          y = getPosition(cropimgElem).top;
//      }
        if (y > maxY || y < minY) {
            return;
        }
        var mainY = getPosition(mainBoxElem).top;// 裁剪框相对于屏幕上边的距离
        var addHeight = mainY - y;// 增加的高度
        var heightBefore = mainBoxElem.offsetHeight - 2;// 裁剪框变化前的高度
        var height = heightBefore + addHeight;
        if (height < 1) {
            return;
        }
        mainBoxElem.style.height = height + "px";// 裁剪框变化后,设置高度
        mainBoxElem.style.top = mainBoxElem.offsetTop - addHeight + "px";// 裁剪框相对于父控件的距离
    };

    // 左边移动
    function leftMove(e) {
        var x = e.clientX;// 鼠标x坐标
//      if(x < getPosition(cropimgElem).left){
//          x = getPosition(cropimgElem).left;
//      }
        if (x > maxX || x < minX) {
            return;
        }
        var mainX = getPosition(mainBoxElem).left;
        var widthBefore = mainBoxElem.offsetWidth -2;// 裁剪框变化前的宽度
        var addWidth = mainX - x;// 鼠标移动后,裁剪框增加的宽度
        var width = widthBefore + addWidth;
        if (width < 1) {
            return;
        }
        mainBoxElem.style.width = width + "px";// 裁剪框变化后,设置宽度
        mainBoxElem.style.left = mainBoxElem.offsetLeft - addWidth + "px";// 裁剪框变化后,设置到父元素左边的距离
    };

    // 下边移动
    function downMove(e) {
        var y = e.clientY;// 鼠标y坐标
//      if(y > getPosition(cropimgElem).top + cropimgElem.offsetHeight){
//          y = getPosition(cropimgElem).top + cropimgElem.offsetHeight;
//      }
        if (y > maxY || y < minY) {
            return;
        }
        var heightBefore = mainBoxElem.offsetHeight - 2;// 裁剪框变化前的高度
        var mainY = getPosition(mainBoxElem).top;// 裁剪框相对于屏幕上边的距离
        var addHeight = y - heightBefore - mainY;// 增加的高度
        var height = heightBefore + addHeight;
        if (height < 1) {
            return;
        }
        mainBoxElem.style.height = height + "px";// 裁剪框变化后,设置高度
    };
    
    // 设置裁剪框的位置
    function setChoice() {
        var top = mainBoxElem.offsetTop;
        var right = mainBoxElem.offsetLeft + mainBoxElem.offsetWidth;
        var bottom = mainBoxElem.offsetTop + mainBoxElem.offsetHeight;
        var left = mainBoxElem.offsetLeft;
        var cropimg2 = document.getElementById("cropimg2");
        cropimg2.style.clip = "rect(" + top + "px, " + right + "px, " + bottom + "px, " + left + "px)";
    
        setPreview();
    };
    
    // 预览函数
    function setPreview() {
        var top = mainBoxElem.offsetTop;
        var right = mainBoxElem.offsetLeft + mainBoxElem.offsetWidth;
        var bottom = mainBoxElem.offsetTop + mainBoxElem.offsetHeight;
        var left = mainBoxElem.offsetLeft;
        var previewImg = document.getElementById("cropimg3");
        previewImg.style.top = -top + "px";
        previewImg.style.left = -left + "px";
        previewImg.style.clip = "rect(" + top + "px, " + right + "px, " + bottom + "px, " + left + "px)";
    }
    
};

// 获取元素相对于屏幕左边的距离 offsetLeft,offsetTop
function getPosition(node) {
    var left = node.offsetLeft;
    var top = node.offsetTop;
    var parent = node.offsetParent;
    while (parent != null) {
        left += parent.offsetLeft;
        top += parent.offsetTop;
        parent = parent.offsetParent;
    }
    return {"left":left,"top":top};
};

注:

1、为了防止父控件对子控件操作进行影响,所以增加e.stopPropagation();。

2、实现裁剪框拖动,还需要借助于jquery-ui-1.10.4.custom.min.js插件,同时添加以下代码:

// 裁剪框拖动
$("#mainBox").draggable({containment: 'parent', drag: setChoice});

3、为了防止裁剪框拖动时,父控件蓝屏闪烁,这里要添加以下代码,对父控件进行屏蔽:

document.onselectstart=new Function('event.returnValue=false;');

最后引入js到布局文件中即可:

<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.10.4.custom.min.js"></script>
<script type="text/javascript" src="js/clip-image.js"></script>

其他功能实现

1、上传图片并预览

<%--上传图片并预览--%>
$('#imgFile').change(function(event) {
    // 根据这个 <input> 获取文件的 HTML5 js对象
    var files = event.target.files, file;
    if (files && files.length > 0) {
        // 获取目前上传的文件
        file = files[0];
        // 获取window的 URL工具
        var URL = window.URL || window.webkitURL;
        // 通过 file生成目标 url
        var imgURL = URL.createObjectURL(file);
        // 用这个URL产生一个 <img> 将其显示出来
        $('#cropimg1').attr('src', imgURL);
        $('#cropimg2').attr('src', imgURL);
        $('#cropimg3').attr('src', imgURL);
        $('#cropimg4').attr('src', imgURL);
    }
});

2、获取裁剪相关信息,并上传

<%--保存裁剪之后的图片--%>
function saveCropImage() {
    // 需要获取裁剪之后,裁剪框的宽度和高度,以及裁剪框相对于裁剪图片的坐标位置
    var mainBox = document.getElementById("mainBox");
    // 裁剪框的宽度
    var width = mainBox.clientWidth;
    // 裁剪框的高度
    var height = mainBox.clientHeight;
    // 相对于裁剪图片x左边
    var x = mainBox.offsetLeft;
    // 相对于裁剪图片y左边
    var y = mainBox.offsetTop;
        
    alert(width);
    alert(height);
    alert(x);
    alert(y);
        
    // AjaxFileUpload提交 或者 jQuery提交表单
};

Github地址
阅读原文


微信公众号:书客创作
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,065评论 4 62
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,781评论 25 707
  • 《裕语言》速成开发手册3.0 官方用户交流:iApp开发交流(1) 239547050iApp开发交流(2) 10...
    叶染柒丶阅读 26,275评论 5 19
  • 携侣江边行,夕阳挂天幕。松水映残霞,远山起薄雾。波澜惹绮怀,红叶满霜树。中年百味尝,尘心转世故。所思寄小诗,每把真...
    倚剑白云天阅读 214评论 0 2
  • 生活顺利时,要知道福乐并非永恒﹔生活不如意时,视困境为过眼云烟。 人生中的许多事情,并非会像想象一样顺利。人生不如...
    淡淡忘阅读 585评论 0 1