基于原生JS实现图片裁剪

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

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

可以改变裁剪框大小

点击确定,返回裁剪数据

原理

完成裁剪的方法有两种:

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

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

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

裁剪区域的形成

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

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

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

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

阴影区域的形成

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

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

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

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

图片的偏移值有两种取法

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

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

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

裁剪越界的阻止

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

1.裁剪过程中越界

2.移动裁剪区域时越界

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

裁剪越界

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

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

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;
}

布局效果如下:

通用函数

完成图片裁剪,通过上述原理,可以知道需要大量获取标签对象以及标签的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前四个代表四角的点状,后四个表示边沿中间的点状,都按照顺时针分布。完成后效果如下:

监视阴影区域

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

// 对阴影区域设置时间 点击到阴影区时 裁剪区域消失 阴影区消失
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值,否则它只会向下、向右增大。来具体说一下如何计算:

原理

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

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

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

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

裁剪区域的移动

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

/* 裁剪区域的移动 */
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有所帮助。

(0)

相关推荐

  • javascript 图片裁剪技巧解读

    学php gd库 看到有图片裁剪 正好整一个 嗯 其实挺简单的 php版 复制代码 代码如下: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Res

  • js实现点击后将文字或图片复制到剪贴板的方法

    本文实例讲述了js实现点击后将文字或图片复制到剪贴板的方法,代码非常简洁实用,具体功能代码如下所示: 实现复制文字代码: <table width="99%" border="0" cellpadding="0" cellspacing="0" class="firtable"> <tr> <th width="100%" style="color

  • jquery imgareaselect 使用利用js与程序结合实现图片剪切

    复制代码 代码如下: /* 缺陷,当前在ff3下,用jquery的 width()与height()函数,在不设置图片的宽度与高度的时候,不能取到 需要在图片load函数里面初始化才可以 */ sanshi_imgareaselect = function(pic_id,view_div_id){     this.pic_obj = jQuery("#"+pic_id);     this.pic_width;     this.pic_height;     this.view_d

  • php+js实现图片的上传、裁剪、预览、提交示例

    首先用到的语言是php.插件imgareaselect(下载地址),没有太多花哨的样式,index.php代码如下: 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.or

  • 基于JavaScript实现图片剪切效果

    学会如何获取鼠标的坐标位置以及监听鼠标的按下.拖动.松开等动作事件,从而实现拖动鼠标来改变图片大小. 还可以学习css中的clip属性. 一.CSS实现图片不透明及裁剪效果. 图片剪切三层结构 1.第一层opacity,给图层设置透明度 2.第二层clip,clip属性:对图片进行裁剪,实现图像的一部分显示,其他部分进行隐藏 3.第三层选取框absolute(与第二层重叠的),包括八个触点的效果 html代码: <div id="box"> <img src=&quo

  • 使用JavaScript+canvas实现图片裁剪

    canvas是一个可以让我们使用脚本绘图的标签,它提供了一系列完整的属性和方法.我们可以借此来实现图形绘制,图像处理甚至实现简单的动画和游戏制作. canvas标签只有两个属性:width和height,用来设定画布的宽和高,如果没有通过标签属性或者脚本来设置,默认为300*150; 好了,canvas的介绍就先到这里,下面我们来看看javascript结合canvas实现图片的裁剪代码: 复制代码 代码如下: var selectObj = null; function ImageCrop(c

  • JS实现图片剪裁并预览效果

    今天又疯狂学习了web前端的图片剪裁效果,可以有个区域来框住图片的某一部分,并可以预览框住的部分 效果图如下: 看着是不是很炫呢 简单介绍下实现方法吧 1.布局就是左右两块div,右边的好说,主要是左边的,左边的用绝对布局的方式分了3层,最下面一层是一个半透明的图片,中间一层是原图,但被剪切成只有一块,也只显示这一块,可以用clip:rect方法实现,然后最上面一层就是自己写的一个边框,在边框上加了8个点,分别给这8个点定义位置. 2.然后JS代码用了鼠标的点击事件来实现. 下面贴上自己的代码:

  • 利用Javascript裁剪图片并存储的简单实现

    前言 就我而言,页面上的设计比较灵动的部分,其实不是很多,诸如滑动验证码,图片裁剪等比较好的交互设计. 从刚开始工作的时候,我就想把这些东西了解下,无奈一直没这个需求,乘着今天的空闲,研究了一下午,期间遇到了大大小小的问题,一直备受折磨,这其实也反映一个问题,我的 还是比较薄弱. 实现效果: 用户点击上传图片后,页面显示所上传的图片,并且出现裁剪框和两个预览区域,最后点击裁剪按钮保存裁剪的图片到服务器上. 效果很简单,整个过程我遇到的两个难点,第一个是裁剪的JS效果,第二个则是图片数据的处理.

  • js+jquery实现图片裁剪功能

    现在我们在使用各大网站的个人中心时,都有个上传个人头像的功能.用户在上传了个人照片之后,可能不符合网站的要求,于是要求用户对照片进行裁剪,最终根据用户裁剪的尺寸生成头像.这个功能真是太棒了,原来不懂js的时候,感觉很神奇,太神奇了.心想哪天要是自己也能搞明白这里面的技术,那该多牛呀~大家是不是也有何我一样的想法呀~哈哈~~ 下面我们就来用javascript来实现这个功能吧. 复制代码 代码如下: <!DOCTYPE html> <html xmlns="http://www.

  • 基于原生JS实现图片裁剪

    下面是我自己写的图片裁剪的功能介绍: 可以利用鼠标拖拉,产生裁剪框 可以改变裁剪框大小 点击确定,返回裁剪数据 原理 完成裁剪的方法有两种: 1.利用HTML5新增拖拽事件drag drop等 2.传统方法,利用鼠标事件,mousedown.mousemove等 在这里,我们采用方法2. 裁剪区域的形成 要进行裁剪首先要形成裁剪区域,这个裁剪区域的形成我们可以与鼠标移动的距离相关联.鼠标移动多远,裁剪区域就有多大.如下图: 如上图所示鼠标的横向移动距离与纵向移动距离共同组成了裁剪区域的宽和高.

  • 原生JS实现图片翻书效果

    下面给大家分享基于原生js实现的图片翻书效果,具体代码如下所示: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>JS实现图片翻书效果-懒人图库</title> <META

  • 基于原生JS实现分页效果的示例代码

    这个只是一个分页的demo,主要是思路整理(很久之前项目用的东西) 分页实现的效果 主要是 左侧上一页 右侧是下一页 中间显示主要是超过5个显示 省略号 然后是可配置选项 实现之后的效果 首先需要初始化该对象的一些基本属性,显示总页码数,中间显示的页面数, 添加一个回调函数,在页面变化激活回调函数并返回当前页面和一些需要的其他参数 init为对象初始化的方法(里面的参数都是可以写成活的,我这里偷懒了所以写成死的了) 这个里的 z_page 可以接是接口返回的总页数 function Page(o

  • 基于原生js运动方式关键点的总结(推荐)

    主要方法:定时器的运用 setInterval(funnction(){},30); 为了避免最后时刻速度即将停止时的误差,可以采用下面的方法: if(iSpeed<1)//速度足够小的时候,让速度直接为0,避免速度的波动 { iSpeed = 0; } 绝对值的运用(主要运用于弹性运动等速度有正负的情况): Math.abs(2.5)// 2 弹性运动和摩擦力的组合: iSpeed+=(iTarget-obj.offsetLeft)/5; iSpeed*=0.7; 模拟摩擦力: iSpeed*

  • 原生js实现图片轮播特效

    本文特意为原生js实现图片轮播特效代码做了下总结,分享给大家供大家参考,欢迎大家学习. 运行效果图: 具体代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>最简单的轮播广告</title> <style> body, div, ul, li { margin: 0; padding: 0

  • 原生JS实现图片网格式渐显、渐隐效果

    先给出效果图: 写的小组件支持图片的渐显.渐隐,并且可以是有序.随机两种方式. 我采用的原型是属性写在构造函数内,方法写在原型对象内.方法写构造函数内有个问题,就是每次调用这个方法就相当于重新实例化一次,举个粟子: 实现网格效果的原理上是将读取图片的宽高,按照设定的参数,分成等高宽的网格(我用的span标签表示的网格),网格利用定位铺满整个图片,每个网格的背景图都是原图片,原理同sprite,利用background-position属性改变显示区域.接下来就是按照设定的顺序实现渐显或渐隐.渐显

  • 原生JS实现图片无缝滚动方法(附带封装的运动框架)

    话说轮播图效果是前端er学习JS的必经之路啊,很多同学写的第一个JS效果应该就是它了,在各大网站我们都会经常见到,但是无缝滚动运动效果的轮播图,对于小白们来说还是有一定难度的. 我们来看看思路吧~ 首先我们要实现的效果有以下几点: 小圆点:点击小圆点显示与之对应的图片 向左和向右按钮:点击向左按钮图片向后运动,点击向右按钮图片向前运动 定时器:每隔 2s 自动播放 主要难点在于: 当图片运动到最后一张,点击向右的按钮时,应该显示第一张: 当前显示的是第一张,点击向左的按钮时,应该显示最后一张:

  • 原生JS实现图片轮播与淡入效果的简单实例

    最近对css的兴趣提不起来,因为以前对图片轮播一直耿耿于怀苦于学艺不精,所以,花了点时间熟悉了一下js.然后一条道走到黑,用jquery和js写了一下轮播和图片淡入的效果.以后学习的路很长,希望自己在前端的路上越走越远`(∩_∩)′ 从原理来讲,网上的教程有很多,简单来说. 淡入淡出,其实这里只用到了淡入的效果.每一张淡入的图片,我们将它的display设置为block,其他为none,所以实际存在并且在文档流占位置的只有一张图片.在设置图片的display方式之前,将图片的透明度逐渐增大,就会

  • 原生JS实现图片懒加载之页面性能优化

    在项目开发中,我们往往会遇到一个页面需要加载很多图片的情况.我们可以一次性加载全部的图片,但是考虑到用户有可能只浏览部分图片.所以我们需要对图片加载进行优化,只加载浏览器窗口内的图片,当用户滚动时,再加载更多的图片.这种加载图片的方式叫做图片懒加载,又叫做按需加载或图片的延时加载.这样做的好处是:1.可以加快页面首屏渲染的速度:2.节约用户的流量. 一.实现思路 1.图片img标签自定义一个属性data-src来存放真实的地址. 2.当滚动页面时,检查所有的img标签,判断是否出现在事业中,如果

  • JS端基于download.js实现图片、视频时直接下载而不是打开预览

    项目中的附件列表,通常情况都需要提供下载.删除的功能,功能本身没有什么要说的,都是基本功能,使用浏览器的的下载功能,也都是用window.open(url),或者window.location.href=url的方式,url即为附件下载接口,浏览器自动解析,如果是图片.视频.txt等格式的会直接预览文件,而不是像docx.xlsx一样直接下载,项目中为了功能明确,将预览单独加了一个查看按钮,下载按钮要实现无论什么文件格式都直接下载. 有两种方式处理: 一.后台接口层面处理:(比较常见) 响应头中

随机推荐