原生JS实现图片裁剪功能(fixed布局)

news2024/9/24 19:23:23

功能介绍:图片通过原生input上传,使用canvas进行图片裁剪。 裁剪框限制不允许超出图片范围,图片限制了最大宽高(自行修改要的尺寸),点击确认获取新的base64图片数据,大部分需求都是弹窗进行处理,这里用到的是fixed布局,将盒子浮动起来,导致判断,取值有变化

在这里插入图片描述

<!DOCTYPE HTML>
<html>

<head lang="en">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>图片裁剪</title>
</head>

<body>
  <input id="npt" type="file">
  <div id="box">
    <img style="position:absolute;top:0px;left:0px;opacity: 0.3;" src="" id="img1" />
    <img style="position:absolute;top:0px;left:0px;clip: rect(50px, 250px, 250px, 50px);" src="" id="img2" />
    <!--第三层需用绝对定位浮在上面-->
    <div id="dragDiv" style="position: absolute;width: 200px;height: 200px;border: 1px solid #fff;top:50px;left:50px;">
      <div class="Divmin up-left"></div>
      <div class="Divmin up"></div>
      <div class="Divmin up-right"></div>
      <div class="Divmin right"></div>
      <div class="Divmin right-down"></div>
      <div class="Divmin down"></div>
      <div class="Divmin left-down"></div>
      <div class="Divmin left"></div>
      <div class="Divmin-btn" style="right: 68px;background-color: #2d87f5;" id="confirmBtn">确定</div>
      <div class="Divmin-btn" style="right: 0px;background-color: #f5a52d;">取消</div>
    </div>
    <div style="position: absolute; right: 0;">
      <img src="" id="later" alt="">
    </div>

  </div>

</body>

</html>

<style>
  body {}

  #box {
    width: 1200px;
    height: 600px;
    background: #333;
    position: fixed;
    top: 50px;
    left: 50px;
  }

  .Divmin-btn {
    bottom: -40px;
    width: 60px;
    height: 30px;
    line-height: 30px;
    color: white;
    font-size: 12px;
    text-align: center;
    display: inline-block;
    position: absolute;
    border-radius: 3px 3px 3px 3px;
  }

  .Divmin-btn:hover {
    background-color: rgba(60, 103, 222, 0.6);
    color: #efeeee;
  }

  .Divmin-btn:active {
    background-color: rgba(69, 94, 167, 0.6);
    color: #efeeee;
  }

  .Divmin {
    position: absolute;
    width: 8px;
    height: 8px;
    background: #fff;
  }

  .up-left {
    margin-top: -4px;
    margin-left: -4px;
    cursor: nw-resize;
  }

  .up {
    left: 50%;
    /*父元素盒子dragDiv宽度的一半,注意要有绝对定位*/
    margin-left: -4px;
    top: -4px;
    cursor: n-resize;
  }

  .up-right {
    top: -4px;
    right: -4px;
    cursor: ne-resize;
  }

  .right {
    top: 50%;
    margin-top: -4px;
    right: -4px;
    cursor: e-resize;
  }

  .right-down {
    right: -4px;
    bottom: -4px;
    cursor: se-resize;
  }

  .down {
    bottom: -4px;
    left: 50%;
    margin-left: -4px;
    cursor: s-resize;
  }

  .left-down {
    left: -4px;
    bottom: -4px;
    cursor: sw-resize;
  }

  .left {
    left: -4px;
    top: 50%;
    margin-top: -4px;
    cursor: w-resize;
  }

  #img1,
  #img2 {
    max-width: 600px;
    max-height: 600px;
    -webkit-user-drag: none;
  }
</style>

<script type="text/javascript">
  //禁止图片被选中
  document.onselectstart = new Function('event.returnValue = false;');
  let confirmBtn = document.getElementById('confirmBtn')
  confirmBtn.addEventListener('click', () => {
    drawRect();
  })


  // 获取图片base64数据
  let npt = document.getElementById("npt");
  npt.onchange = function () {
    let reader = new FileReader();
    reader.readAsDataURL(npt.files[0]);
    reader.onloadend = function (e) {
      img1.src = e.target.result;
      img2.src = e.target.result;
      // console.log(e.target.result);// 图片的base64数据
      getImage(e.target.result)
    };
  }

  let canvas = document.createElement("canvas");
  let ctx = canvas.getContext('2d');

  // 创建图片
  let getImage = function (b64) {
    // 创建图片对象
    let image = new Image();
    image.src = `${b64}`;
    image.onload = function () {
      // 获取原图宽高
      let height = img1.offsetHeight;
      let width = img1.offsetWidth;
      //设置canvas大小与原图宽高一致
      canvas.height = height;
      canvas.width = width;
      // 在canvas绘制图片
      ctx.drawImage(this, 0, 0, width, height);
      // 截图:
      // drawRect();

      // 图片上传后设置裁剪框与图片大小一致
      dragDiv.style.height = img1.offsetHeight + 'px'
      dragDiv.style.width = img1.offsetWidth + 'px'
      dragDiv.style.top = 0 + 'px';
      dragDiv.style.left = 0 + 'px';
      setChoice();
    }
  };

  // 绘制截图矩阵
  let drawRect = function () {
    let top = dragDiv.offsetTop;
    let right = dragDiv.offsetLeft + dragDiv.offsetWidth;
    let bottom = dragDiv.offsetTop + dragDiv.offsetHeight;
    let left = dragDiv.offsetLeft;

    // 截图宽度
    let w = right - left;
    // 截图高度
    let h = bottom - top;
    // 获取截图区域内容,截图区域的像素点矩阵
    let cutImage = ctx.getImageData(left, top, w, h);
    // 裁剪后的base64数据
    let newImage = createNewCanvas(cutImage, w, h);
    later.src = newImage;
    // console.log(newImage);// 裁剪后的base64数据
  };

  var createNewCanvas = function (content, width, height) {
    var nCanvas = document.createElement('canvas');
    var nCtx = nCanvas.getContext('2d');
    nCanvas.width = width;
    nCanvas.height = height;
    nCtx.putImageData(content, 0, 0);// 将画布上指定矩形的像素数据,通过 putImageData() 方法将图像数据放回画布
    return nCanvas.toDataURL('image/png');
  }

  //获取id的函数
  function $(id) {
    if (id.indexOf(".") == 0) {
      let className = id.substring(1, id.length);
      let els = document.getElementsByClassName(className);
      return els[0];
    }
    return document.getElementById(id);
  }

  let dragDiv = $('dragDiv');
  let box = $('box')
  let img1 = $('img1')
  let rightDiv = $('.right');
  let isDraging = false;
  let contact = "";//表示被按下的触点
  //鼠标按下时
  $('.right').onmousedown = function () {
    isDraging = true;
    contact = "right";
  }
  $('.left').onmousedown = function () {
    isDraging = true;
    contact = "left";
  }
  $('.down').onmousedown = function () {
    isDraging = true;
    contact = "down";
  }
  $('.up').onmousedown = function () {
    isDraging = true;
    contact = "up";
  }
  $('.up-right').onmousedown = function () {
    isDraging = true;
    contact = "up-right";
  }
  $('.right-down').onmousedown = function () {
    isDraging = true;
    contact = "down-right";
  }
  $('.up-left').onmousedown = function () {
    isDraging = true;
    contact = "up-left";
  }
  $('.left-down').onmousedown = function () {
    isDraging = true;
    contact = "down-left";
  }

  //鼠标松开时
  window.onmouseup = function () {
    isDraging = false;
  }

  //鼠标移动时
  window.onmousemove = function (e) {
    var e = e || window.event;
    if (isDraging == true) {
      switch (contact) {
        case "up":
          upMove(e);
          break;
        case "right":
          rightMove(e);
          break;
        case "down":
          downMove(e);
          break;
        case "left":
          leftMove(e);
          break;
        case "up-right":
          upMove(e);
          rightMove(e);
          break;
        case "down-right":
          downMove(e);
          rightMove(e);
          break;
        case "down-left":
          downMove(e);
          leftMove(e);
          break;
        case "up-left":
          upMove(e);
          leftMove(e);
          break;
      }
    }
  }

  //up移动
  function upMove(e) {

    let boxTop = box.getBoundingClientRect().top //父盒子距浏览器顶部距离
    let y = e.clientY  // 鼠标所在位置
    let dragDivRect = dragDiv.getBoundingClientRect()
    //上限制:y 不小于 父盒子距顶部距离
    //下限制: y 不大于 父盒子距顶部距离 + 编辑盒子上边距 + 编辑盒子高度 - 2
    let maxHeight = boxTop + dragDiv.offsetTop + dragDivRect.height - 2
    if (y <= boxTop || y >= maxHeight) return
    //当前编辑框上边框距父盒子顶部距离 = 当前鼠标位置 - 父盒子外边距
    let top = y - boxTop
    let addHeight = dragDivRect.top - y
    let height = dragDivRect.height + addHeight - 2
    dragDiv.style.height = height + 'px';//选取框变化后的宽度
    dragDiv.style.top = top + 'px';//相当于变化后左上角的纵坐标,鼠标向上移纵坐标减小,下移增大
    setChoice();
  }

  //right移动
  function rightMove(e) {
    //限制最大宽度 :  当鼠标位置 >= 父级盒子左边距 + 图片总宽度
    let maxWidth = box.getBoundingClientRect().left + img1.getBoundingClientRect().width
    if (e.clientX >= maxWidth) return

    //盒子的宽度 = 鼠标所在位置 - 盒子左边距
    let width = e.clientX - dragDiv.getBoundingClientRect().left
    dragDiv.style.width = width + 'px';//选取框变化后的宽度
    setChoice();
  }

  //down移动
  function downMove(e) {

    let boxTop = box.getBoundingClientRect().top
    //下限制: 鼠标位置 >= 图片高度 + 盒子顶部距离
    if (e.clientY >= img1.getBoundingClientRect().height + boxTop) return
    // 高度 = 鼠标所在位置 - 盒子距顶部距离 - 编辑盒子距父级外边距
    let newHeight = e.clientY - boxTop - dragDiv.offsetTop
    dragDiv.style.height = newHeight + 'px';
    setChoice();

  }

  //left移动
  function leftMove(e) {
    //父盒子距离浏览器左侧宽度
    let boxLeft = box.getBoundingClientRect().left
    //当前鼠标位置 - 盒子距离浏览器左边距  = left
    let newLeft = e.clientX - boxLeft

    //当前增加的宽度 = 盒子的宽度 +
    let dragDivRect = dragDiv.getBoundingClientRect()
    let addWidth = dragDivRect.left - e.clientX;//增加的宽度等于距离屏幕左边的距离减去鼠标位置横坐标
    let width = dragDivRect.width + addWidth - 2
    // 左限制 = 当前鼠标位置 <= 父盒子左边距
    // 右限制 = 当前鼠标位置 >= 父盒子左边距+ 编辑盒子宽 + 编辑盒子距父级盒子左边距
    let maxWidth = boxLeft + dragDivRect.width + dragDiv.offsetLeft
    if (newLeft <= 1 || (e.clientX >= maxWidth)) return
    dragDiv.style.width = width + 'px';
    dragDiv.style.left = newLeft + 'px';
    setChoice();
  }

  //设置选取框图片区域明亮显示
  function setChoice() {
    let top = dragDiv.offsetTop;
    let right = dragDiv.offsetLeft + dragDiv.offsetWidth;
    let bottom = dragDiv.offsetTop + dragDiv.offsetHeight;
    let left = dragDiv.offsetLeft;
    $('img2').style.clip = "rect(" + top + "px," + right + "px," + bottom + "px," + left + "px)";
  }
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/689339.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

office word 2007

office word 2007 指数怎么写的

反AI来了…尼康的Natural Intelligence

a mutant_umbrella tree shaped like a nuclear bomb explosion,a photo-realism photograph, 4k, ultra realistic VS a mutant_umbrella tree shaped like a nuclear bomb explosion 尼康发起了一次名为&#xff1a;Natural Intelligence &#xff0c;“不要放弃现实世界”的…

机器学习之K-means聚类算法

目录 K-means聚类算法 算法流程 优点 缺点 随机点聚类 人脸聚类 旋转物体聚类 K-means聚类算法 K-means聚类算法是一种无监督的学习方法&#xff0c;通过对样本数据进行分组来发现数据内在的结构。K-means的基本思想是将n个实例分成k个簇&#xff0c;使得同一簇内数据相…

Java性能权威指南-总结18

Java性能权威指南-总结18 线程与同步的性能线程同步避免同步伪共享 线程与同步的性能 线程同步 避免同步 如果同步可以完全避免&#xff0c;那加锁的损失就不会影响应用的性能。 有两种一般性的方式可以应对。其一是在每个线程中使用不同的对象&#xff0c;这样访问对象时就…

Selenium教程__界面的刷新、后退、前进操作(4)

本文将介绍如何使用Selenium来实现界面的刷新、后退和前进操作&#xff0c;以便于测试、开发人员能够更好地控制和管理用户界面的交互行为。 通过学习本文内容&#xff0c;您将能够掌握Selenium中相关API的使用方法&#xff0c;并能够灵活地应用到您的项目中&#xff0c;从而提…

机器学习-搭建轻量级机器人模型

在自己的机器上部署一个机器人简直太酷啦&#xff0c;因为模型数据缘故&#xff0c;可能有时候回复会有一点点怪&#xff0c;不过不影响我们探索机器模型的学习&#xff0c;搭建安装完毕&#xff0c;大家就可自行学习源码啦。 这是启动后台的图片。 需要安装环境&#xff1a;p…

vue监听鼠标与键盘事件

mounted () {window.addEventListener(mousedown, this.handleMousedown)//监听鼠标按下window.addEventListener(mouseup, this.handleMouseup)//监听鼠标抬起window.addEventListener(keydown, this.handlekeydown)//监听键盘按下},methods: {// 鼠标按下事件handleMousedown…

GDAL 标记图像连接区域

文章目录 一、简介1.1原始算法1.2修改标记算法二、实现代码三、实现效果参考资料一、简介 1.1原始算法 标记图像连接区域的算法有很多,这里主要实现了一种基于扫描线的改进算法(Suzuki算法),原始算法使用了一种决策树策略,即对二进制图像b(x,y)进行重复传递,在前向和后向…

chatgpt赋能python:Python要点:从入门到精通

Python要点&#xff1a;从入门到精通 Python是一门高级编程语言&#xff0c;是一种解释型、面向对象、动态数据类型的语言。它的设计思想是“代码易读易写”&#xff0c;在数据科学、人工智能、自动化测试、Web开发等领域广泛应用。本文将从入门到精通的角度来介绍Python的要点…

模拟电路系列分享-电阻的选则

目录 概要 整体架构流程 技术名词解释 技术细节 1.阻值的选择 2.不能太小的原因 3.不能太大的原因 4.E系列选择 小结 概要 提示&#xff1a;这里可以添加技术概要 例如&#xff1a; 电阻(Resistor]是我们的老朋友了&#xff0c;从初中就认识。但到目前为止&#xff0c;我们却…

chatgpt赋能python:Python获取电脑IP:教你简单又快速的实现方式

Python获取电脑IP&#xff1a;教你简单又快速的实现方式 如果你是一名网络工程师或者Web开发者&#xff0c;那么获得电脑IP地址对你来说是一个常见的任务。而Python作为一种流行的脚本语言&#xff0c;也提供了多种方法来获取电脑的IP地址。下面我们将介绍三种Python获取电脑I…

深度生成模型系统的实现原理有哪些?未来的挑战是什么?

由于计算机性能的快速提升, 学习可观测样本的概率密度并随机生成新样本的生成模型成为热点。相比于需要学习条件概率分布的判别模型生成模型的训练难度大、模型结构复杂, 但除了能够生成新样本外, 生成模型在图像重构、缺失数据填充、密度估计、风格迁移和半监督学习等应用领域…

【因果图法和决策表】某软件的一个模块的需求规格说明书中描述:(1)年薪制员工:严重过失,扣年终风险金的4%;过失,扣年终风险金的2%。(2)非年薪制员工:严重过失,扣当月薪资的8%;过失,扣当月薪

题目&#xff1a; 某软件的一个模块的需求规格说明书中描述&#xff1a; &#xff08;1&#xff09;年薪制员工&#xff1a;严重过失&#xff0c;扣年终风险金的4%&#xff1b;过失&#xff0c;扣年终风险金的2%。 &#xff08;2&#xff09;非年薪制员工&#xff1a;严重过…

14.RocketMQ之高可用性机制

1.2 高可用性机制 RocketMQ分布式集群是通过Master和Slave的配合达到高可用性的。 Master和Slave的区别&#xff1a;在Broker的配置文件中&#xff0c;参数 brokerId的值为0表明这个Broker是Master&#xff0c;大于0表明这个Broker是 Slave&#xff0c;同时brokerRole参数也会说…

保证水库大坝安全需要做好哪方面的监测

水库安全监测是保证水库大坝安全的重要手段是确保水库大坝安全运行的基础也是做好水库安全管理的重要技术保障。根据《水库大坝安全管理条例》《水库大坝安全监测技术规范》等有关规定&#xff0c;对坝体变形、渗透、应力应变等进行监测&#xff0c;以掌握坝体、坝基和库岸的运…

css增加高斯模糊的效果

实现效果 关键代码 backdrop-filter 当你创造一个元素加上这个属性后&#xff0c;会使得这个元素后面的区域添加效果&#xff08;如模糊或颜色偏移&#xff09; background: rgba(0,0,0,.5);backdrop-filter: blur(10px);

MFC开发第二天 Windows计算器的开发,常用消息解析与处理

文章目录 相关概念陈述一、初始API汇总消息汇总 二、Windows计算器的开发三、常见的消息解析与处理附录 相关概念陈述 INT PTR是一个指向整数类型数据的指针。PTR是指针的缩写&#xff0c;INT是表示整数类型。因此&#xff0c;INT PTR表示指向整数类型的指针。 1、对话框弹出…

Ambari自动部署hadoop

1、Ambari介绍 Apache Ambari项目旨在通过开发用于配置&#xff0c;管理和监控Apache Hadoop集群的软件来简化Hadoop管理. Ambari提供了一个由RESTful API支持的直观&#xff0c;易用的Hadoop管理Web Ul。 Ambari使系统管理员能够: 提供Hadoop集群 Ambari提供了跨任意数量的主…

戴尔游匣笔记本Dell G16 7630原厂Win11系统重装,安装原装出厂OEM预装系统镜像,恢复出厂状态

DELL戴尔游匣笔记本电脑&#xff0c;Dell G16 7630原厂Windows11系统原装OEM预装系统镜像&#xff0c;恢复出厂状态 系统自带所有驱动、出厂主题壁纸LOGO、Office办公软件、戴尔外星人控制中心等预装程序 链接&#xff1a;https://pan.baidu.com/s/10s7dFd1yHhUsgkKVS-No2A?…

数据库管理-第八十五期 19c OCM之路-准备与环境篇(20230626)

数据库管理 2023-06-26 第八十五期 19c OCM之路-准备与环境篇1 计划2 考试环境3 技巧和注意事项总结 第八十五期 19c OCM之路-准备与环境篇 从去年就有消息传出&#xff0c;OCM将从12c升级到19c&#xff0c;今年12c OCM停考&#xff0c;从业内大佬和OU处了解到其实今年3月30日…