VUE图像裁剪小工具

图像裁剪分为两个区域,预览区域、裁剪区域。

第一步:拿到File文件对象,创建Image对象并在此处理预览区域的宽高。

             预览区域宽高处理:图片尺寸大小分为三种,宽大于高、高大于宽、宽高相等。宽大于高或者宽高相等处理方式,宽度计算公式:宽除以高乘以宽度基准值,高度固定。高大于宽处理方式,高度计算公式:高除以宽乘以高度基准值,宽度固定。(住:宽基准值184,高基准值:184)

第二步:获取预览区域canvasDOM,通过drawImage方法绘制图像。处理预览区域位置。预览裁剪同步处理,通过getImageData方法将预览区域图像同步到裁剪区域。

第三步:鼠标移动预览区域,预览裁剪同步处理。根据图片大小规格处理移动方式,宽大与高纵向移动,垂直方向固定。高大于宽垂直方向移动,纵向固定。宽高相等禁止移动。通过鼠标移动X,Y方向的值进行预览裁剪同步处理。

第四步:裁剪,获取裁剪区域canvasDOM,通过putImageData方法将获取到的预览区域图片信息绘制到裁剪区域。

第五步:下载,通过toDataURL获取裁剪区域图片信息,通过fetch方法将获取到的图片URL信息转换为blob。

整体代码:

<template>
  <div class="cropping">
    <div class="cropping-box">
      <!-- 预览 -->
      <div class="box-l">
        <canvas class="pre_canvas"></canvas>
      </div>
      <!-- 裁剪 -->
      <div class="box-r">
        <canvas class="cro_canvas"></canvas>
      </div>
    </div>
  </div>
</template>
<script>
import move from './move.js';
export default {
  data() {
    return {
      preCanvasData: {
        w: '',
        h: '',
        maxW: 184,
        maxH: 184,
        pre_ctx: null
      },
      croCanvasData: {
        w: 184,
        h: 184
      }
    };
  },
  mounted() {},
  methods: {
    // 创建Image对象,处理宽高
    ready(file = null) {
      let that = this;
      const { maxH, maxW } = this.preCanvasData;
      let img = new Image();
      img.src = window.URL.createObjectURL(file);
      img.onload = function () {
        const W = img.width;
        const H = img.height;
        that.preCanvasData.w = W;
        that.preCanvasData.h = H;
        // 宽大于高或者宽高相等处理方式
        if ((W > maxW && W > H) || W === H) {
          that.preCanvasData.w = (W / H) * maxW; // 宽度计算公式:宽除以高乘以宽度基准值
          that.preCanvasData.h = maxH; // 高度固定
        }
        // 高大于宽处理方式
        if (H > maxH && H > W) {
          that.preCanvasData.w = maxW;
          that.preCanvasData.h = (H / W) * maxH; //高度计算公式:高除以宽乘以高度基准值
        }
        that.preview(img);
      };
    },
    // 预览
    preview(img) {
      const { w, h } = this.preCanvasData;
      let that = this;
      let canvas = document.querySelector('.pre_canvas');
      canvas.width = w;
      canvas.height = h;
      this.preCanvasData.pre_ctx = canvas.getContext('2d');
      this.preCanvasData.pre_ctx.clearRect(0, 0, w, h);
      this.preCanvasData.pre_ctx.drawImage(img, 0, 0, w, h);
      // 图片预览居中
      this.leftDefault();
      // 鼠标事件
      move(
        '.pre_canvas',
        function (x, y) {
          that.cropping(that.preCanvasData.pre_ctx.getImageData(x, y, w, h));
        },
        this
      );
    },
    // 裁剪
    cropping(img) {
      const { w, h } = this.croCanvasData;
      let canvas = document.querySelector('.cro_canvas');
      canvas.width = w;
      canvas.height = h;
      let cro_ctx = canvas.getContext('2d');
      cro_ctx.clearRect(0, 0, w, h);
      // 绘制图像
      cro_ctx.putImageData(img, 0, 0);
    },
    // 下载
    async upCropping() {
      let canvas = document.querySelector('.cro_canvas');
      let res = await fetch(canvas.toDataURL('image/png'));
      let blob = await res.blob();
      this.$emit('upCroppingBlob', blob);
    },
    // 预览居中处理
    leftDefault() {
      const { w, h, maxW } = this.preCanvasData;
      let canvas = document.querySelector('.pre_canvas');
      let x = 0;
      let y = 0;
      if (w > maxW && w > h) {
        x = (w - maxW) / 2;
        canvas.style.left = '-' + (w - maxW) / 2 + 'px';
      }
      if (w === maxW) {
        canvas.style.left = (250 - w) / 2 + 'px';
      }
      // 预览裁剪同步处理
      this.cropping(this.preCanvasData.pre_ctx.getImageData(x, y, w, h));
    }
  }
};
</script>
<style lang="scss" scoped>
.cropping {
  .cropping-box {
    height: 322px;
    display: flex;
    justify-content: space-around;
    .box-l {
      height: 250px;
      width: 250px;
      position: relative;
      overflow: hidden;
      border: 1px solid #ccc;
      .pre_canvas {
        cursor: move;
        position: absolute;
        top: 0;
        left: 0;
      }
    }
    .box-r {
      width: 184px;
      height: 184px;
      border-radius: 100%;
      border: 1px solid #ccc;
      overflow: hidden;
    }
  }
}
</style>

              

const move = (id = "", callback = () => {}, that = null) => {
  const { w, h, maxW, maxH } = that.preCanvasData;
  let flag = false;
  let dom = document.querySelector(id);
  dom.onmousedown = function (ev) {
    flag = true;
    let left = ev.offsetX;
    let pl = ev.target.parentNode.offsetLeft;
    let top = ev.offsetY;
    let pt = ev.target.parentNode.offsetTop;
    dom.onmousemove = function (ev) {
      // 获取鼠标在目标盒子上的X轴坐标
      let l =
        ev.clientX -
        (document.querySelector(".el-dialog").offsetLeft + pl) -
        left;
      // 获取鼠标在目标盒子上的Y轴坐标
      let t =
        ev.clientY -
        (document.querySelector(".el-dialog").offsetTop + pt) -
        top;
      if (flag) {
        if (w > h) {
          // 纵向滑动边界限制
          l = l >= 0 ? 0 : l <= "-" + (w - maxW) ? "-" + (w - maxW) : l;
          dom.style.left = l + "px";
          // 右侧裁剪滑动同步处理
          l = l > 0 ? "-" + l : Math.abs(l);
          // 纵向滑动时垂直方向锁定
          t = 0;
        } else if (h > w) {
          // 垂直方向滑动边界限制
          t = t >= 0 ? 0 : t <= "-" + (h - maxH) ? "-" + (h - maxH) : t;
          dom.style.top = t + "px";
          // 右侧裁剪滑动同步处理
          t = t > 0 ? "-" + t : Math.abs(t);
          // 垂直向滑动时纵向锁定
          l = 0;
        } else {
          // 禁止滑动
          l = 0;
          t = 0;
        }
        callback(l, t);
      }
    };
  };
  document.onmouseup = function () {
    flag = false;
  };
};
export default move;

效果图:

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值