原生JS实现图片裁剪功能

功能介绍:图片通过原生input上传,使用canvas进行图片裁剪。 裁剪框限制不允许超出图片范围,图片限制了最大宽高(自行修改要的尺寸),点击确认获取新的base64图片数据

注:fixed布局不适用该方案,若是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: absolute;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: 300px;}
</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);}//获取元素相对于屏幕左边及上边的距离,利用offsetLeftfunction getPosition(el) {let left = el.offsetLeft;let top = el.offsetTop;let parent = el.offsetParent;while (parent != null) {left += parent.offsetLeft;top += parent.offsetTop;parent = parent.offsetParent;}return { "left": left, "top": top };}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 y = e.clientY;//鼠标位置的纵坐标let heightBefore = dragDiv.offsetHeight - 2;//选取框变化前的高度let addHeight = getPosition(dragDiv).top - y;//增加的高度let height = heightBefore + addHeightlet top = dragDiv.offsetTop - addHeightif (top <= 1 || height <= 1) returndragDiv.style.height = height + 'px';//选取框变化后的宽度dragDiv.style.top = top + 'px';//相当于变化后左上角的纵坐标,鼠标向上移纵坐标减小,下移增大setChoice();}//right移动function rightMove(e) {let allWidth = img1.offsetWidth + box.offsetLeftlet x = e.clientX;//鼠标位置的横坐标let widthBefore = dragDiv.offsetWidth - 2;//选取框变化前的宽度//let widthBefore = dragDiv.clientWidth;if (x >= allWidth) returnlet addWidth = x - getPosition(dragDiv).left - widthBefore;//鼠标移动后选取框增加的宽度dragDiv.style.width = widthBefore + addWidth + 'px';//选取框变化后的宽度setChoice();}//down移动function downMove(e) {let heightBefore = dragDiv.offsetHeight - 2;let bottom = box.offsetTop + img1.offsetHeightlet addHeight = e.clientY - getPosition(dragDiv).top - dragDiv.offsetHeight;if (e.clientY >= bottom) returnlet height = heightBefore + addHeightdragDiv.style.height = heightBefore + addHeight + 'px';setChoice();}//left移动function leftMove(e) {let widthBefore = dragDiv.offsetWidth - 2;let addWidth = getPosition(dragDiv).left - e.clientX;//增加的宽度等于距离屏幕左边的距离减去鼠标位置横坐标let width = widthBefore + addWidthlet left = dragDiv.offsetLeft - addWidthif (left <= 1 || width <= 1) returndragDiv.style.width = width + 'px';dragDiv.style.left = left + '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.hqwc.cn/news/3808.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JDK8新特性-下部

文章目录 一、Stream结果收集1.1 结果收集到集合中1.2 结果集收集到数组中1.3 对流中数据做聚合运算1.4 对流中数据做分组操作1.5 对流中的数据做分区操作1.6 对流中的数据做拼接 二、并行的Stream流2.1 串行的Stream流2.2 并行流2.2.1获取并行流2.2.2 并行流操作 2.3 串行流与…

arcgis js 通过某一个经纬度 定位报错,并且图标变得很大【已解决】

报错 svg.js:42 Error: attribute transform: Expected number, “…0000,0.02102085,NaN,NaN)”. svg.js:49 Error: attribute x: Expected length, “NaN”. svg.js:49 Error: attribute y: Expected length, “NaN”. 图标特别大&#xff0c;也看不到地图 分析 这个方法中…

vhost-net-原理-初始化流程-数据传输流程-vhost-net后端

文章目录 1.vhost net2.vhost-net的初始化流程vhost net设置vhost dev设置vhost vring设置 3.数据收发流程分析3.1 数据发送3.2 数据接收 4ioventfd和irqfd的通知机制4.1ioeventfdqemu侧kvm侧总体效果 4.2irqfdqemu侧kvm侧总体效果 参考&#xff1a; 1.vhost net 传统的virtio…

linux eventfd事件通知 比信号量更好用

专栏内容&#xff1a;linux下并发编程个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e; 目录 前言 概述 原理简介 使用场景 接口说明 头文件 参数说明 代码演示 默认参数 …

探讨绿色照明与智能照明节能控制系统应用

张心志 安科瑞电气股份有限公司 上海嘉定 201801 【摘 要】随着社会经济的不断发展&#xff0c;人们对生活质量、环境品质越发重视。积极推广绿色智能照明&#xff0c;提高城市照明质量&#xff0c;对于改善人们居住环境意义重大。文章简要介绍了绿色照 明的基本要求、室内智…

Excel 经常复制粘贴失效,复制表格粘贴不了无反应,怎么解决?

环境&#xff1a; Win10 专业版 Excel2021 L盾加密客户端 wps2021 问题描述&#xff1a; 之前正常的&#xff0c;excel2016和2021 经常复制表格粘贴不了无反应每隔10几分钟随机出现&#xff0c;在表格外面复制粘贴没有问题&#xff0c;把外面东西&#xff0c;粘贴进表格里…

UE5 Stride Warping Orientation Warping功能学习

在UE5的 Lyra Demo中&#xff0c;运用到了各类动画Warping&#xff08;动画扭曲&#xff09;技术&#xff0c;通过各类Warping节点在动画蓝图中的合理组织&#xff0c;可以有效的解决运动滑步问题&#xff0c;并为动画增添更多细节。 本文主要基于Animation Warping插件讲一下…

SQL中的——左连接(Left join)、右连接(Right join)、内连接(Inner join)

前言 最近有一个开发需求&#xff0c;需要实现一个复杂年度报表&#xff0c;前后端都是博主开发&#xff0c;这里的业务逻辑比较复杂&#xff0c;也很锻炼sql能力&#xff0c;这里博主也将表的内外连接做了一个整理分享给大家 一、概念 首先还是介绍一下这三个的定义 1.Lef…

PHP 基础知识

目录 PHP基础 2 PHP代码标记 2 PHP注释 2 PHP语句分隔符 2 PHP变量 3 常量 3 数据类型 4 流程控制 6 文件 7 函数 9 闭包 11 常用系统函数 12 错误处理 13 错误显示设置 15 字符串类型 17 字符串相关函数 19 数组 21 遍历数组 22 数组的相关函数 25 PHP基础 PHP是一种运行在服务…

在虚幻引擎中创建大气的HIMIL电影作品

今天瑞云渲染小编给大家带来了关于电影制片人Tiziano Fioriti展示了《H I M I L》项目背后的工作流程&#xff0c;解释了人工智能是如何用于细节的&#xff0c;并谈到了设置火光的问题。 介绍 大家好&#xff0c;我叫Tiziano Fioriti&#xff0c;是来自意大利的自由电影制作人…

我们来谈谈websocket

"你一无所有地闯荡。" 一、初始WebSocket (1) 什么是websocket WebSocket是一种在单个TCP连接上进行全双工通信的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在WebSocket API中&#xff0c;浏览器和…

(动态规划) 673. 最长递增子序列的个数 ——【Leetcode每日一题】

❓ 673. 最长递增子序列的个数 难度&#xff1a;中等 给定一个未排序的整数数组 nums &#xff0c; 返回最长递增子序列的个数 。 注意 这个数列必须是 严格 递增的。 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列&#xff0c;分别是 [1, 3, 4, 7] 和[1,…