基于 canvas 实现的一个截图小 demo

栏目: Html5 · 发布时间: 7年前

内容简介:基于 canvas 实现的一个截图小 demo

写在最前

记得以前在人人上看到一个分享,讲解基于js的截图方案,详细的不记得了,只记得还挺有意思的貌似用了canvas?所以这次打算自己写一个分享给大家作者的思路。这只是一个很简陋的小demo如有bug请提issues。按照惯例po 代码地址 ;以及作者博客的 github仓库 ,不定期更新中——[捂脸]求star

效果图

基于 canvas 实现的一个截图小 demo

整体思路

  1. 设置开始/结束快捷键
  2. 开始后将DOM绘制成canvas来覆盖原始DOM界面
  3. 添加一张canvas模拟鼠标截图区域
  4. 添加一张canvas用来绘制鼠标截图区域对应的浏览器界面(从第一张canvas中截取)
  5. 保存截取的图像

1.设置开始/结束快捷键

由于快捷键可能导致的冲突故希望开始快捷键可以不限定快捷键数量,所以在第一个参数中采用了数组的形式进行传递。

function screenShot(quickStartKey, EndKey) {
  //兼容性考虑不使用...扩展字符串
  var keyLength = quickStartKey.length
  var isKeyTrigger = {}
  var cantStartShot = false
  ...
  quickStartKey.forEach(function(item) { //遍历参数数组
    isKeyTrigger[item] = false //默认数组中所有键都没有触发
  })
  $('html').on('keyup', function(e) {
    var keyCode = e.which
    if(keyCode === EndKey) {
      ...
    } else if(!cantStartShot) {
      isKeyTrigger[keyCode] = true
      var notTrigger = Object.keys(isKeyTrigger).filter(function(item) {
        return isKeyTrigger[item] === false //查看有没有需要触发的快捷键
      })
      if(notTrigger.length === 0) { //没有需要触发的快捷键即可以开始截图
        cantStartShot = true
        beginShot(cantStartShot)
      }
    }
  })

2.将的DOM绘制成canvas来覆盖原始DOM界面

如果采用原生的方法可以参照MDN下对于在canvas中绘制DOM的介绍。里面最棘手的地方是你需要创建一个包含XML的SVG图像涉及到的元素为 <foreignObject> 。如何能计算出当前浏览器显示的DOM并且将其提取出来其实是最繁琐的。好的其实作者也没有好的思路手动实现一个=。=,所以选择了这个 html2canvas 库来完成这件事。大致调用方式如下:

function beginShot(cantStartShot) {
    if(cantStartShot) {
        html2canvas(document.body, {
            onrendered: function(canvas) {
                //得到与界面一致的canvas图像
            }
        })
    }
}

3.添加一张canvas模拟鼠标截图区域

这个地方的实现本来打算使用原生canvasAPI,但是里面涉及到一个问题就是在鼠标按下开始拖拽后,canvas要实时绘制,这里面就要引出一个类似于PS图层的概念,每当mousemove的时候都画出一个当前的截图框,但是当下一次触发mousemove的时候就删掉上一个截图框。以此来模拟实时的绘制过程。无奈作者没有找到使用canvas原生API的方法,如果有的话一定告诉我如何对画出的图做出标记。在这里作者使用了一个基于Jq的canvas的库叫做Jcanvas,里面给出了图层的概念,即在一个图层上只能画一张图,同时可以给图层标记名称。这就满足了作者的需求,实现如下:

$('#' + canvasId).mousedown(function(e) {
    $("#"+canvasId).removeLayer(layerName) //删除上一图层
    layerName += 1
    startX = that._calculateXY(e).x //计算鼠标位置
    startY = that._calculateXY(e).y
    isShot = true
    $("#"+canvasId).addLayer({
        type: 'rectangle', //矩形
        ...
        name:layerName, //图层名称
        x: startX,
        y: startY,
        width: 1,
        height: 1
    })
}).mousemove(function(e) {
    if(isShot) {
        $("#"+canvasId).removeLayer(layerName)
        var moveX = that._calculateXY(e).x
        var moveY = that._calculateXY(e).y
        var width = moveX - startX
        var height = moveY - startY
        $("#"+canvasId).addLayer({
            type: 'rectangle',
            ...
            name:layerName,
            fromCenter: false,
            x: startX,
            y: startY,
            width: width,
            height: height
        })
        $("#"+canvasId).drawLayers(); //绘制
    }
    })

4.添加一张canvas用来绘制鼠标截图区域对应的浏览器界面

var canvasResult = document.getElementById('canvasResult')
              var ctx = canvasResult.getContext("2d");
              ctx.drawImage(copyDomCanvas, moveX - startX > 0 ? startX : moveX, moveY - startY > 0 ? startY : moveY, width, height, 0, 0, width, height )
              var dataURL = canvasResult.toDataURL("image/png");

其中通过 drawImage 截取了图像,再使用 toDataURL 方法将图像转换为了base64编码

5.保存截取的图像

function downloadFile(el, fileName, href){
      el.attr({
        'download':fileName,
        'href': href
      })
  }
  ...
downloadFile($('.ok'), 'screenShot' + Math.random().toString().split('.')[1] || Math.random()  + '.png', dataURL)
// 传入按键对象、图像保存随机名、base64编码的图像

其中用到了a标签的download属性,当用户点击之后就可以直接进行下载。

部署

依赖项

<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/jcanvas/16.7.3/jcanvas.min.js"></script>
<script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.min.js"></script>

配置快捷键

screenShot([16, 65], 27) // 开始快捷键设置为shift+a;退出键为ESC

最后

文中最恶心的地方(DOM写入canvas、canvas设置图层)分别采用了两个库来进行实现,后续作者还会陆续关注如何使用原生API来实现这些操作,虽然个人认为自己写还是有点。。

最后的最后。。这是 作者的博客 欢迎不定时关注——


以上所述就是小编给大家介绍的《基于 canvas 实现的一个截图小 demo》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Realm of Racket

Realm of Racket

Matthias Felleisen、Conrad Barski M.D.、David Van Horn、Eight Students Northeastern University of / No Starch Press / 2013-6-25 / USD 39.95

Racket is the noble descendant of Lisp, a programming language renowned for its elegance and power. But while Racket retains the functional goodness of Lisp that makes programming purists drool, it wa......一起来看看 《Realm of Racket》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具