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模型有哪些优势 与图像数据标注类似,视频标注是教计算机识别对象…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
