基于html2canvas 的简易截图工具

今天分享一个自己手写的简易截图工具(基于html2canvas),因为是在vue项目上做的,少量用了es6语法,如果不支持es6的项目上需要稍微修改下,写的时候有考虑过这个,所以只需要改引入方式、将class换成es5的构造函数写法、let和const换成var即可。

基于html2canvas要画重点*,所以生成图片跟html2canvas的规则是一样的,请熟知html2canvas的特性(比如部分css3不兼容,svg之类的,该怎么处理就按html2canvas的方法处理完再调用)*

大致思路如下:
1、使用html2canvas将目标dom转化为图片;
2、然后在body上创建全屏弹窗,将图片置于弹窗内,再创建蒙版(蒙版绑定鼠标点击、移动事件)覆盖在上面,形成灰蒙蒙的截图界面;
3、截图界面已经形成,接来下就是鼠标拖拽创建(拉伸)矩形选区,根据鼠标在蒙版上点击时的坐标,然后计算按住鼠标后指针移动的实时坐标 计算出矩形选区的宽高,这样矩形选区就可以完整的创建出来并实时更新大小了,创建矩形选区之后在选区内8个方位创建8个拖拽点并绑定事件用于拉伸选区的宽高,同时也要给选区绑定拖拽事件用于移动选区;
4、矩形选区创建完成之后接下来就是让选区内部的视觉效果变成清晰高亮了,我这里用的是背景图偏移属性background-position,首先我们将矩形选区的样式background-image设置为第一步生成的图片,然后计算矩形选区与图片的相对坐标来设置偏移量;这样视觉效果就出来了;
5、通过上面的步骤我们已经能拿到选区的坐标和大小了,接下来就通过canvas的drawImage方法和计算的各个数值生成最终的截图并转化为base64,然后绑定各种钩子(如成功、取消等),这样一个简易的截图工具就算完成了,接下来我会考虑找时间加上那些辅助截图工具用于标注截图之类的

有什么地方写的不好的请私聊指正,勿喷哈

零、补充

a、演示地址

懒出风格的我终于弄了个demo来了 泪目
http://tools.lzhong.wang/tools/screenshot

一、代码实现

这里并非完整代码而是一个个实现步骤

1、初始化

开始之前记得先安装html2canvas(以vue为例)

npm install html2canvas --save

然后开始撸代码,首先创建一个构造函数并调用html2canvas将目标dom转化为图片的base64编码,赋值给imgUrl

// 引入html2canvas
import html2canvas from 'html2canvas';
// 样式
const cssText = {
  box: 'overflow:hidden;position:fixed;left:0;top:0;right:0;bottom:0;background-color:rgba(255,255,255,0.9);z-index: 100000;',
  img: '',
  mask: 'position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(0,0,0,0.6);',
  rect: 'position:absolute;border:1px solid #3e8ef7;box-sizing:border-box;cursor:move;user-select:none;background: url() no-repeat;',
  toolBox: 'position:absolute;top:0;left:0;padding:0 10px;background:#eee;line-height:2em;text-align:right;',
  toolBtn: 'font-weight:bold;color:#111;margin:0 1em;user-select:none;font-size:12px;cursor:pointer;',
}
// 构造类
/**
 * dom节点截图工具(基于html2canvas)
 * dom: 要截图的目标dom
 * options: { 
 *   // 以下三个回调方法作用域this指向构造函数
 *   success: function(res), //截图完成触发 参数为截图结果
 *   fail: function(), //取消截图触发
 *   complete: function(), //截图结束触发 success和fail都会触发
 * }
 * 调用示例:
 * new ClipScreen(dom节点, {
 *   success: function (res) {},
 *   complete: function () {},
 * });
 */
class ClipScreen {
  constructor(dom, options) {
    if (window.ClipScreen) return false;
    window.ClipScreen = this;
    this.dom = dom;
    this.options = options;
    html2canvas(this.dom).then((canvas) => {
      let dataURL = canvas.toDataURL("image/png");
      this.imgUrl = dataURL;
      this.start(); // 下一步要用的 调用初始化方法
    });
  }
}
export default ClipScreen

2、生成截图界面

图片base64有了,接下来就是初始化截图界面(载入图片,创建蒙版,并为蒙版绑定事件)

start() {
    this.border = 2; // 用于计算选区拖拽点和边界的判断
    this.win_w = window.innerWidth;
    this.win_h = window.innerHeight; 
    // 创建弹窗并写入样式
    let box = this.box = document.createElement('div');
    box.id = 'ClipScreen';
    box.style.cssText = cssText.box;
    // 创建图片
    let img = document.createElement('img');
    img.style.cssText = cssText.img;
    img.src = this.imgUrl;
    // 创建蒙版
    let mask = document.createElement('div');
    mask.style.cssText = cssText.mask;
    box.appendChild(img);
    box.appendChild(mask);
    document.body.appendChild(box);
    // 图片载入 初始化图片
    img.onload = (e) => {
      let w = img.offsetWidth,
        h = img.offsetHeight,
        win_w = window.innerWidth,
        win_h = window.innerHeight,
        left = (win_w - w) / 2,
        top = (win_h - h) / 2;
      img.style.position = 'absolute';
      img.style.left = left + 'px';
      img.style.top = top + 'px';
      img.style.width = w + 'px';
      img.style.height = h + 'px';
      this.axis = {
        left,
        top
      }
      this.img = img;
      // 蒙版绑定事件
      this.bindEvent(mask);
    }
  }
  bindEvent(mask) {
    document.onkeydown = (e) => {
      if (e.keyCode == 27) {
        this.cancel();
      }
    }
    mask.onmousedown = (e) => {
      let offsetX = e.offsetX,
        offsetY = e.offsetY;
      document.onmousemove = (e) => {
        let x = e.offsetX,
          y = e.offsetY,
          sx = offsetX,
          sy = offsetY,
          w = Math.abs(offsetX - x),
          h = Math.abs(offsetY - y);
        if (x < offsetX) sx = x;
        if (y < offsetY) sy = y;
        this.createRect(sx, sy, w, h); // 下一部用的 创建矩形选区
      }
      document.onmouseup = (e) => {
        this.unbindMouseEvent(); // 解绑鼠标move和up事件
      }
    }
  }
   // 解绑鼠标move和up事件
  unbindMouseEvent() {
    document.onmousemove = null;
    document.onmouseup = null;
  }

3、创建矩形选区,绑定选区相关事件

通过上一步的蒙版拖拽事件来创建矩形选区,并绑定事件,同时改变选区图片视觉高亮效果

// 创建矩形截图选区
  createRect(x, y, w, h) {
    let rect = this.rect;
    if (!rect) {
      rect = this.rect = document.createElement('div');
      rect.style.cssText = cssText.rect;
      rect.style.backgroundImage = 'url(' + this.imgUrl + ')';
      // 创建8个方向的拖拽点
      const doms = this.createPoints(rect);
      this.box.appendChild(rect);
      // 绑定选区事件
      this.bindRectEvent(doms);
    }
    let border = this.border;
    if (x <= border) x = border;
    if (y <= border) y = border;
    if (x + w >= this.win_w - border) x = this.win_w - border - w;
    if (y + h >= this.win_h - border) y = this.win_h - border - h;
    rect.style.pointerEvents = 'none';
    rect.style.display = 'block';
    rect.style.left = x + 'px';
    rect.style.top = y + 'px';
    rect.style.width = w + 'px';
    rect.style.height = h + 'px';
    // 矩形选区图片视觉高亮
    rect.style.backgroundPosition = (-x + this.axis.left - 1) + 'px ' + (-y + this.axis.top - 1) + 'px';
    if (this.toolBox) this.toolBox.style.display = 'none';
  }
  // 创建截图选区各个方位拉伸点
  createPoints(rect) {
    let
      lt = document.createElement('span'),
      tc = document.createElement('span'),
      rt = document.createElement('span'),
      rc = document.createElement('span'),
      rb = document.createElement('span'),
      bc = document.createElement('span'),
      lb = document.createElement('span'),
      lc = document.createElement('span');
    let c_style = 'position:absolute;width:5px;height:5px;background:#3e8ef7;';
    lt.style.cssText = c_style + 'left:-3px;top:-3px;cursor:nw-resize;';
    tc.style.cssText = c_style + 'left:50%;top:-3px;margin-left:-3px;cursor:ns-resize;';
    rt.style.cssText = c_style + 'right:-3px;top:-3px;cursor:ne-resize;';
    rc.style.cssText = c_style + 'top:50%;right:-3px;margin-top:-3px;cursor:ew-resize;';
    rb.style.cssText = c_style + 'right:-3px;bottom:-3px;cursor:nw-resize;';
    bc.style.cssText = c_style + 'left:50%;bottom:-3px;margin-left:-3px;cursor:ns-resize;';
    lb.style.cssText = c_style + 'left:-3px;bottom:-3px;cursor:ne-resize;';
    lc.style.cssText = c_style + 'top:50%;left:-3px;margin-top:-3px;cursor:ew-resize;';
    let res = {lt,tc,rt,rc,rb,bc,lb,lc}
    for (let k in res) {
      rect.appendChild(res[k])
    }
    res.rect = rect;
    return res;
  }
  // 绑定截图选区事件
  bindRectEvent(o) {
    o.rect.addEventListener("mousedown", (e) => {
      let border = this.border;
      let $target = e.target;
      let offsetX = e.x,
        offsetY = e.y;
      let r_w = o.rect.offsetWidth,
        r_h = o.rect.offsetHeight,
        r_l = o.rect.offsetLeft,
        r_t = o.rect.offsetTop;
	// 拖拽移动选区
      if ($target == o.rect) {
        offsetX = e.offsetX;
        offsetY = e.offsetY;
        document.onmousemove = (e) => {
          let dif_x = e.x - offsetX,
            dif_y = e.y - offsetY;
            // 边界判断
          if (dif_x <= border) dif_x = border;
          if (dif_y <= border) dif_y = border;
          if (dif_x + r_w >= this.win_w - border) dif_x = this.win_w - border - r_w;
          if (dif_y + r_h >= this.win_h - border) dif_y = this.win_h - border - r_h;
          o.rect.style.left = dif_x + 'px';
          o.rect.style.top = dif_y + 'px';
          o.rect.style.backgroundPosition = (-dif_x + this.axis.left - 1) + 'px ' + (-dif_y + this.axis.top - 1) + 'px';
          this.toolBox.style.display = 'none'
        }
      } else {
      // 八个方位的拖拽点事件
        document.onmousemove = (e) => {
          this.toolBox.style.display = 'none'
          this.transform($target, o, offsetX, offsetY, r_w, r_h, r_l, r_t, e)
        }
      }
      document.onmouseup = (e) => {
        this.moveToolBox(); // 工具栏
        this.unbindMouseEvent();
      }
    })
  }
  // 拉伸选区
  transform($t, o, offsetX, offsetY, r_w, r_h, r_l, r_t, e) {
    let border = this.border;
    let x = e.x,
      y = e.y;
      // 边界判断
    if (x <= border) x = border;
    if (y <= border) y = border;
    if (x >= this.win_w - border) x = this.win_w - border;
    if (y >= this.win_h - border) y = this.win_h - border;
    let dif_x = x - offsetX,
      dif_y = y - offsetY;
    let min = 10; // 宽高最小值
    let left = r_l,
      top = r_t,
      width = r_w,
      height = r_h;
      // 判断是哪个方位的拖拽点
    if ($t == o.lt) {
      if (r_w - dif_x <= min || r_h - dif_y <= min) return false; // 最小宽高判断
      left = r_l + dif_x;
      top = r_t + dif_y;
      width = r_w - dif_x;
      height = r_h - dif_y;
    } else if ($t == o.tc) {
      if (r_h - dif_y <= min) return false;
      top = r_t + dif_y;
      height = r_h - dif_y;
    } else if ($t == o.rt) {
      if (r_w + dif_x <= min || r_h - dif_y <= min) return false;
      top = r_t + dif_y;
      width = r_w + dif_x;
      height = r_h - dif_y;
    } else if ($t == o.rc) {
      if (r_w + dif_x <= min) return false;
      width = r_w + dif_x;
    } else if ($t == o.rb) {
      if (r_w + dif_x <= min || r_h + dif_y <= min) return false;
      width = r_w + dif_x;
      height = r_h + dif_y;
    } else if ($t == o.bc) {
      if (r_h + dif_y <= min) return false;
      height = r_h + dif_y;
    } else if ($t == o.lb) {
      if (r_w - dif_x <= min || r_h + dif_y <= min) return false;
      left = r_l + dif_x;
      width = r_w - dif_x;
      height = r_h + dif_y;
    } else if ($t == o.lc) {
      if (r_w - dif_x <= min) return false;
      left = r_l + dif_x;
      width = r_w - dif_x;
    }
    // 根据拖拽点计算矩形的大小和方位
    o.rect.style.left = left + 'px';
    o.rect.style.top = top + 'px';
    o.rect.style.width = width + 'px';
    o.rect.style.height = height + 'px';
     //改变矩形选区背景图偏移量
    o.rect.style.backgroundPosition = (-left + this.axis.left - 1) + 'px ' + (-top + this.axis.top - 1) + 'px';
  }

4、工具栏相关

这里主要是工具栏的相关代码

// 生成 、移动工具
  moveToolBox() {
    let toolBox = this.toolBox;
    if (!toolBox) {
    // 创建工具栏
      toolBox = this.toolBox = document.createElement('div');
      toolBox.style.cssText = cssText.toolBox;
      let save = document.createElement('span'),
        cancel = document.createElement('span');
      save.innerText = '完成';
      cancel.innerText = '取消';
      save.style.cssText = cancel.style.cssText = cssText.toolBtn;
      toolBox.appendChild(cancel);
      toolBox.appendChild(save);
      this.box.appendChild(toolBox);
      this.bindToolBoxEvent(save, cancel);
    }
    // 显示工具栏并设置工具栏所在坐标
    toolBox.style.display = 'block';
    let border = this.border;
    let t_w = this.toolBox.offsetWidth,
      t_h = this.toolBox.offsetHeight,
      r_t = this.rect.offsetTop,
      r_h = this.rect.offsetHeight;
    let t = r_t + r_h + 10,
      l = this.rect.offsetLeft + this.rect.offsetWidth - t_w;
     // 工具栏坐标判断,确保不会跑出浏览器外部,提高视觉体验(规则同微信截图)
    if (l <= border) l = border;
    if (t >= this.win_h - border - t_h) t = r_t - t_h - 10;
    if (r_h >= this.win_h - border - t_h) {
      t = r_t + r_h - t_h - 10;
      l -= 10;
    }
    toolBox.style.top = t + 'px';
    toolBox.style.left = l + 'px';
  }
  // 绑定工具栏按钮事件
  bindToolBoxEvent(save, cancel) {
    save.onclick = () => { // 完成
      this.success();
    }
    cancel.onclick = () => { // 取消
      this.cancel();
    }
  }

5、截图完成

生成最终截图(没什么好说的就是调用各种api)、绑定各种回调事件,

// 生成base64图片
  getImagePortion(imgDom, new_w, new_h, s_x, s_y) {
    let sx = s_x - this.axis.left,
      sy = s_y - this.axis.top;
    let t_cv = document.createElement('canvas');
    let t_ct = t_cv.getContext('2d');
    t_cv.width = new_w;
    t_cv.height = new_h;

    let b_cv = document.createElement('canvas');
    let b_ct = b_cv.getContext('2d');
    b_cv.width = imgDom.width;
    b_cv.height = imgDom.height;
    b_ct.drawImage(imgDom, 0, 0);

    t_ct.drawImage(b_cv, sx, sy, new_w, new_h, 0, 0, new_w, new_h);
    let res = t_cv.toDataURL();
    return res;
  }
// 完成
  success() {
    let imgBase64 = this.getImagePortion(this.img, this.rect.offsetWidth, this.rect.offsetHeight, this.rect.offsetLeft, this.rect.offsetTop);
    if (this.options) {
      this.options.success && this.options.success.call(this, imgBase64);
    }
    this.close();
  }
  // 取消
  cancel() {
    if (this.options) {
      this.options.fail && this.options.fail.call(this);
    }
    this.close();
  }
  close() {
    if (this.options) {
      this.options.complete && this.options.complete.call(this);
    }
    this.distroy();
  }
  // 销毁
  distroy() {
    window.ClipScreen = undefined;
    this.box.remove();
  }

至此,简易功能就算是实现了

二、场景效果(截图)

初始化界面是根据dom的大小1比1生成的图片
原始dom节点 截图界面显示的是我截图的目标dom
原始dom
初始化蒙版状态
初始化界面
截图过程
截图过程

截图过程
截图过程
截图完成后获得的图片(该效果为项目内容,本插件只能返回成品截图的base64编码)
截图完成的效果
由于项目隐私 不方便拍视频 也懒得再去写一个demo 所以将就着哈

三、完整代码

完整代码下载链接:
https://download.csdn.net/download/qq_34206004/13705057

import html2canvas from 'html2canvas';
// 样式
const cssText = {
  box: 'overflow:hidden;position:fixed;left:0;top:0;right:0;bottom:0;background-color:rgba(255,255,255,0.9);z-index: 100000;',
  img: '',
  mask: 'position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(0,0,0,0.6);',
  rect: 'position:absolute;border:1px solid #3e8ef7;box-sizing:border-box;cursor:move;user-select:none;background: url() no-repeat;',
  toolBox: 'position:absolute;top:0;left:0;padding:0 10px;background:#eee;line-height:2em;text-align:right;',
  toolBtn: 'font-weight:bold;color:#111;margin:0 1em;user-select:none;font-size:12px;cursor:pointer;',
}
/**
 * dom节点截图工具(基于html2canvas)
 * dom: 要截图的目标dom
 * options: { 
 *   // 以下三个回调方法作用域this指向构造函数
 *   success: function(res), //截图完成触发 参数为截图结果
 *   fail: function(), //取消截图触发
 *   complete: function(), //截图结束触发 success和fail都会触发
 * }
 * 
 * 调用示例:
 * new ClipScreen(dom节点, {
 *   success: function (res) {},
 *   complete: function () {},
 * });
 */
class ClipScreen {
  constructor(dom, options) {
    if (window.ClipScreen) return false;
    window.ClipScreen = this;
    this.dom = dom;
    this.options = options;
    html2canvas(this.dom).then((canvas) => {
      let dataURL = canvas.toDataURL("image/png");
      this.imgUrl = dataURL;
      this.start();
    });
  }
  // 初始化
  start() {
    this.border = 2; //用于计算选区拖拽点和边界的判断
    this.win_w = window.innerWidth;
    this.win_h = window.innerHeight;
    let box = this.box = document.createElement('div');
    box.id = 'ClipScreen';
    box.style.cssText = cssText.box;
    let img = document.createElement('img');
    img.style.cssText = cssText.img;
    img.src = this.imgUrl;
    let mask = document.createElement('div');
    mask.style.cssText = cssText.mask;
    box.appendChild(img);
    box.appendChild(mask);
    document.body.appendChild(box);
    img.onload = (e) => {
      let w = img.offsetWidth,
        h = img.offsetHeight,
        win_w = window.innerWidth,
        win_h = window.innerHeight,
        left = (win_w - w) / 2,
        top = (win_h - h) / 2;
      img.style.position = 'absolute';
      img.style.left = left + 'px';
      img.style.top = top + 'px';
      img.style.width = w + 'px';
      img.style.height = h + 'px';
      this.axis = {
        left,
        top
      }
      this.img = img;
      this.bindEvent(mask);
    }
  }
  // 绑定蒙版事件、键盘事件
  bindEvent(mask) {
    document.onkeydown = (e) => {
      if (e.keyCode == 27) {
        this.cancel();
      }
    }
    mask.onmousedown = (e) => {
      let offsetX = e.offsetX,
        offsetY = e.offsetY;
      document.onmousemove = (e) => {
        let x = e.offsetX,
          y = e.offsetY,
          sx = offsetX,
          sy = offsetY,
          w = Math.abs(offsetX - x),
          h = Math.abs(offsetY - y);
        if (x < offsetX) sx = x;
        if (y < offsetY) sy = y;
        this.createRect(sx, sy, w, h);
      }
      document.onmouseup = (e) => {
        this.moveToolBox();
        this.rect.style.pointerEvents = 'initial';
        this.unbindMouseEvent();
      }
    }
  }
  // 创建矩形截图选区
  createRect(x, y, w, h) {
    let rect = this.rect;
    if (!rect) {
      rect = this.rect = document.createElement('div');
      rect.style.cssText = cssText.rect;
      rect.style.backgroundImage = 'url(' + this.imgUrl + ')';
      // this.newImg = document.createElement('img');
      // this.newImg.style.cssText = cssText.rect_img;
      // rect.appendChild(this.newImg);
      let doms = this.createPoints(rect);
      this.box.appendChild(rect);
      this.bindRectEvent(doms);
    }
    let border = this.border;
    if (x <= border) x = border;
    if (y <= border) y = border;
    if (x + w >= this.win_w - border) x = this.win_w - border - w;
    if (y + h >= this.win_h - border) y = this.win_h - border - h;
    rect.style.pointerEvents = 'none';
    rect.style.display = 'block';
    rect.style.left = x + 'px';
    rect.style.top = y + 'px';
    rect.style.width = w + 'px';
    rect.style.height = h + 'px';
    rect.style.backgroundPosition = (-x + this.axis.left - 1) + 'px ' + (-y + this.axis.top - 1) + 'px';
    if (this.toolBox) this.toolBox.style.display = 'none';
  }
  // 创建截图选区各个方位拉伸点
  createPoints(rect) {
    let
      lt = document.createElement('span'),
      tc = document.createElement('span'),
      rt = document.createElement('span'),
      rc = document.createElement('span'),
      rb = document.createElement('span'),
      bc = document.createElement('span'),
      lb = document.createElement('span'),
      lc = document.createElement('span');
    let c_style = 'position:absolute;width:5px;height:5px;background:#3e8ef7;';
    lt.style.cssText = c_style + 'left:-3px;top:-3px;cursor:nw-resize;';
    tc.style.cssText = c_style + 'left:50%;top:-3px;margin-left:-3px;cursor:ns-resize;';
    rt.style.cssText = c_style + 'right:-3px;top:-3px;cursor:ne-resize;';
    rc.style.cssText = c_style + 'top:50%;right:-3px;margin-top:-3px;cursor:ew-resize;';
    rb.style.cssText = c_style + 'right:-3px;bottom:-3px;cursor:nw-resize;';
    bc.style.cssText = c_style + 'left:50%;bottom:-3px;margin-left:-3px;cursor:ns-resize;';
    lb.style.cssText = c_style + 'left:-3px;bottom:-3px;cursor:ne-resize;';
    lc.style.cssText = c_style + 'top:50%;left:-3px;margin-top:-3px;cursor:ew-resize;';
    let res = {
      lt,
      tc,
      rt,
      rc,
      rb,
      bc,
      lb,
      lc
    }
    for (let k in res) {
      rect.appendChild(res[k])
    }
    res.rect = rect;
    return res;
  }
  // 生成 、移动工具
  moveToolBox() {
    let toolBox = this.toolBox;
    if (!toolBox) {
      toolBox = this.toolBox = document.createElement('div');
      toolBox.style.cssText = cssText.toolBox;
      let save = document.createElement('span'),
        cancel = document.createElement('span');
      save.innerText = '完成';
      cancel.innerText = '取消';
      save.style.cssText = cancel.style.cssText = cssText.toolBtn;
      toolBox.appendChild(cancel);
      toolBox.appendChild(save);
      this.box.appendChild(toolBox);
      this.bindToolBoxEvent(save, cancel);
    }
    toolBox.style.display = 'block';
    let border = this.border;
    let t_w = this.toolBox.offsetWidth,
      t_h = this.toolBox.offsetHeight,
      r_t = this.rect.offsetTop,
      r_h = this.rect.offsetHeight;
    let t = r_t + r_h + 10,
      l = this.rect.offsetLeft + this.rect.offsetWidth - t_w;
    if (l <= border) l = border;
    if (t >= this.win_h - border - t_h) t = r_t - t_h - 10;
    if (r_h >= this.win_h - border - t_h) {
      t = r_t + r_h - t_h - 10;
      l -= 10;
    }
    toolBox.style.top = t + 'px';
    toolBox.style.left = l + 'px';
  }
  // 绑定工具栏事件
  bindToolBoxEvent(save, cancel) {
    save.onclick = () => {
      this.success();
    }
    cancel.onclick = () => {
      this.cancel();
    }
  }
  // 绑定截图选区事件
  bindRectEvent(o) {
    o.rect.addEventListener("mousedown", (e) => {
      let border = this.border;
      let $target = e.target;
      let offsetX = e.x,
        offsetY = e.y;
      let r_w = o.rect.offsetWidth,
        r_h = o.rect.offsetHeight,
        r_l = o.rect.offsetLeft,
        r_t = o.rect.offsetTop;

      if ($target == o.rect) {
        offsetX = e.offsetX;
        offsetY = e.offsetY;
        document.onmousemove = (e) => {
          let dif_x = e.x - offsetX,
            dif_y = e.y - offsetY;
          if (dif_x <= border) dif_x = border;
          if (dif_y <= border) dif_y = border;
          if (dif_x + r_w >= this.win_w - border) dif_x = this.win_w - border - r_w;
          if (dif_y + r_h >= this.win_h - border) dif_y = this.win_h - border - r_h;
          o.rect.style.left = dif_x + 'px';
          o.rect.style.top = dif_y + 'px';
          o.rect.style.backgroundPosition = (-dif_x + this.axis.left - 1) + 'px ' + (-dif_y + this.axis.top - 1) + 'px';
          this.toolBox.style.display = 'none'
        }
      } else {
        document.onmousemove = (e) => {
          this.toolBox.style.display = 'none'
          this.transform($target, o, offsetX, offsetY, r_w, r_h, r_l, r_t, e)
        }
      }
      document.onmouseup = (e) => {
        this.moveToolBox();
        this.unbindMouseEvent();
      }
    })
  }
  // 拉伸选区
  transform($t, o, offsetX, offsetY, r_w, r_h, r_l, r_t, e) {
    let border = this.border;
    let x = e.x,
      y = e.y;
    if (x <= border) x = border;
    if (y <= border) y = border;
    if (x >= this.win_w - border) x = this.win_w - border;
    if (y >= this.win_h - border) y = this.win_h - border;
    let dif_x = x - offsetX,
      dif_y = y - offsetY;
    let min = 10;
    let left = r_l,
      top = r_t,
      width = r_w,
      height = r_h;
    if ($t == o.lt) {
      if (r_w - dif_x <= min || r_h - dif_y <= min) return false;
      left = r_l + dif_x;
      top = r_t + dif_y;
      width = r_w - dif_x;
      height = r_h - dif_y;
    } else if ($t == o.tc) {
      if (r_h - dif_y <= min) return false;
      top = r_t + dif_y;
      height = r_h - dif_y;
    } else if ($t == o.rt) {
      if (r_w + dif_x <= min || r_h - dif_y <= min) return false;
      top = r_t + dif_y;
      width = r_w + dif_x;
      height = r_h - dif_y;
    } else if ($t == o.rc) {
      if (r_w + dif_x <= min) return false;
      width = r_w + dif_x;
    } else if ($t == o.rb) {
      if (r_w + dif_x <= min || r_h + dif_y <= min) return false;
      width = r_w + dif_x;
      height = r_h + dif_y;
    } else if ($t == o.bc) {
      if (r_h + dif_y <= min) return false;
      height = r_h + dif_y;
    } else if ($t == o.lb) {
      if (r_w - dif_x <= min || r_h + dif_y <= min) return false;
      left = r_l + dif_x;
      width = r_w - dif_x;
      height = r_h + dif_y;
    } else if ($t == o.lc) {
      if (r_w - dif_x <= min) return false;
      left = r_l + dif_x;
      width = r_w - dif_x;
    }
    o.rect.style.left = left + 'px';
    o.rect.style.top = top + 'px';
    o.rect.style.width = width + 'px';
    o.rect.style.height = height + 'px';
    o.rect.style.backgroundPosition = (-left + this.axis.left - 1) + 'px ' + (-top + this.axis.top - 1) + 'px';
  }
  // 解绑事件
  unbindMouseEvent() {
    document.onmousemove = null;
    document.onmouseup = null;
  }
  // 生成base64图片
  getImagePortion(imgDom, new_w, new_h, s_x, s_y) {
    let sx = s_x - this.axis.left,
      sy = s_y - this.axis.top;
    let t_cv = document.createElement('canvas');
    let t_ct = t_cv.getContext('2d');
    t_cv.width = new_w;
    t_cv.height = new_h;

    let b_cv = document.createElement('canvas');
    let b_ct = b_cv.getContext('2d');
    b_cv.width = imgDom.width;
    b_cv.height = imgDom.height;
    b_ct.drawImage(imgDom, 0, 0);

    t_ct.drawImage(b_cv, sx, sy, new_w, new_h, 0, 0, new_w, new_h);
    let res = t_cv.toDataURL();
    return res;
  }
  // 完成
  success() {
    let imgBase64 = this.getImagePortion(this.img, this.rect.offsetWidth, this.rect.offsetHeight, this.rect.offsetLeft, this.rect.offsetTop);
    if (this.options) {
      this.options.success && this.options.success.call(this, imgBase64);
    }
    this.close();
  }
  // 取消
  cancel() {
    if (this.options) {
      this.options.fail && this.options.fail.call(this);
    }
    this.close();
  }
  // 关闭
  close() {
    if (this.options) {
      this.options.complete && this.options.complete.call(this);
    }
    this.distroy();
  }
  // 销毁
  distroy() {
    window.ClipScreen = undefined;
    this.box.remove();
  }
}
export default ClipScreen
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
shearphoto2.0 是HTML5头像截图插件,拍照截图JS截图,美工切图插件,能直接压缩数码相机图片进行截图!是互联网上写得最好的一个同类型插件 ShearPhoto 完美支持Linux Windows 服务器,国外空间等完美通过。 兼容IE6及所有浏览器,兼容PHP5.2X至PHP7.0! ShearPhoto拖动拉伸超准,超流畅,在互联网同类型软件绝对排行第一,除了shearphoto,你别无选择! JAVA用户请到http://git.oschina.net/alexyang/JFinal-shearphoto 下载 ------------------------------------------------------------------------ 从shearphoto 1.5直接跳跃到shearphoto 2.0,这是shearphoto重大革新。本来我是想shearphoto 1.6 、1.7、 1.8 慢慢升的,但是这样升级只会让shearphoto慢慢走向灭亡!结果我又辛苦了一个多星期,把shearphoto 2.0升级完成! shearphoto2.0之前,我认为没必要加入HTML5,兼容IE6 7 8就够。但是直到后来!我知道这是我一个错误的决定 因为用户并没有为shearphoto 1.5埋单,原因shearphoto 1.5没有HTML5截取,用户觉得会增加服务器负载!而且又不是本地加载图片!我一个错误的决定!导致用户份额一直没有明显大增。 shearphoto 2.0是收集所有用户的意见开发而成的! 重大的特性就是全面支持HTML5 1:支持translate3d 硬件加速移动 2:加入图片预览功能 3:加入了压缩数码相机图片, 以及HTML5 canvas本地切图,截图 但依然继续支持IE6 7 8 哦!有人问IE6 7 8不兼容HTML5啊,你骗人吗? 先不要急!shearphoto 2.0的机制是这样的:有HTML5则使用HTML5 canvas切图,截图JS先会截取一张最合理化的截图,然后交给后端,根据用户设置,进行压缩截图 没有HTML5的浏览器则采用先上传再截取的策略,就是原先1.5的策略。 当然有些用户如果不喜欢HTML5,也可以根据接口自行关闭 4:加HTML5图片特效,就一如美图秀秀这样的特效!shearphoto一共提供14种漂亮特效,感谢腾讯AI对图片特效提供支持 shearphoto 2.0增添很多接口,大部份是HTML5的设置!请下载源码体验 shearphoto外忧内患,已经没退路了。在WEB截图界,shearphoto必须要干个第一!.shearphoto不再局限于头像截取,shearphoto更可用于商城的商品图片编辑。 shearphoto含HTML5图片压缩功能!一张十M 二十M的图,照样能帮你压成你要的容量和尺寸, 一般情况下!商城的商品图片都是通过数码相机拍摄后,要用PHOTOshop把数码相机内几十M的图片,压缩,截取,然后才能上传到商城服务器! 这样的操作是不是太麻烦了! 如果你使用shearphoto你就快捷很多了,shearphoto你只需要直接选择图片,就会帮你进行压缩截取,上传,添加到数据库。这样的一条龙服务! shearphoto 2.0的机制是无可挑剔的!但是不排除有BUG存在,如果用户遇到BUG情况,请到论坛 或官方QQ群进行反馈,我会第一时间发布补丁! shearphoto支持PHP和JAVA,JAVA由网友所写,但是JAVA版并不是太完善,使用的是以前的shearphoto1.3!我 一直很想把NET python nodejs JAVA的很完善地做出来! 可惜个人能力有限,如果你喜欢shearphoto,你又会玩 NET python nodejs JAVA,又想为互联网做贡献,那么你可以加入shearphoto团队,把这些后端版本做出来。但shearphoto没有薪水给你! shearphoto免费开源的,没有利润可图,纯粹是抱着为互联网做贡献的心态!如果你跟我一样,请加入到shearphoto后端开发 浏览器支持: 兼容IE 6 及以上的所有浏览器 后端支持: 支持PHP5.X 至 PHP7.0或以上 支持JAVA后端(shearphoto1.3开发) 系统支持: 支持linux WINDOW服务器 shearphoto采用原生JS + 原生PHP所写,绝对不含JQ插件,对JQ情有独忠的,这个插件不合适你 2015 年 9月 5 日 shearphoto作者:明哥先生 版本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值