当前位置: 首页 > news >正文

js函数预览图片:支持鼠标和手势拖拽缩放

对之前的方式改进:原生js实现图片预览控件,支持丝滑拖拽,滚轮放缩,放缩聚焦_js图片预览-CSDN博客

/*** 图片预览函数,调用后自动预览图片* @param {图片地址} imgurl*/
function openImagePreview(imgurl) {if (!imgurl) return;const max = 30;//放缩原图倍数const scale = 0.1;//滚轮一下缩放的变化比例 越大放缩越快const box = document.createElement("div");box.style.cssText = "position: fixed;top:0px;left:0px;z-index: 10000;background-color: rgba(0,0, 0, 0.3);width:100%;height:100%;overflow: hidden;cursor: grab;";const img = document.createElement("img");img.style.cssText = "position: absolute;object-fit: contain;user-select: none;-webkit-user-drag: none;user-select: none;-moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;";img.src = imgurl;img.title = "预览";const close = document.createElement("div");close.innerHTML = `<svg aria-hidden="true" role="img" font-size="20"  width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"><g fill="none" fill-rule="evenodd"><path d="M0 0h16v16H0z"></path><path fill="currentColor" d="M13.303 2.697a.5.5 0 010 .707L8.707 8l4.596 4.596a.5.5 0 01-.707.707L8 8.707l-4.596 4.596a.5.5 0 01-.707-.707L7.293 8 2.697 3.404a.5.5 0 01.707-.707L8 7.293l4.596-4.596a.5.5 0 01.707 0z"></path></g></svg>`;close.style.cssText = "position: absolute;top:20px;right:20px;align-items: center;color:white;display: flex;justify-content: center;background: rgba(29,29,37,0.4);border-radius: 50%;width:30px;height:30px;";close.onclick = () => {document.body.removeChild(box);}box.append(img);box.append(close);document.body.append(box);img.onload = function () {const imgRatio = img.naturalWidth / img.naturalHeight; //图片横纵比const boxRatio = box.clientWidth / box.clientHeight;   //容器横纵比if (imgRatio > boxRatio) {const scale = box.clientWidth / img.naturalWidth;img.style.width = box.clientWidth + "px"; //长度填充img.style.height = img.naturalHeight * scale + "px"; //高度自适应img.style.top = Math.ceil((box.clientHeight - img.clientHeight) / 2) + "px";//位置居中} else {const scale = box.clientHeight / img.naturalHeight;img.style.height = box.clientHeight + "px";//高度填充img.style.width = img.naturalWidth * scale + "px";//长度自适应img.style.left = Math.ceil((box.clientWidth - img.clientWidth) / 2) + "px";//位置居中}const download = document.createElement("div");download.innerHTML = `<svg style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024"  ><path d="M511.3 856.9c-11.3 0-20.4-9.1-20.4-20.4V87c0-11.3 9.1-20.4 20.4-20.4s20.4 9.2 20.4 20.4v749.5c0.1 11.2-9.1 20.4-20.4 20.4z" fill="#FFFFFF" ></path><path d="M511.3 857.3c-20.5 0-39.7-8-54.2-22.4L187.3 565c-8-8-8-20.9 0-28.9s20.9-8 28.9 0L486.1 806c6.7 6.7 15.7 10.5 25.2 10.5s18.5-3.7 25.2-10.5l269.9-269.9c8-8 20.9-8 28.9 0s8 20.9 0 28.9L565.5 834.9c-14.5 14.5-33.7 22.4-54.2 22.4zM170.8 961.2c-11 0-20.1-8.8-20.4-19.9-0.3-11.3 8.6-20.7 19.9-21l681-18.1h0.6c11 0 20.1 8.8 20.4 19.9 0.3 11.3-8.6 20.7-19.9 21l-681 18.1h-0.6z" fill="#FFFFFF" ></path></svg>`;download.style.cssText = "position: absolute;top:20px;right:60px;align-items: center;color:white;display: flex;justify-content: center;background: rgba(29,29,37,0.4);border-radius: 50%;width:30px;height:30px;";download.onclick = () => {let fileName = imgurl;let downloadUrl = imgurl;try {const regex = /([^/\\?&]+(?:\.[a-zA-Z0-9\u4e00-\u9fa5_-]+))(?:[?#]|$)/;const match = imgurl.match(regex);fileName = match ? match[0] : null;if (!fileName) {fileName = new Date().getTime() + ".png";}} catch (e) {}if (fileName.trim().toLowerCase().endsWith(".svg")) {fileName = fileName.substring(0, fileName.lastIndexOf(".svg")) + ".png";// 创建一个 canvas 元素const canvas = document.createElement('canvas');const ctx = canvas.getContext('2d');canvas.width = img.clientWidth;canvas.height = img.clientHeight;ctx.drawImage(img, 0, 0);downloadUrl = canvas.toDataURL('image/png');}let link = document.createElement('a')link.style.display = 'none'link.href = downloadUrllink.target = "_blank";link.setAttribute('download', fileName);document.body.appendChild(link)link.click()document.body.removeChild(link) //下载完成移除元素window.URL.revokeObjectURL(downloadUrl) //释放掉blob对象}box.append(download);};const getRange = (actual, limita, limitb) => {if (actual < -limita) {return -limita;} else if (actual > limitb) {return limitb;}return actual;}const drag = {status: false, lastX: null, lastY: null}const dragStart = (x, y) => {if (drag === true) return;drag.status = truedrag.lastX = xdrag.lastY = y}const dragMove = (x, y) => {if (drag.status) {let mx = x - drag.lastXlet my = y - drag.lastYdrag.lastX = xdrag.lastY = ylet top = img.offsetTop + mylet left = img.offsetLeft + mximg.style.left = getRange(left, img.clientWidth - 10, box.clientWidth - 10) + 'px';img.style.top = getRange(top, img.clientHeight - 10, box.clientHeight - 10) + "px";}}const dragEnd = () => {drag.status = falsedrag.lastX = nulldrag.lastY = null}const zoom = {status: false,lastDistance: null,lastCenter: null,}const getCenter = (x1, y1, x2, y2) => {return {x: (x1 + x2) / 2, y: (y1 + y2) / 2}}const getDistance = (x1, y1, x2, y2) => {const dx = x2 - x1;const dy = y2 - y1;return Math.sqrt(dx * dx + dy * dy); // 返回距离}const zoomStart = (x1, y1, x2, y2) => {zoom.lastDistance = getDistance(x1, y1, x2, y2);zoom.center = getCenter(x1, y1, x2, y2)dragStart(zoom.center.x, zoom.center.y);}const zoomCore = (isChangeBig, center_x, center_y, changeScale) => {const top_d = center_y - img.offsetTop;const left_d = center_x - img.offsetLeft;let modifyHeight = img.clientHeight * changeScale;let modifyWidth = img.clientWidth * changeScale;if (isChangeBig && modifyHeight > img.naturalHeight * max) return;if (!isChangeBig && modifyHeight * max < img.naturalHeight) return;img.style.height = modifyHeight + "px";img.style.width = modifyWidth + "px";img.style.top = (center_y - top_d * changeScale) + "px";img.style.left = (center_x - left_d * changeScale) + "px";}const zoomMove = (x1, y1, x2, y2) => {let newDistance = getDistance(x1, y1, x2, y2);let center = getCenter(x1, y1, x2, y2)if (Math.abs(newDistance - zoom.lastDistance) > 0.1) {zoomCore(zoom.lastDistance < newDistance, center.x, center.y, newDistance / zoom.lastDistance);}zoom.lastDistance = newDistance;}const zoomEnd = () => {zoom.lastDistance = null;zoom.center = null;dragEnd();}box.ontouchstart = (event) => {if (event.touches.length === 1) {dragStart(event.touches[0].pageX, event.touches[0].pageY);} else if (event.touches.length === 2) {zoomStart(event.touches[0].pageX, event.touches[0].pageY, event.touches[1].pageX, event.touches[1].pageY)}box.ontouchmove = (e) => {if (event.touches.length === 1) {dragMove(e.touches[0].pageX, e.touches[0].pageY);} else if (e.touches.length === 2) {zoomMove(e.touches[0].pageX, e.touches[0].pageY, e.touches[1].pageX, e.touches[1].pageY)}}box.ontouchend = () => {zoomEnd();box.ontouchmove = null;box.ontouchend = null;}}box.onmousedown = (event) => {document.body.style.userSelect = 'none';if (event.button === 0) {document.onmousemove = (event) => {dragMove(event.clientX, event.clientY);}document.onmouseup = (event) => {document.body.style.userSelect = '';if (event.button === 0) {dragEnd();document.onmousemove = nulldocument.onmouseup = null}}dragStart(event.clientX, event.clientY);}}box.onwheel = (event) => {event.preventDefault(); //关闭默认事件zoomCore(event.deltaY < 0, event.clientX, event.clientY, event.deltaY > 0 ? (1 - scale) : (1 + scale));}
}

相关文章:

js函数预览图片:支持鼠标和手势拖拽缩放

对之前的方式改进&#xff1a;原生js实现图片预览控件&#xff0c;支持丝滑拖拽&#xff0c;滚轮放缩&#xff0c;放缩聚焦_js图片预览-CSDN博客 /*** 图片预览函数&#xff0c;调用后自动预览图片* param {图片地址} imgurl*/ function openImagePreview(imgurl) {if (!imgurl…...

用QT实现 端口扫描工具1

安装在线QT&#xff0c;尽量是完整地自己进行安装&#xff0c;不然会少包 参考【保姆级图文教程】QT下载、安装、入门、配置VS Qt环境-CSDN博客 临时存储空间不够。 Windows系统通常会使用C盘来存储临时文件。 修改临时文件存储位置 打开系统属性&#xff1a; 右键点击“此电…...

设计模式 结构型 适配器模式(Adapter Pattern)与 常见技术框架应用 解析

适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将一个类的接口转换成客户端所期望的另一个接口&#xff0c;从而使原本因接口不兼容而无法一起工作的类能够协同工作。这种设计模式在软件开发中非常有用&#xff0c;尤其是在需要集成…...

vue 项目集成 electron 和 electron 打包及环境配置

vue electron 开发桌面端应用 安装 electron npm i electron -D记得加上-D&#xff0c;electron 需添加到devDependencies&#xff0c;如果添加到dependencies后面运行可能会报错 根目录创建electron文件夹&#xff0c;在electron文件夹创建main.js&#xff08;或者backgrou…...

vscode如何离线安装插件

在没有网络的时候,如果要安装插件,就会麻烦一些,需要通过离线安装的方式进行。下面记录如何在vscode离线安装插件。 一、下载离线插件 在一台能联网的电脑中,下载好离线插件,拷贝到无法联网的电脑上。等待安装。 vscode插件商店地址:https://marketplace.visualstudio.co…...

计算机网络常见面试题及解答

以下是计算机网络中常见的面试题及解答&#xff0c;按主题分类&#xff1a; --- ## **一、基础概念** ### **1. OSI 七层模型和 TCP/IP 模型的区别是什么&#xff1f;** **答&#xff1a;** - **OSI 七层模型&#xff1a;** - 应用层、表示层、会话层、传输层、网络层、数…...

举例说明AI模型怎么聚类,最后神经网络怎么保存

举例说明怎么聚类,最后神经网络怎么保存 目录 举例说明怎么聚类,最后神经网络怎么保存K - Means聚类算法实现神经元特征聚类划分成不同专家的原理和过程 特征提取: 首先,需要从神经元中提取有代表性的特征。例如,对于一个多层感知机(MLP)中的神经元,其权重向量可以作为特…...

HarmonyOS NEXT应用开发实战(一):边学边玩,从零开发一款影视APP

引言 学习一项技能&#xff0c;最好也最快的办法就是动手实战。通过自己给自己找项目练习&#xff0c;不仅能够激发兴趣&#xff0c;还能从开发实战中不断总结经验。这种学习方法是最为高效的。今天&#xff0c;我们将通过开发一款名为“爱影家”的影视APP&#xff0c;来学习H…...

STM32G0B1 can Error_Handler 解决方法

问题现象 MCU上电&#xff0c;发送0x13帧数据固定进入 Error_Handler 硬件介绍 MCU :STM32G0B1 can:NSI1042 tx 接TX RX 接RX 折腾了一下午&#xff0c;无解&#xff0c;问题依旧&#xff1b; 对比测试 STM32G431 手头有块G431 官方评估版CAN 模块&#xff1b; 同样的…...

使用 `llama_index` 构建智能问答系统:多种文档切片方法的评估

使用 llama_index 构建智能问答系统&#xff1a;多种文档切片方法的评估 代码优化与解析1. **代码结构优化**2. **日志管理**3. **环境变量管理**4. **模型初始化**5. **提示模板更新**6. **问答函数优化**7. **索引构建与查询引擎**8. **节点解析器测试** 总结 在现代自然语言…...

【大模型】7 天 AI 大模型学习

7 天 AI 大模型学习 Day 2 今天是 7 天AI 大模型学习的第二天 &#x1f604;&#xff0c;今天我将会学习 Transformer 、Encoder-based and Decoder-Based LLMs 等 。如果有感兴趣的&#xff0c;就和我一起开始吧 &#xff5e; 课程链接 &#xff1a;2025年快速吃透AI大模型&am…...

软件工程大复习之(四)——面向对象与UML

4.1 面向对象概述 面向对象&#xff08;OO&#xff09;是一种编程范式&#xff0c;它将数据和处理数据的方法封装在对象中。面向对象的主要概念包括&#xff1a; 对象&#xff1a;实例化的数据和方法的集合。类&#xff1a;对象的蓝图或模板。封装&#xff1a;隐藏对象的内部…...

【Linux】shell命令

目录 shell的基本命令 shell - 贝壳 外在保护工具 用户、shell、内核、硬件之间的关系 解析器的分类&#xff1a; shell命令格式 history -历史记录查询 修改环境变量的值&#xff1a; shell中的特殊字符 通配符 管道 | 输入输出重定向 命令置换符 shell的基本命…...

ValuesRAG:以检索增强情境学习强化文化对齐

随着大型语言模型&#xff08;LLMs&#xff09;的迅猛发展&#xff0c;其在各个领域展现出强大的能力。然而&#xff0c;训练数据中西方中心主义的倾向&#xff0c;使得 LLMs 在文化价值观一致性方面面临严峻挑战&#xff0c;这一问题在跨文化场景中尤为突出&#xff0c;可能导…...

【机器学习篇】交通革命:机器学习如何引领未来的道路创新

嘿&#xff0c;你知道吗&#xff1f;机器学习正在交通领域掀起一场革命啦&#xff01;它将如何引领未来道路创新呢 本文有精彩的 C 代码演示、实用的图片解释&#xff0c;还有超多干货&#xff0c;保证让你大开眼界&#xff0c;点赞收藏关注&#xff0c; 开启一场奇妙的探索之…...

DeepSeek-V3 通俗详解:从诞生到优势,以及与 GPT-4o 的对比

1. DeepSeek 的前世今生 1.1 什么是 DeepSeek&#xff1f; DeepSeek 是一家专注于人工智能技术研发的公司&#xff0c;致力于打造高性能、低成本的 AI 模型。它的目标是让 AI 技术更加普惠&#xff0c;让更多人能够用上强大的 AI 工具。 1.2 DeepSeek-V3 的诞生 DeepSeek-V…...

把vue项目或者vue组件发布成npm包或者打包成lib库文件本地使用

将vue项目发布成npm库文件&#xff0c;第三方通过npm依赖安装使用&#xff1b;使用最近公司接了一个项目&#xff0c;这个项目需要集成到第三方页面&#xff0c;在第三方页面点击项目名称&#xff0c;页面变成我们的项目页面&#xff1b;要求以npm库文件提供给他们&#xff1b;…...

【STC库函数】Compare比较器的使用

如果我们需要比较两个点的电压&#xff0c;当A点高于B点的时候我们做一个操作&#xff0c;当B点高于A点的时候做另一个操作。 我们除了加一个运放或者比较器&#xff0c;还可以直接使用STC内部的一个比较器。 正极输入端可以是P37、P50、P51&#xff0c;或者从ADC的十六个通道…...

单片机-独立按键矩阵按键实验

1、按键介绍 按键管脚两端距离长的表示默认是导通状态&#xff0c;距离短的默认是断开状态&#xff0c; 如果按键按下&#xff0c;初始导通状态变为断开&#xff0c;初始断开状态变为导通 我们开发板是采用软件消抖&#xff0c;一般来说一个简单的按键消抖就是先读取按键的状…...

若要把普通表转成分区表,就需要先新建分区表,然后把普通表中的数据导入新建分区表。 具体怎么导入?

将普通表转换为分区表并导入数据是一个常见的数据库管理任务。以下是详细的步骤和示例&#xff0c;帮助你在 GaussDB 中完成这一过程&#xff1a; 1. 创建分区表 首先&#xff0c;你需要创建一个新的分区表&#xff0c;定义好分区键和分区策略。假设你有一个普通表 orders&am…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集&#xff0c;单周期执行&#xff1b;低功耗、CIP 独立外设&#xff1b;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel&#xff08;原始…...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!

今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等&#xff0c;设置经线、纬线都以10间隔显示。 2、需要插入背会归线&#xf…...