Canvas裁剪图片(截选框可拖拽)

更新日期: 2019-06-28阅读: 2.5k标签: canvas

效果图



实现思路

  1. 打开图片并将图片绘制到canvas中;
  2. 利用canvas的drawImage()函数来裁剪图片;
  3. 将canvas转化为Image即可。


html代码

<div id="container">
  <div id="btnDiv">
    <button id="btn1">截图</button>
    <button id="btn2">确认截图</button>
    <button id="btn3">打开</button>
  </div>
  <div id="imgDiv"></div>
  <div id="clipImgDiv"></div>
</div>


css代码

CSS代码基本通过javaScript添加

<style>
    body {
      background-color: black;
    }
  </style>


重点JavaScript代码

变量定义、添加各事件按钮、容器等:

  let originWidth; // 图片原始宽度
  let originHeight; // 图片原始高度
  let container = document.getElementById('container');
  let imgDiv = document.getElementById('imgDiv');    // 存放mycanvas
  let btnDiv = document.getElementById('btnDiv');
  let clipImgDiv = document.getElementById('clipImgDiv');    // 显示裁剪所获的图片
  let btn1 = document.getElementById('btn1');    // 截图按钮
  let btn2 = document.getElementById('btn2');    // 确认截图按钮
  let btn3 = document.getElementById('btn3');    // 打开文件按钮
  var oRelDiv = document.createElement("div"); // 截图框
  var scaleX = 1;// 图片宽度缩放比例(当前实际/原始)
  var scaleY = 1;  // 图片高度缩放比例(当前实际/原始)
  //拖拽与拉伸方法
  //拖拽拉伸所需参数
  let params = {
    left: 0,
    top: 0,
    width: 0,
    height: 0,
    currentX: 0,
    currentY: 0,
    flag: false,
    kind: "drag"
  };
  
// CSS样式修改
  container.style.display = 'flex';
  container.style.flexDirection = 'column';
  btnDiv.style.marginBottom = '20px';
  btnDiv.style.height = '30px';
  imgDiv.style.marginBottom = '20px';

  // 创建canvas,用于显示被裁剪图片
  var myCanvas = document.createElement('canvas');
  myCanvas.setAttribute('id', 'myCanvas');
  myCanvas.style.display = 'block';
  /*myCanvas.style.position = 'absolute';*/
  myCanvas.width = 600;
  myCanvas.height = 600;
  myCanvas.style.border = "1px solid #d3d3d3";
  myCanvas.innerText = '您的浏览器不支持 HTML5 canvas 标签。';
  myCanvas.style.zIndex = 'auto';

  var ctx = myCanvas.getContext('2d');

  // 被裁剪图片
  var img = new Image();
  img.src = './images/IMG_1550.jpg';
  img.setAttribute('id', 'img');
  img.width = 600;
  img.height = 600;
  img.onload = function () {
    console.log('onload()执行...');
    ctx.drawImage(img, 0, 0, 600, 600);
    originWidth = img.naturalWidth;
    originHeight = img.naturalHeight;
    console.log('图片原始宽度=', originWidth);
    console.log('图片原始高度=', originHeight);
  };

  // 裁剪得到的图片
  let clipImg = new Image();
  clipImg.src = '';
  clipImg.style.height = '100px';
  clipImg.style.width = '100px';
  clipImg.alt = '裁剪获得图片...';

  // input用于打开文件
  let fileInput = document.createElement('input');
  fileInput.setAttribute('multiple', 'multiple');
  fileInput.setAttribute('type', 'file');
  fileInput.setAttribute('id', 'fileInput');

  /*btnDiv.appendChild(fileInput);*/
  imgDiv.appendChild(myCanvas);
  /*clipImgDiv.appendChild(clipImg);*/

一些简单的功能函数

// 生成本地图片URL地址
let getObjectURL = function (file) {
    let url = null;
    if (window.createObjectURL !== undefined) { // basic
      url = window.createObjectURL(file);
    } else if (window.webkitURL !== undefined) { // webkit or chrome
      url = window.webkitURL.createObjectURL(file);
    } else if (window.URL !== undefined) { // mozilla(firefox)
      url = window.URL.createObjectURL(file);
    }
    return url;
  };

  // 获取指定元素dom
  const ID = function (id) {
    return document.getElementById(id);
  };

  //获取相关CSS属性方法
  let getCss = function (o, key) {
    return o.currentStyle ? o.currentStyle[key] : document.defaultView.getComputedStyle(o, false)[key];
  };

打开本地图片

可伸缩截图框实现思路:

截图框由8各控制截图框大小、位置小div组成,鼠标在选中截图框后在拖动鼠标的过程中会根据鼠标位置对截图框进行实时绘制
// 打开本地图片
fileInput.addEventListener('change', function () {
    console.log('change()执行...');
    img.src = getObjectURL(this.files[0]);
  });
btn3.addEventListener("click", function () {
    fileInput.click();
  });

截图选框的绘制、拖动、大小调整

btn1.addEventListener("click", function () {
    var clickFlag = false;
    // 获取canvas中图片实际大小
    var iCurWidth = img.width;
    var iCurHeight = img.height;
    console.log('图片当前实际宽度=', iCurWidth);
    console.log('图片当前实际高度=', iCurHeight);

    // 可调整截图框
    oRelDiv.innerHTML = '';
    oRelDiv.style.position = "absolute";
    oRelDiv.style.width = iCurWidth + "px";
    oRelDiv.style.height = iCurHeight + "px";
    oRelDiv.style.top = myCanvas.offsetTop + 'px';
    console.log('oRelDiv.style.top = ', oRelDiv.style.top);
    oRelDiv.id = "cropContainer";

    var iOrigWidth = originWidth;
    var iOrigHeight = originHeight;
    scaleX = iCurWidth / iOrigWidth; // 图片宽度缩放比例(当前实际/原始)
    scaleY = iCurHeight / iOrigHeight;  // 图片高度缩放比例(当前实际/原始)
    console.log('图片横向(宽度)缩放比=', scaleX);
    console.log('图片纵向(高度)缩放比=', scaleY);

    // 将oRelDiv插入到myCanvas前
    myCanvas.parentNode.insertBefore(oRelDiv, myCanvas);

    //初始化坐标与剪裁高宽
    var cropW = 80; //截图框默认宽度
    var cropH = 80; //截图框默认高度
    /*console.log('myCanvas.offsetLeft=', myCanvas.offsetLeft);
    console.log('myCanvas.offsetTop=', myCanvas.offsetTop);*/
    var posX = myCanvas.width / 2 - cropW / 2;  // 截图框左上角x坐标
    var posY = myCanvas.height / 2 - cropH / 2;    // 截图框左上角y坐标
    /*console.log('posX=',posX);
    console.log('posY=',posY);*/

    oRelDiv.innerHTML = '<div id="zxxCropBox" + cropH + 'px; width:' + cropW + 'px; position:absolute; left:' +
      posX + 'px; top:' + posY + 'px; border:1px solid black;">' +
      '<div id="zxxDragBg"></div>' +
      '<div id="dragLeftTop"></div>' +
      '<div id="dragLeftBot"></div>' +
      '<div id="dragRightTop"></div>' +
      '<div id="dragRightBot"></div>' +
      '<div id="dragTopCenter"></div>' +
      '<div id="dragBotCenter"></div>' +
      '<div id="dragRightCenter"></div> ' +
      '<div id="dragLeftCenter"></div>' +
      '</div>' +
      '<input type="text" id="cropPosX" value="' + posX / scaleX + '"/>' +
      '<input type="text" id="cropPosY" value="' + posY / scaleY + '"/>' +
      '<input type="text" id="cropImageWidth" value="' + cropW / scaleX + '"/>' +
      '<input type="text" id="cropImageHeight" value="' + cropH / scaleY + '"/>';

    var startDrag = function (point, target, kind) {
      //point是拉伸点,target是被拉伸的目标,其高度及位置会发生改变
      //此处的target与上面拖拽的target是同一目标,故其params.left,params.top可以共用,也必须共用
      //初始化宽高
      params.width = getCss(target, "width");
      params.height = getCss(target, "height");
      //初始化坐标
      if (getCss(target, "left") !== "auto") {
        params.left = getCss(target, "left");
      }
      if (getCss(target, "top") !== "auto") {
        params.top = getCss(target, "top");
      }
      //target是移动对象
      point.onmousedown = function (event) {
        params.kind = kind;
        params.flag = true;
        clickFlag = true;
        if (!event) {
          event = window.event;
        }
        var e = event;
        params.currentX = e.clientX;  //鼠标按下时坐标x轴
        params.currentY = e.clientY;  //鼠标按下时坐标y轴
        /*console.log('params.currentX=', params.currentX);
        console.log('params.currentY=', params.currentY);*/
        //防止IE文字选中,有助于拖拽平滑
        point.onselectstart = function () {
          return false;
        };

        document.onmousemove = function (event) {
          let e = event ? event : window.event;
          clickFlag = false;
          if (params.flag) {
            var nowX = e.clientX; // 鼠标移动时x坐标
            var nowY = e.clientY;   // 鼠标移动时y坐标
            var disX = nowX - params.currentX;  // 鼠标x方向移动距离
            var disY = nowY - params.currentY;  // 鼠标y方向移动距离
            if (params.kind === "n") {
              //上拉伸
              //高度增加或减小,位置上下移动
              target.style.top = parseInt(params.top) + disY + "px";
              target.style.height = parseInt(params.height) - disY + "px";
            } else if (params.kind === "w") { //左拉伸
              target.style.left = parseInt(params.left) + disX + "px";
              target.style.width = parseInt(params.width) - disX + "px";
            } else if (params.kind === "e") { //右拉伸
              target.style.width = parseInt(params.width) + disX + "px";
            } else if (params.kind === "s") { //下拉伸
              target.style.height = parseInt(params.height) + disY + "px";
            } else if (params.kind === "nw") { //左上拉伸
              target.style.left = parseInt(params.left) + disX + "px";
              target.style.width = parseInt(params.width) - disX + "px";
              target.style.top = parseInt(params.top) + disY + "px";
              target.style.height = parseInt(params.height) - disY + "px";
            } else if (params.kind === "ne") { //右上拉伸
              target.style.top = parseInt(params.top) + disY + "px";
              target.style.height = parseInt(params.height) - disY + "px";
              target.style.width = parseInt(params.width) + disX + "px";
            } else if (params.kind === "sw") { //左下拉伸
              target.style.left = parseInt(params.left) + disX + "px";
              target.style.width = parseInt(params.width) - disX + "px";
              target.style.height = parseInt(params.height) + disY + "px";
            } else if (params.kind === "se") { //右下拉伸
              target.style.width = parseInt(params.width) + disX + "px";
              target.style.height = parseInt(params.height) + disY + "px";
            } else { //移动
              target.style.left = parseInt(params.left) + disX + "px";
              target.style.top = parseInt(params.top) + disY + "px";
            }
          }

          document.onmouseup = function () {

            params.flag = false;
            if (getCss(target, "left") !== "auto") {
              params.left = getCss(target, "left");
            }
            if (getCss(target, "top") !== "auto") {
              params.top = getCss(target, "top");
            }
            params.width = getCss(target, "width");
            params.height = getCss(target, "height");
            /*console.log('params.width=', params.width);
            console.log('params.height', params.width);*/

            //给隐藏文本框赋值
            posX = parseInt(target.style.left);
            posY = parseInt(target.style.top);
            cropW = parseInt(target.style.width);
            cropH = parseInt(target.style.height);
            if (posX < 0) {
              posX = 0;
            }
            if (posY < 0) {
              posY = 0;
            }
            if ((posX + cropW) > iCurWidth) {
              cropW = iCurWidth - posX;
            }
            if ((posY + cropH) > iCurHeight) {
              cropH = iCurHeight - posY;
            }
            //赋值
            ID("cropPosX").value = posX;
            ID("cropPosY").value = posY;
            ID("cropImageWidth").value = parseInt(ID("zxxCropBox").style.width);
            ID("cropImageHeight").value = parseInt(ID("zxxCropBox").style.height);

            /*console.log('posX=',posX);
            console.log('posY=',posY);*/
          };
        }
      };
    };

    //绑定拖拽
    startDrag(ID("zxxDragBg"), ID("zxxCropBox"), "drag");
    //绑定拉伸
    startDrag(ID("dragLeftTop"), ID("zxxCropBox"), "nw");
    startDrag(ID("dragLeftBot"), ID("zxxCropBox"), "sw");
    startDrag(ID("dragRightTop"), ID("zxxCropBox"), "ne");
    startDrag(ID("dragRightBot"), ID("zxxCropBox"), "se");
    startDrag(ID("dragTopCenter"), ID("zxxCropBox"), "n");
    startDrag(ID("dragBotCenter"), ID("zxxCropBox"), "s");
    startDrag(ID("dragRightCenter"), ID("zxxCropBox"), "e");
    startDrag(ID("dragLeftCenter"), ID("zxxCropBox"), "w");


    //图片不能被选中,目的在于使拖拽顺滑
    ID("myCanvas").onselectstart = function () {
      return false;
    };
    img.onselectstart = function () {
      return false;
    };
  });

所获截图绘制

function cropImage(img, cropPosX, cropPosY, width, height) {
    /*var cropContainer = ID("cropContainer");
    cropContainer.parentNode.removeChild(cropContainer);*/
    /*ctx.clearRect(0, 0, myCanvas.width, myCanvas.height);*/
    //sx,sy 是相对于图片的坐标。巨坑
    var newCanvas = document.createElement('canvas');
    newCanvas.setAttribute('id', 'newCanvas');
    newCanvas.width = width * scaleX;
    newCanvas.height = height * scaleY;
    newCanvas.style.border = "1px solid #d3d3d3";
    var newCtx = newCanvas.getContext('2d');
    clipImgDiv.appendChild(newCanvas);
    newCtx.drawImage(img, cropPosX, cropPosY, width, height, 0, 0, width * scaleX, height * scaleY);

    // canvas转化为图片
    var newImage = new Image();
    newImage.src = newCanvas.toDataURL("image/png");
    newImage.style.marginLeft = '5px';
    clipImgDiv.appendChild(newImage);

    oRelDiv.innerHTML = '';
  }

确认截图

// 确认截图
  btn2.addEventListener("click", function () {
    console.log("clipend......");

    var x = document.getElementById("cropPosX").value;
    var y = document.getElementById("cropPosY").value;
    var w = document.getElementById("cropImageWidth").value;
    var h = document.getElementById("cropImageHeight").value;
    console.log('cropImage(img,', x, ',', y, ',', parseInt(w), ',', parseInt(h), ')');
    cropImage(img, x / scaleX, y / scaleY, parseInt(w) / scaleX, parseInt(h) / scaleY);
  });
参考文章https://blog.csdn.net/qq_3870
来自:https://segmentfault.com/a/1190000019611035,作者:Cloudy




链接: https://www.fly63.com/article/detial/3918

HTML5 Canvas绘图基本使用方法, H5使用Canvas绘图

Canvas 是H5的一部分,允许脚本语言动态渲染图像。Canvas 定义一个区域,可以由html属性定义该区域的宽高,javascript代码可以访问该区域,通过一整套完整的绘图功能(API),在网页上渲染动态效果图。

web图片前端裁剪功能实现_利用html5 canvas技术实现图片裁剪

上传截图很多做法是把图像发送到后端,把裁剪后的结果发送给浏览器,这种方式会增加处理时延。用canvas提供的API实现纯前端的剪切:这里头关键有三步:显示未经处理的图片,得到裁剪区域,显示裁剪后的区域。

原生js使用canvas实现图片格式webp/png/jpeg在线转换

javascript完成图片格式转换: 通过input上传图片,使用FileReader将文件读取到内存中。将图片转换为canvas,canvas.toDataURL()方法设置为我们需要的格式,最后将canvas转换为图片。

离屏Canvas — 使用Web Worker提高你的Canvas运行速度

现在因为有了离屏Canvas,你可以不用在你的主线程中绘制图像了!Canvas 是一个非常受欢迎的表现方式,同时也是WebGL的入口。它能绘制图形,图片,展示动画,甚至是处理视频内容

canvas高效绘制10万图形,你必须知道的高效绘制技巧

最近的一个客户项目中,简化的需求是绘制按照行列绘制很多个圆圈。需求看起来不难,上手就可以做,写两个for循环。,IT行业的知识更新越来越快,能够以不变应万变的人,就是拥有良好的学习力、创造力、判断力和思考力的人。这些能力会让你在变换万千的技术海洋中,屹立不倒,不被淹没。

利用canvas将网页元素生成图片并保存在本地

利用canvas将网页元素生成图片并保存在本地,首先引入三个文件,createElementNS() 方法可创建带有指定命名空间的元素节点。 createElementNS(ns,name) > createElementNS() 方法与 createElement() 方法相似

基于 HTML5 Canvas 的智能安防 SCADA 巡逻模块

随着大数据时代的来临,物联网的日益发展,原先的 SCADA 系统本身也在求新求变,从最开始的专业计算机和操作系统,到通用计算机和相关软件,再到现在基于 HTML5 Canvas 的新型组态开发,其应用的范围也从最初的电力

js用canvas实现简单的粒子运动

在写下合格粒子运动时要先清楚你的思路,不能一开始就盲目的开始写,首先先要确定思路然后在去一步步的实现,在写的过程要注意细节,要思考js有些知识是跟数学知识相关的要注意观察

Canvas 点线动画案例

canvas 画的圆不是圆,是椭圆。不要在style里指定 Canvas 的宽度,Canvas 画布的尺寸的大小和显示的大小是有很大的区别的,在 canvas 里面设置的是才是 Canvas 本身的大小。不要企图通过闭合现有路径来开始一条新路径

Canvas在移动端绘制模糊的原因与解决办法

由于一些移动端的兼容性原因,我们某个项目需要前端将pdf转换成在移动端页面可直接观看的界面。为了方便解决,我们采用了pdf.js这个插件,该插件可以将pdf转换成canvas绘制在页面上

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!