js实现框选截屏功能
实现的思路大概就是,先将dom转化为canvas画布,再对canvas进行裁切,然后通过canvas api生成图片,这里用到了一个库
html2canvas
效果如图:

首先实现框选效果:
const mousedownEvent = (e) => {moveX = 0;moveY = 0;const [startX, startY] = [e.clientX, e.clientY];x = startX - viewer.getBoundingClientRect().left;y = startY - viewer.getBoundingClientRect().top;const divDom = document.createElement("div");divDom.id = 'screenshot';divDom.width = '1px';divDom.height = '1px';divDom.style.position = "absolute";divDom.style.top = y + "px";divDom.style.left = x + "px";const closeIcon = document.createElement("span");closeIcon.className = 'outline-close-icon';closeIcon.textContent = 'x';divDom.appendChild(closeIcon);closeIcon.addEventListener('click', () => {divDom.remove();});// document.body.appendChild(divDom)viewer.appendChild(divDom);const moveEvent = (e) => {moveX = e.clientX - startX;moveY = e.clientY - startY;if (moveX > 0) {divDom.style.width = moveX + 'px';} else {divDom.style.width = -moveX + 'px';divDom.style.left = e.clientX - viewer.getBoundingClientRect().left + 'px';}if (moveY > 0) {divDom.style.height = moveY + 'px';} else {divDom.style.height = -moveY + 'px';divDom.style.top = e.clientY - viewer.getBoundingClientRect().top + 'px';}};window.addEventListener("mousemove", moveEvent);window.addEventListener("mouseup", () => {window.removeEventListener("mousemove", moveEvent);window.removeEventListener("mousedown", mousedownEvent);document.querySelector("body").style.cursor = "default";});
};
window.addEventListener("mousedown", mousedownEvent);
全码:
const viewer = document.getElementById('viewer');
let canvas;
document.getElementById('screen-button').addEventListener('click', (e) => {// 创建一个canvas画布if (canvas) {canvas.remove();}canvas = document.createElement('canvas');canvas.setAttribute('id', 'bg_canvas');canvas.style.position = "absolute";canvas.style.zIndex = 2;canvas.style.left = 0;canvas.style.top = 0;canvas.style.width = '100%';canvas.style.height = '100%';viewer.appendChild(canvas);document.querySelector("body").style.cursor = "crosshair";let moveX;let moveY;let x;let y;const mousedownEvent = (e) => {moveX = 0;moveY = 0;const [startX, startY] = [e.clientX, e.clientY];x = startX - viewer.getBoundingClientRect().left;y = startY - viewer.getBoundingClientRect().top;const divDom = document.createElement("div");divDom.id = 'screenshot';divDom.width = '1px';divDom.height = '1px';divDom.style.position = "absolute";divDom.style.top = y + "px";divDom.style.left = x + "px";const closeIcon = document.createElement("span");closeIcon.className = 'outline-close-icon';closeIcon.textContent = 'x';divDom.appendChild(closeIcon);closeIcon.addEventListener('click', () => {divDom.remove();});// document.body.appendChild(divDom)viewer.appendChild(divDom);const moveEvent = (e) => {moveX = e.clientX - startX;moveY = e.clientY - startY;if (moveX > 0) {divDom.style.width = moveX + 'px';} else {divDom.style.width = -moveX + 'px';divDom.style.left = e.clientX - viewer.getBoundingClientRect().left + 'px';}if (moveY > 0) {divDom.style.height = moveY + 'px';} else {divDom.style.height = -moveY + 'px';divDom.style.top = e.clientY - viewer.getBoundingClientRect().top + 'px';}};window.addEventListener("mousemove", moveEvent);window.addEventListener("mouseup", () => {window.removeEventListener("mousemove", moveEvent);window.removeEventListener("mousedown", mousedownEvent);document.querySelector("body").style.cursor = "default";if (!moveX) {return;}// 把body转成canvashtml2canvas(viewer, {scale: 1,// allowTaint: true,useCORS: true //跨域使用}).then(canvas2 => {let capture_x, capture_y;let width = moveX;let height = moveY;if (width > 0) {//从左往右画capture_x = startX - canvas.getBoundingClientRect().left + 1;} else {//从右往左画capture_x = x + width + 1;}if (height > 0) {//从上往下画capture_y = y + 1;} else {//从下往上画capture_y = y + height + 1;}printClip(canvas2, capture_x, capture_y, Math.abs(width), Math.abs(height));moveX = 0;canvas.remove();});});};window.addEventListener("mousedown", mousedownEvent);
});/*** 打印截取区域* @param canvas 截取的canvas* @param capture_x 截取的起点x* @param capture_y 截取的起点y* @param capture_width 截取的起点宽* @param capture_height 截取的起点高*/
async function printClip(canvas2, capture_x, capture_y, capture_width, capture_height) {// 创建一个用于截取的canvasconst clipCanvas = document.createElement('canvas');clipCanvas.width = capture_width;clipCanvas.height = capture_height;// 截取clipCanvas.getContext('2d').drawImage(canvas2, capture_x, capture_y, capture_width, capture_height, 0, 0, capture_width, capture_height);const clipImgBase64 = clipCanvas.toDataURL();// console.log('clipImgBase64->', clipImgBase64);// console.log('clipImgBase64->', clipImgBase64.replace(/^data:image\/\w+;base64,/, ""));const obj = {// file: new File([this.blob],'main.audio',{ type: 'audio/mp3' })file: new File([base64ToBlob(clipImgBase64.replace(/^data:image\/\w+;base64,/, ""), 'image/png')], 'test.png', { type: 'image/png' })};// 生成图片// var clipImg = new Image()// clipImg.src = clipImgBase64downloadIamge(clipImgBase64)
}/*** 下载保存图片* @param imgUrl 图片地址*/
function downloadIamge(imgUrl) {// 生成一个a元素const a = document.createElement('a');// 创建一个单击事件const event = new MouseEvent('click');// 生成文件名称const timestamp = new Date().getTime();const name = imgUrl.substring(22, 30) + timestamp + '.png';a.download = name;// 将生成的URL设置为a.href属性a.href = imgUrl;// 触发a的单击事件 开始下载a.dispatchEvent(event);
}// 将Base64编码转换为Blob对象
function base64ToBlob(base64, type) {const byteCharacters = atob(base64);const byteArrays = [];for (let offset = 0; offset < byteCharacters.length; offset += 512) {let slice = byteCharacters.slice(offset, offset + 512);let byteNumbers = new Array(slice.length);for (let i = 0; i < slice.length; i++) {byteNumbers[i] = slice.charCodeAt(i);}let byteArray = new Uint8Array(byteNumbers);byteArrays.push(byteArray);}let blob = new Blob(byteArrays, { type: type });return blob;
}
坑:
- 如果生成图片样式有问题 html就用内联样式
- 当截图片的时候如果不识别 就将图片url转化为base64
相关文章:
js实现框选截屏功能
实现的思路大概就是,先将dom转化为canvas画布,再对canvas进行裁切,然后通过canvas api生成图片,这里用到了一个库html2canvas 效果如图: 首先实现框选效果: const mousedownEvent (e) > {moveX 0;mo…...
Manjaro Linux 连接公司的 VPN 网络
注意:如果你公司的 VPN 网络是在苹果下使用的,本文可能不适用(苹果系统不支持 PPTP)。 用 Linux 和用 Windows/macOS 不一样,它真的需要用户操心很多东西。比如怎么连接公司的 VPN 网络…… 我是折腾了挺久࿰…...
Ama no Jaku
登录—专业IT笔试面试备考平台_牛客网 题目大意:有一个n*n且仅由0和1构成的矩阵,每次操作可以将一整行或一整列的所有数取反,问能否使所有行中构成的最小数>所有列中构成的最大数 1<n<2000 思路:首先,如果…...
视频基础知识
1.视频比特率 视频的比特率是指传输过程中单位时间传输的数据量。可以理解为视频的编码采样率。单位是kbps,即每秒千比特。视频比特率是决定视频清晰度的一个重要指标。比特率越高,视频越清晰,但数据量也会越大。比如一部100分钟的电影&#…...
安全渗透初级知识总结
Day1: xss详解:web攻防之XSS攻击详解——XSS简介与类型 - 知乎 (zhihu.com) Cookie:身份验证 网页元素属性: id: class:样式名称 console.log(div_class);----打印标签 tabindex"0"---这是…...
rocketmq客户端本地日志文件过大调整配置(导致pod缓存cache过高)
现象 在使用rocketmq时,发现本地项目中文件越来越大,查找发现在/home/root/logs/rocketmqlog目录下存在大量rocketmq_client.log日志文件。 配置调整 开启slf4j日志模式,在项目启动项中增加-Drocketmq.client.logUseSlf4jtrue因为配置使用的…...
Unity进阶-ui框架学习笔记
文章目录 Unity进阶-ui框架学习笔记 Unity进阶-ui框架学习笔记 笔记来源课程:https://study.163.com/course/courseMain.htm?courseId1212756805&_trace_c_p_k2_8c8d7393c43b400d89ae94ab037586fc 最上面的管理层(canvas) using System…...
Django实现接口自动化平台(十四)测试用例模块Testcases序列化器及视图【持续更新中】
相关文章: Django实现接口自动化平台(十三)接口模块Interfaces序列化器及视图【持续更新中】_做测试的喵酱的博客-CSDN博客 本章是项目的一个分解,查看本章内容时,要结合整体项目代码来看: python django…...
如何高效实现文件传输:小文件采用零拷贝、大文件采用异步io+直接io
一般会如何实现文件传输? 服务器提供文件传输功能,需要将磁盘上的文件读取出来,通过网络协议发送到客户端。如果需要你自己编码实现这个文件传输功能,你会怎么实现呢? 通常,你会选择最直接的方法…...
Docker运行MySQL5.7
步骤如下: 1.获取镜像: docker pull mysql:5.7 2.创建挂载目录: mkdir /home/mydata/data mkdir /home/mydata/log mkdir /home/mydata/conf 3.先启动docker把配置文件拷贝出来: docker run -it --name temp mysql:5.7 /bi…...
-jar和 javaagent命令冲突吗?
当使用 -jar 命令运行 Java 应用程序时,Java 虚拟机 (JVM) 会忽略任何设置的 -javaagent 命令。这是因为 -jar 命令会覆盖其他命令行选项,包括 -javaagent。 这是因为 -jar 命令是用于运行打包为 JAR 文件的 Java 应用程序的快捷方式。它会忽略其他命令…...
LLC和MAC子层的应用
计算机局域网标准IEEE802 由于局域网只是一个计算机通信网,而且局域网不存在路由选择问题,因此它不需要网络层,而只有最低的两个层次。然而局域网的种类繁多,其媒体接入控制的方法也各不相同。 为了使局域网中的数据链路层不致过…...
【MySQL】之复合查询
【MySQL】之复合查询 基本查询多表查询笛卡尔积自连接子查询单行子查询多行子查询多列子查询在from子句中使用子查询 合并查询小练习 基本查询 查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J按照部门号升序而雇员的工资降序排序使用…...
Vue系列第五篇:Vue2(Element UI) + Go(gin框架) + nginx开发登录页面及其校验登录功能
本篇使用Vue2开发前端,Go语言开发服务端,使用nginx代理部署实现登录页面及其校验功能。 目录 1.部署结构 2.Vue2前端 2.1代码结构 2.1源码 3.Go后台服务 3.2代码结构 3.2 源码 3.3单测效果 4.nginx 5.运行效果 6.问题总结 1.部署结构 2.Vue2…...
u盘里的数据丢失怎么恢复 u盘数据丢失怎么恢复
在使用U盘的时候不知道大家有没有经历过数据丢失或者U盘提示格式化的情况呢?U盘使用久了就会遇到各种各样的问题,而关于U盘数据丢失,大家又知道多少呢?当数据丢失了,我们应该怎样恢复数据?这个问题困扰了很…...
Mysql-约束
约束 概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。 目的:保证数据库中数据的正确、有效性和完整性。 分类: 约束描述关键字非空约束限制该字段的数据不能为nullNOT NULL唯一约束保证该字段的所有数据都是唯一…...
数据结构问答7
1. 图的定义和相关术语 答: 定义:图是由顶点集V和边集E组成,其中V为有限非空集。 相关术语:n个顶点,e条边,G=(V,E) ① 邻接点和端点:无向图中,若存在一条边(i, j),则称i,j为该边的端点,且它们互为邻接点;在有向图中,若存在一条边<i, j>,则称i,j分别为…...
[Spark] 大纲
1、Spark任务提交流程 2、SparkSQL执行流程 2.1 RBO,基于规则的优化 2.2 CBO,基于成本的优化 3、Spark性能调优 3.1 固定资源申请和动态资源分配 3.2 数据倾斜常见解决方法 3.3 小文件优化 4、Spark 3.0 4.1 动态分区裁剪(Dynamic Partition Pr…...
【NLP】使用 Keras 保存和加载深度学习模型
一、说明 训练深度学习模型是一个耗时的过程。您可以在训练期间和训练后保存模型进度。因此,您可以从上次中断的地方继续训练模型,并克服漫长的训练挑战。 在这篇博文中,我们将介绍如何保存模型并使用 Keras 逐步加载它。我们还将探索模型检查…...
视频标注是什么?和图像数据标注的区别?
视频数据标注是对视频剪辑进行标注的过程。进行标注后的视频数据将作为训练数据集用于训练深度学习和机器学习模型。这些预先训练的神经网络之后会被用于计算机视觉领域。 自动化视频标注对训练AI模型有哪些优势 与图像数据标注类似,视频标注是教计算机识别对象…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...
