基于原生JS实现图片裁剪


Posted in Javascript onAugust 01, 2016

下面是我自己写的图片裁剪的功能介绍:

可以利用鼠标拖拉,产生裁剪框

可以改变裁剪框大小

点击确定,返回裁剪数据

原理

完成裁剪的方法有两种:

1、利用HTML5新增拖拽事件drag drop等

2、传统方法,利用鼠标事件,mousedown、mousemove等

在这里,我们采用方法2。

裁剪区域的形成

要进行裁剪首先要形成裁剪区域,这个裁剪区域的形成我们可以与鼠标移动的距离相关联。鼠标移动多远,裁剪区域就有多大。如下图:

基于原生JS实现图片裁剪

如上图所示鼠标的横向移动距离与纵向移动距离共同组成了裁剪区域的宽和高。

而这横向与纵向移动的距离如何计算呢?当我们点下鼠标时,就能够通过event事件对象获取鼠标点击位置,而移动鼠标时,也能够通过event获取鼠标的位置,通过两次鼠标位置的改变,就能够获得鼠标的移动距离。

获取鼠标位置的属性是clientX以及clientY

阴影区域的形成

接下来就是绘制阴影区域。被裁剪图片中除裁剪区域以外的部分,都属于阴影部分,也可以不绘制该区域,绘制该区域是为了让用户更清晰的看清裁剪区域。

我将该区域分成了上下左右四个部分,见下图分布:

基于原生JS实现图片裁剪

那么该区域如果计算呢?这时就要用到Dom元素的偏移值了,利用裁剪区域的左偏移值减去图片本身的左偏移值就是左阴影的宽,利用裁剪区域的上偏移值减去图片的上偏移值,等于上阴影的高度值。如下图:

基于原生JS实现图片裁剪

获取到左阴影、上阴影的值后,就能够通过这两个将其他阴影的属性计算出来。

图片的偏移值有两种取法

    1.利用offsetLeft 与 offsetTop 值 弊端 如果dom元素有border margin等值会将这些值计算在内

    2.获取dom的css属性 弊端 预定义的css有关 如果没定义left top就无法获取

这两种方法都有各自的弊端,视不同情况来使用

裁剪越界的阻止

裁剪区域的计算是通过鼠标的移动距离来计算的,因此会出现裁剪区域越界的情况,而这情况又分成两种:

    1.裁剪过程中越界

    2.移动裁剪区域时越界

那么下面就来说说如何防止越界。

裁剪越界

什么是裁剪时越界?就是鼠标拖动区域超出了图片的返回,形成了越界,如下图:

基于原生JS实现图片裁剪

对于这种越界需要判断裁剪区域的右侧相对于浏览器左侧的位置 不能够超过 图片右侧的位置相当于浏览器左侧的位置;同时裁剪区域底部相对于浏览器顶部位置 不能够超过 图片底部相对应浏览器顶部的位置。还是画图来说明:

基于原生JS实现图片裁剪

TX >= PX 时就让TX的值强制为一固定值。

TX与PX的计算方法,假设裁剪区域为oTailor,图片区域oPicture:

TX = oTailor.offsetWidth + oTailor.offsetLeft;
PX = oPicture.offsetWidth + oPicture.offsetLeft;

同理,可以按照上述方法对左侧越界,上侧越界,下侧越界进行限制,就不多赘述。

移动越界

移动越界指的是已经形成了裁剪区域了,但通过鼠标移动裁剪区域时产生了越界。这个理解比较简单,就不画图介绍了。这种越界与dom拖拽越界限制一致,通过判断鼠标移动距离是否超过了图片区域来判断。

原理与问题解决了,现在开始来完成实际功能。

准备工作

在做之前,先做一些准备工作,磨刀不误砍柴功。

网页布局准备

网页布局部分关键代码如下:

<img src="./images/img_2.jpg" alt="">
<div class="img_box">
  <div class="box_border1"></div>
  <div class="box_border2"></div>
  <div class="box_border3"></div>
  <div class="box_border4"></div>
  <div class="box_handle" id="box_1"></div>
  <div class="box_handle" id="box_2"></div>
  <div class="box_handle" id="box_3"></div>
  <div class="box_handle" id="box_4"></div>
  <div class="box_handle" id="box_5"></div>
  <div class="box_handle" id="box_6"></div>
  <div class="box_handle" id="box_7"></div>
  <div class="box_handle" id="box_8"></div>
</div>
<!-- 左 -->
<div class="outer"></div>
<!-- 上 -->    
<div class="outer"></div>
<!-- 右 -->    
<div class="outer"></div>
<!-- 下 -->    
<div class="outer"></div>

<button class="confirm">确定</button>

其中img_box表示的是裁剪区域,outer表示阴影区域,而img_box中的div是裁剪区域的边框

样式控制如下:

* {
  padding:0;
  margin:0;
}
body {

  background: #454545;    
}          
.main {
  width: 500px;
  margin:50px auto;
}
.main img {
  width: 500px;
  position: absolute;
  left: 450px;
  top: 50px;
}
.img_box {    
  overflow: hidden;
  position: absolute;
  top:0px;
  left: 0px;
  z-index: 2;
}
.outer {
  overflow: hidden;
  background: #000;
  opacity: 0.4;
  position: absolute;
  top:0px;
  left: 0px;
  z-index: 0;
}
.box_border1 ,
.box_border2 ,
.box_border3 ,
.box_border4 {
  opacity: 0.5;
}
.box_border1 {
  background: url(./images/border-anim-v.gif) repeat-y left top;
} 
.box_border2 {
  background: url(./images/border-anim-h.gif) repeat-x left top;
}
.box_border3 {
  background: url(./images/border-anim-v.gif) repeat-y right top;
} 
.box_border4 {
  background: url(./images/border-anim-h.gif) repeat-x right bottom;
} 
.box_handle {    
  background: #fff;
  border: 1px solid #000;
  opacity: 0.5;
}
.confrim {
  width: 80px;
  height: 35px;
}

布局效果如下:

基于原生JS实现图片裁剪

通用函数

完成图片裁剪,通过上述原理,可以知道需要大量获取标签对象以及标签的css属性等,所以可以编写通用函数,更好的获取这些值。如下:

Dom获取函数

/*   仿JqueryDom获取   */
function $(dom) {

   function getDom(dom) {

    var str = dom.charAt(0);    
    switch( str ) {
      case '.' :
        this.ele = document.getElementsByClassName(dom.substring(1))||null;  

        break;

      case '#' :

        this.ele = document.getElementById(dom.substring(1)) || null;

        break;

      default : 

        if(document.getElementsByTagName(dom).length) {

          this.ele = document.getElementsByTagName(dom);                

        } else if(document.getElementsByName(dom).length) {

          this.ele = document.getElementsByName(dom);                  

        } else {          
          this.ele = null;
        }
    }
    return this;      
  };


  getDom.prototype.get = function(num) {
    return this.ele[num]||this.ele;
  }

  getDom.prototype.insert = function(value , num) {
    this.ele[num].innerHTML = value;      
  }

  return new getDom(dom);
}

Css属性获取函数

Css属性的获取分成两种,一种是IE的,使用currentStyle;另一种是其他主流浏览器,使用getComputedStyle,以下是兼容版本:

/* Css获取 */
function getCss(o , key){
  return o.currentStyle? o.currentStyle[key] : document.defaultView.getComputedStyle(o,false)[key];   
};

赋值函数

编写时经常遇到对Dom的样式进行赋值,为方便,我专门编写了一个函数用于赋值:

/**
 - 赋值函数 
 - @param : obj     被赋值对象
 - @param : option  进行的操作
 - @parma : value  赋值内容
 */
function setAssign(obj , option , value) {  

  switch(option) {
    case 'width':
      obj.style.width = value;
      break;
    case 'height':
      obj.style.height = value;
      break;
    case 'top':
      obj.style.top = value;
      break;
    case 'left':
      obj.style.left = value;
      break;
    case 'position':
      obj.style.position = value;
      break;
    case 'cursor':
      obj.style.cursor = value;
  }
}

好了准备工作基本完成,现在就正式开始编写。

通过点击与移动事件完成裁剪区域绘制

对图片设置mousedown以及mousemove事件监视,如下:

// 鼠标点击图片触发
oPicture.onmousedown = function(ev) {
  // 事件对象
  var oEvent = ev || window.event;

  // 初始鼠标位置
  var tempX = oEvent.clientX;
  var tempY = oEvent.clientY;      

  // 调整裁剪区域位置
  oTailor.style.left = oEvent.clientX + 'px';
  oTailor.style.top = oEvent.clientY + 'px';

  // 鼠标在图片上移动 绘制裁剪区域 阴影区域
  document.onmousemove = function(ev) {

    // 鼠标移动事件对象
    var oEvent = ev || window.event;

    // 当前鼠标位置减去鼠标之前的鼠标位置 等于 鼠标移动距离
    var sLeft = oEvent.clientX - tempX;
    var sTop = oEvent.clientY - tempY;

    // 裁剪越界限制 只需限制右侧 与 下侧
    if((oTailor.offsetLeft+oTailor.offsetWidth) >= (oPicture.offsetLeft+oPicture.offsetWidth)) {
      sLeft = oPicture.offsetLeft+oPicture.offsetWidth - oTailor.offsetLeft;
    }  
    if((oTailor.offsetTop+oTailor.offsetHeight) >= (oPicture.offsetTop+oPicture.offsetHeight)) {
      sTop = oPicture.offsetTop+oPicture.offsetHeight - oTailor.offsetTop;
    }

    // 裁剪区域绘制
    oTailor.style.width = sLeft + 'px';
    oTailor.style.height = sTop + 'px';

    // 裁剪区域显示
    oTailor.style.display = 'block';

    // 阴影区域显示
    for (var i = 0; i < oShadow.length; i++) {
      oShadow[i].style.display = 'block';
    }

    // 阴影区域绘制
    shadow(oPicture , oTailor , oShadow);

    // 添加裁剪边框
    tailorBorder(oDiv , oHandle , oTailor);

    // 阻止默认事件
    oEvent.preventDefault();
  };

  // 鼠标松开 将移动事件取消
  document.onmouseup = function(ev) {
    var oEvent = ev || window.event;

    // 移动事件取消
    document.onmousemove = null;

    // 阻止默认事件
    oEvent.preventDefault();
  };

  // 阻止默认事件
  oEvent.preventDefault();
}

阴影区域绘制

/** 
 * @param:oPicture    图片dom对象
 * @param:oTailor    裁剪区域dom对象
 * @param:oShadow    阴影区域dom对象
 */ 
function shadow(oPicture , oTailor , oShadow) {  

  // 左侧阴影区
  setAssign(oShadow[0] , 'width' , (parseInt(getCss(oTailor , 'left')) - parseInt(getCss(oPicture , 'left'))) + 'px');
  setAssign(oShadow[0] , 'height' , parseInt(getCss(oPicture , 'height')) + 'px');
  setAssign(oShadow[0] , 'left'  , parseInt(getCss(oPicture , 'left')) + 'px')
  setAssign(oShadow[0] , 'top'  , parseInt(getCss(oPicture , 'top')) + 'px')

  //右侧阴影区
  setAssign(oShadow[2] , 'width' , (parseInt(getCss(oPicture , 'width')) - parseInt(getCss(oTailor ,'width')) - parseInt(getCss(oShadow[0] , 'width'))) + 'px');
  setAssign(oShadow[2] , 'height' , parseInt(getCss(oPicture , 'height')) + 'px');
  setAssign(oShadow[2] , 'left'  , (parseInt(getCss(oTailor , 'left')) + parseInt(getCss(oTailor , 'width'))) + 'px');
  setAssign(oShadow[2] , 'top'  , parseInt(getCss(oPicture , 'top')) + 'px');

  // 上侧阴影区
  setAssign(oShadow[1] , 'width' , parseInt(getCss(oTailor , 'width')) + 'px');
  setAssign(oShadow[1] , 'height' , (parseInt(getCss(oTailor , 'top')) - parseInt(getCss(oPicture , 'top'))) + 'px');
  setAssign(oShadow[1] , 'left'  , (parseInt(getCss(oPicture , 'left')) + parseInt(getCss(oShadow[0] , 'width'))) + 'px');
  setAssign(oShadow[1] , 'top'  , parseInt(getCss(oPicture , 'top')) + 'px');

  // 下侧阴影区
  setAssign(oShadow[3] , 'width' , parseInt(getCss(oTailor , 'width')) + 'px');
  setAssign(oShadow[3] , 'height' , (parseInt(getCss(oPicture , 'height')) - parseInt(getCss(oTailor , 'height')) - parseInt(getCss(oShadow[1] , 'height'))) + 'px');
  setAssign(oShadow[3] , 'left'  , (parseInt(getCss(oPicture , 'left' )) + parseInt(getCss(oShadow[0] , 'width'))) + 'px');
  setAssign(oShadow[3] , 'top'  , (parseInt(getCss(oTailor , 'top' )) + parseInt(getCss(oTailor , 'height'))) + 'px');
}

注意在网页实际运用中,如果布局中图片css中没有left或top属性,那么上面代码会产生错误。应该使用offsetLeft与offsetTop代替之。

添加裁剪边框

在放出的布局图中,可以看见裁剪的边沿,四角及四边各有一个小正方形的形状,添加不仅是为了区分裁剪区与非裁剪区,还为下一步添加拉伸裁剪区域提供方便。下面开始编写代码:

/**
 *   裁剪边框绘制
 *   @param : oDIv    所有边框对象
 *   @param : oHandle   点状边沿
 * @param : oTailor  裁剪对象
 */
function tailorBorder(oDiv , oHandle , oTailor) {
  // 对边框进行初始化
  for (var i = 0; i < oDiv.length; i++) {
    setAssign(oDiv[i] , 'position' , 'absolute');
    setAssign(oDiv[i] , 'top'    , '0px');
    setAssign(oDiv[i] , 'left'    , '0px');
    setAssign(oDiv[i] , 'width'  , parseInt(getCss(oTailor , 'width')) + 'px');
    setAssign(oDiv[i] , 'height'  , parseInt(getCss(oTailor , 'height')) + 'px');
  }

  /* 点状边沿绘制 */  
  // 四角点状边沿绘制
  for (var i = 0; i < 4; i++) {  

    // 点状绘制
    setAssign(oHandle[i] , 'position' , 'absolute');
    setAssign(oHandle[i] , 'width'    , '5px');
    setAssign(oHandle[i] , 'height'  , '5px');

    // 0 2 表示左侧点状
    if(i % 2 == 0) {
      setAssign(oHandle[i] , 'left' , '0px');

      setAssign(oHandle[i] , 'top'  , (i == 0?'0px' : (parseInt(getCss(oTailor , 'height')) - 8) + 'px'));      

    } else {
      // 右侧点状
      setAssign(oHandle[i] , 'left' , ( parseInt(getCss(oTailor , 'width')) - 6 ) + 'px');

      setAssign(oHandle[i] , 'top'  , (i == 1?'0px' : parseInt(getCss(oTailor , 'height')) - 8 ) + 'px');          
    }                              
  }

  // 四边点状边框
  for (var i = 4; i < oHandle.length; i++) {
    setAssign(oHandle[i] , 'position' , 'absolute');
    setAssign(oHandle[i] , 'width'    , '5px');
    setAssign(oHandle[i] , 'height'  , '5px');

    // 4 6 表示上 下 点状边框
    if(i % 2 == 0) {

      setAssign(oHandle[i] , 'left' , parseInt(getCss(oTailor , 'width')) / 2 + 'px');

      setAssign(oHandle[i] , 'top'  , (i == 4 ? '0px' : (parseInt(getCss(oTailor , 'height')) - 8) + 'px'));

    } else {

      // 左右点状
      setAssign(oHandle[i] , 'top'  , parseInt(getCss(oTailor , 'height')) / 2 + 'px');

      setAssign(oHandle[i] , 'left' ,(i == 5 ? '0px' : parseInt(getCss(oTailor , 'width')) - 8 ) + 'px');

    }
  }
}

布局中,裁剪区域类名为box_handle的div前四个代表四角的点状,后四个表示边沿中间的点状,都按照顺时针分布。完成后效果如下:

基于原生JS实现图片裁剪

监视阴影区域

裁剪区域与阴影区域绘制完成,现在添加一个小功能,当鼠标点击到非裁剪区时(即阴影区),取消裁剪区域。

// 对阴影区域设置时间 点击到阴影区时 裁剪区域消失 阴影区消失
for (var i = 0; i < oShadow.length; i++) {
  oShadow[i].index = i;
  oShadow[i].onmousedown = function() {

    oTailor.style.display = 'none';
    oTailor.style.width = '0px';
    oTailor.style.hegiht = '0px';
    for (var i = 0; i < oShadow.length; i++) {
      oShadow[i].style.display = 'none';
      oShadow[i].style.left = '0px';
      oShadow[i].style.top = '0px';
    }                      
  }
}

监视鼠标移动位置

接下来添加裁剪区域拉伸的功能,当鼠标移动到边沿的点状边框时呈现不同的效果

添加鼠标显示效果

// 点状边框监视 设置相应操作
oTailor.onmousemove = function(ev) {
  var oTarget = oEvent.target;  
  switch(oTarget.id) {
    case 'box_1':              // 左上

      setAssign(oTailor , 'cursor' , 'nw-resize');        

      break;
    case 'box_2':              // 右上 

      setAssign(oTailor , 'cursor' , 'ne-resize');        

      break;
    case 'box_3':              // 左下

      setAssign(oTailor , 'cursor' , 'sw-resize');

      break;
    case 'box_4':              // 右下
      setAssign(oTailor , 'cursor' , 'se-resize');

      break;
    case 'box_5':              // 上      
      setAssign(oTailor , 'cursor' , 'n-resize');

      break;
    case 'box_6':              // 左
      setAssign(oTailor , 'cursor' , 'w-resize');

      break;
    case 'box_7':              // 下      
      setAssign(oTailor , 'cursor' , 's-resize');

      break;
    case 'box_8':              // 右      
      setAssign(oTailor , 'cursor' , 'e-resize');

      break;
    default :                // 裁剪区域 显示可移动提示
      setAssign(oTailor , 'cursor' , 'move');
      break;
  }
}

由于监视的div较多,因此采用事件委托的方式添加,效果不方便演示,有兴趣的同学可以自己测试,

添加拉伸效果

代码

// 裁剪区域的移动事件
oTailor.onmousedown = function(ev) {
  // event事件对象
  var oEvent = ev || window.event;
  // 获取cursor状态
  var oCur = getCss(oTailor , 'cursor');    
  // 鼠标初始位置
  var sTmpX = oEvent.clientX;
  var sTmpY = oEvent.clientY;

  // 获取裁剪区域的属性 用一个对象保存起来方便调用
  oAttrs.left = getCss(oTailor , 'left');
  oAttrs.top = getCss(oTailor , 'top');
  oAttrs.width = getCss(oTailor , 'width');
  oAttrs.height = getCss(oTailor , 'height');    

  document.onmousemove = function(ev) {
    // 移动事件对象
    var oEvent = ev || window.event;
    // 当前鼠标位置减去初始鼠标位置 等于 鼠标移动距离
    var sLeftT = oEvent.clientX - sTmpX;
    var sTopT = oEvent.clientY - sTmpY ;

    // 表示鼠标移动的距离
    var oTmpHeight = '';
    var oTmpTop = '';
    var oTmpWidth = '';
    var oTmpLeft = '';

    switch(oCur) {
      case 'nw-resize' :       // 左上

        oTmpWidth = parseInt(oAttrs.width) - sLeftT ; 
        oTmpHeight = parseInt(oAttrs.height) - sTopT ; 
        oTmpLeft = parseInt(oAttrs.left) + sLeftT ; 
        oTmpTop = parseInt(oAttrs.top) + sTopT ;                   

        break;
      case 'ne-resize' :       // 右上
        // 此时width不能减去鼠标移动距离 因为此时移动距离为正值
        oTmpWidth = parseInt(oAttrs.width) + sLeftT ; 
        oTmpHeight = parseInt(oAttrs.height) - sTopT ; 
        // 右上角移动不需要left值 因为默认响右移动
        oTmpTop = parseInt(oAttrs.top) + sTopT ;                                     

        break;
      case 'sw-resize' :       // 左下
        // 同右上 height 必须是加上鼠标移动距离
        oTmpWidth = parseInt(oAttrs.width) - sLeftT ; 
        oTmpHeight = parseInt(oAttrs.height) + sTopT ; 
        oTmpLeft = parseInt(oAttrs.left) + sLeftT ;                   

        break;
      case 'se-resize' :       // 右下
        // 左下与右上的结合 同时去除left与top
        oTmpWidth = parseInt(oAttrs.width) + sLeftT ; 
        oTmpHeight = parseInt(oAttrs.height) + sTopT ;           

        break;
      case 'n-resize' :       // 上

        oTmpHeight = parseInt(oAttrs.height) - sTopT;
        oTmpTop = parseInt(oAttrs.top) + sTopT;        

        break;
      case 'w-resize' :       // 左

        oTmpWidth = parseInt(oAttrs.width) - sLeftT ;
        oTmpLeft = parseInt(oAttrs.left) + sLeftT;   

        break;
      case 's-resize' :     // 下

        oTmpHeight = parseInt(oAttrs.height) + sTopT;

        break;
      case 'e-resize' :       // 右

        var oTmpWidth = parseInt(oAttrs.width) + sLeftT;

        break;
      default :                      
        // 否则是移动裁剪区域
        tailorMove(oEvent , oTailor , oPicture , oShadow);

        break;
    }  

 

    // 向上拉到边界
    if(parseInt(getCss(oTailor , 'top')) <= oPicture.offsetTop) {
      oTmpHeight = parseInt(getCss(oPicture,'height')) - (oPicture.offsetTop+parseInt(getCss(oPicture,'height'))-parseInt(getCss(oTailor,'top'))-parseInt(getCss(oTailor,'height')));
      oTmpTop = oPicture.offsetTop;
    }else if(oPicture.offsetTop+parseInt(getCss(oPicture,'height')) <= (parseInt(getCss(oTailor,'top'))+parseInt(getCss(oTailor,'height')))){
      // 向下拉到边界
      oTmpHeight = oPicture.offsetTop+parseInt(getCss(oPicture,'height')) - parseInt(getCss(oTailor,'top'));
    }
    // 向左拉到边界
    if((parseInt(getCss(oTailor , 'left'))) <= oPicture.offsetLeft) {
      oTmpWidth = parseInt(getCss(oPicture,'width')) - (oPicture.offsetLeft+parseInt(getCss(oPicture),'width')-parseInt(getCss(oTailor,'left'))-parseInt(getCss(oTailor,'width')))
      oTmpLeft = oPicture.offsetLeft;
    } else if(parseInt(getCss(oTailor , 'width')) + parseInt(getCss(oTailor,'left')) >= (oPicture.offsetLeft+oPicture.offsetWidth)) {
      // 向右拉到边界    
      oTmpWidth = oPicture.offsetLeft+oPicture.offsetWidth - parseInt(getCss(oTailor,'left'));            
    }

    // 赋值
    if(oTmpWidth){
      setAssign(oTailor , 'width' , oTmpWidth + 'px');
    }
    if(oTmpHeight) {
      setAssign(oTailor , 'height' , oTmpHeight + 'px');
    }
    if (oTmpLeft) {
      setAssign(oTailor , 'left' , oTmpLeft + 'px');
    }
    if (oTmpTop) {
      setAssign(oTailor , 'top' , oTmpTop + 'px');        
    }      

    // 阴影区域绘制
    shadow(oPicture , oTailor , oShadow);

    // 添加裁剪边框
    tailorBorder(oDiv , oHandle , oTailor);
  };

  // 当松开鼠标时注意取消移动事件
  document.onmouseup = function(ev) {
    // event事件对象
    var oEvent = ev || window.event;

    document.onmousemove = null;      
    oEvent.preventDefault();
  }

  oEvent.preventDefault();  
};

拉伸时注意移动距离的计算,特别是向上及向左移动时,要注意同时改变裁剪区域的left、top值,否则它只会向下、向右增大。来具体说一下如何计算:

原理

以鼠标向左上角拉伸为例,鼠标的移动距离与上面所讲的一致,但此时注意计算出的值是一个负数,所以在计算裁剪区域的增加值时,要用原裁剪区的宽度或高度减去该值,同时,增加多少宽度,裁剪区的左偏移值就要减去多少,否则显示的效果是裁剪区域向右增大,如下图:

基于原生JS实现图片裁剪

上图中,绿色区域是拉伸时增加宽、高后的裁剪区域,如果没进行偏移调整后的效果既是这样,黄色区域是进行偏移跳转后的裁剪区域,两个的叠加区就是原来的裁剪区了。

这是左上角拉伸,左下角拉伸即其他与之类似,可依照向上套。

而另一关键,拉伸越界在上面已经说过,就不再叙述了。

裁剪区域的移动

现在来说最后一个功能,裁剪区域的移动。当鼠标移动到裁剪区域内部时,就会触发移动事件,此时可以移动裁剪区域,代码如下:

/* 裁剪区域的移动 */
function tailorMove(ev ,oTailor , oPicture ,oShadow) {
  var oEvent = ev || window.event;

  var oTmpx = oEvent.clientX - oTailor.offsetLeft;
  var oTmpy = oEvent.clientY - oTailor.offsetTop;    

  document.onmousemove = function(ev) {
    var oEvent = ev || window.event;              

    oLeft = oEvent.clientX - oTmpx;
    oTop = oEvent.clientY - oTmpy;  


    if(oLeft < oPicture.offsetLeft ) {
      oLeft = oPicture.offsetLeft ;  
    } else if(oLeft > (oPicture.offsetLeft + oPicture.offsetWidth - oTailor.offsetWidth)) {
      oLeft = oPicture.offsetLeft + oPicture.offsetWidth - oTailor.offsetWidth;
    }      
    if(oTop < oPicture.offsetTop) {
      oTop = oPicture.offsetTop;  
    } else if (oTop > (oPicture.offsetTop + oPicture.offsetHeight - oTailor.offsetHeight)) {
      oTop = oPicture.offsetTop + oPicture.offsetHeight - oTailor.offsetHeight;
    }        

    oTailor.style.left = ( oLeft)+ 'px';
    oTailor.style.top = (oTop) + 'px';    
    shadow(oPicture , oTailor , oShadow);
  }
}

获取裁剪的位置

裁剪效果的功能基本完成,那么就要获取裁剪的位置,首先要知道需要获取那些属性。根据PHPGD库操作,进行图片裁剪需要知道,裁剪的起点坐标以及裁剪的宽高。我用一个函数来获取这些数据,并将其封装后返回:

function getEle() {
  var oPicture = $('img').get(0);
  var oTailor = $('.img_box').get(0);

  oAttrs.LeftX = (parseInt(getCss(oTailor,'left')) - oPicture.offsetLeft);
  oAttrs.LeftY = (parseInt(getCss(oTailor,'top')) - oPicture.offsetTop);
  oAttrs.Twidth = (parseInt(getCss(oTailor,'width')));
  oAttrs.Theight = (parseInt(getCss(oTailor,'height')));
  return oAttrs;
}

还有一个问题,如果网页上的图片是使用css压缩后的图片,那么在此获得的位置与裁剪大小会与你想像的有区别,可能裁剪后的图片范围会变大(原图较大),也有可能会变小(原图较小)。

如果能够获得原图的大小,可以根据压缩图与原图的比例来进行裁剪,这样可以获得正确的裁剪图。

好了,一个简单的图片裁剪功能就完成了,可以利用ajax传递到后台进行处理了。

本文内容到此就结束了,有问题的话欢迎大家留言讨论,希望本文对大家学习javascript有所帮助。

Javascript 相关文章推荐
js css样式操作代码(批量操作)
Oct 09 Javascript
JQUERY dialog的用法详细解析
Dec 19 Javascript
React.js入门实例教程之创建hello world 的5种方式
May 11 Javascript
跨域请求的完美解决方法(JSONP, CORS)
Jun 12 Javascript
js实现select选择框效果及美化
Aug 19 Javascript
jQuery电话号码验证实例
Jan 05 Javascript
Angular4实现动态添加删除表单输入框功能
Aug 11 Javascript
浅析为什么a=&quot;abc&quot; 不等于 a=new String(&quot;abc&quot;)
Oct 25 Javascript
Vue-Router2.X多种路由实现方式总结
Feb 09 Javascript
es6 filter() 数组过滤方法总结
Apr 03 Javascript
详解VScode编辑器vue环境搭建所遇问题解决方案
Apr 26 Javascript
Vue2.0 $set()的正确使用详解
Jul 28 Javascript
AngularJS基础 ng-include 指令简单示例
Aug 01 #Javascript
jQuery实现的表头固定效果实例【附完整demo源码下载】
Aug 01 #Javascript
AngularJS基础 ng-if 指令用法
Aug 01 #Javascript
AngularJS控制器之间的数据共享及通信详解
Aug 01 #Javascript
BootstrapTable+KnockoutJS自定义T4模板快速生成增删改查页面
Aug 01 #Javascript
AngularJS基础 ng-href 指令用法
Aug 01 #Javascript
jQuery实现点击行选中或取消CheckBox的方法
Aug 01 #Javascript
You might like
PHP脚本数据库功能详解(中)
2006/10/09 PHP
phpMyAdmin 链接表的附加功能尚未激活的问题
2010/08/01 PHP
使用PHP接收POST数据,解析json数据
2013/06/28 PHP
学习php设计模式 php实现模板方法模式
2015/12/08 PHP
PHP封装的PDO数据库操作类实例
2017/06/21 PHP
一文掌握PHP Xdebug 本地与远程调试(小结)
2019/04/23 PHP
Javascript异步表单提交,图片上传,兼容异步模拟ajax技术
2010/05/10 Javascript
JavaScript中URL编码函数代码
2011/01/11 Javascript
jQuery判断密码强度实现思路及代码
2013/04/24 Javascript
浅谈JavaScript之事件绑定
2013/07/08 Javascript
appendChild() 或 insertBefore()使用与区别介绍
2013/10/11 Javascript
JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)
2014/08/16 Javascript
JavaScript生成的动态下雨背景效果实现方法
2015/02/25 Javascript
js+html5实现canvas绘制简单矩形的方法
2015/06/05 Javascript
基于jQuery实现交互体验社会化分享代码附源码下载
2016/01/04 Javascript
Bootstrap carousel轮转图的使用实例详解
2016/05/17 Javascript
针对JavaScript中this指向的简单理解
2016/08/26 Javascript
总结十个Angular.js由浅入深的面试问题
2016/08/26 Javascript
简单理解vue中el、template、replace元素
2016/10/27 Javascript
jQuery实现点击某个div打开层,点击其他div关闭层实例分析(阻止冒泡)
2016/11/18 Javascript
详解Vue.js搭建路由报错 router.map is not a function
2017/06/27 Javascript
vue中rem的配置的方法示例
2018/08/30 Javascript
JS中实现一个下载进度条及播放进度条的代码
2019/06/10 Javascript
layui的layedit富文本赋值方法
2019/09/18 Javascript
Angular如何由模板生成DOM树的方法
2019/12/23 Javascript
vue实现图书管理系统
2020/12/29 Vue.js
python基础教程之对象和类的实际运用
2014/08/29 Python
python实现给字典添加条目的方法
2014/09/25 Python
Python插件virtualenv搭建虚拟环境
2017/11/20 Python
Python设计模式之组合模式原理与用法实例分析
2019/01/11 Python
自定义Django Form中choicefield下拉菜单选取数据库内容实例
2020/03/13 Python
Python selenium自动化测试模型图解
2020/04/15 Python
PAUL HEWITT手表美国站:德国北部时尚生活配饰品牌,船锚元素
2017/11/18 全球购物
新加坡网上化妆品店:Best Buy World
2018/05/18 全球购物
农村环境卫生倡议书
2015/04/29 职场文书
导游词之海南-南湾猴岛
2019/10/12 职场文书