记录-JS简单实现购物车图片局部放大预览效果
Posted 林恒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记录-JS简单实现购物车图片局部放大预览效果相关的知识,希望对你有一定的参考价值。
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
一、实现效果
二、代码实现
代码不多,先看一下 HTML 里面结构很简单,初始化 MagnifyingGlass 对象来关联一个 IMG 标签来实现放大。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <style type="text/css"> * padding: 0; margin: 0; .clothes width: auto; height: auto; </style> <body> <div> <img id="clothes" class="clothes" src="./clothes.jpg" > </div> </body> <script src="./magnifyingGlass.js"></script> <script> //针对某个标签进行图片放大处理 let magnifyingGlass = new MagnifyingGlass(document.getElementById(\'clothes\')) </script> </html>
再看一下 MagnifyingGlass
class MagnifyingGlass // 需要放大的图片 imgEl // 放大预览视图 magnifyingGlassView // 区域小图 smallCanvas // 保存原图的像素值 originalPiexls = [] // 截流定时器 interceptionTimer = null constructor(el) if(el.tagName == \'IMG\') this.imgEl = el this.listenerImgLoadSucceeded() // 监听图片加载完成 async listenerImgLoadSucceeded() if(!this.imgEl.complete) await new Promise((resolve)=> this.imgEl.onload = resolve ) // 添加鼠标事件 this.addMouseEvent() // 创建一个放大预览视图 this.createMagnifyingGlassView() // 创建一个放大预览视图 createMagnifyingGlassView() if(this.magnifyingGlassView) this.magnifyingGlassView.remove() this.magnifyingGlassView = document.createElement(\'canvas\') this.magnifyingGlassView.style.cssText = \'position: fixed;background:aliceblue;left:0;top:0;pointer-events:none;display:none\' this.magnifyingGlassView.setAttribute(\'width\',`$200px`) this.magnifyingGlassView.setAttribute(\'height\',`$200px`) let body = document.getElementsByTagName(\'body\')[0] body.appendChild(this.magnifyingGlassView) // 添加鼠标事件 addMouseEvent() // 添加鼠标滑过事件 this.addMouseMoveToImageEl() // 鼠标滑出事件 this.addMouseLeaveToImageEl() // 添加鼠标滑过事件 addMouseMoveToImageEl() this.imgEl.onmousemove = (event)=> let x = event.clientX + this.getElementPosition(this.imgEl).left + 20 let y = event.clientY + this.getElementPosition(this.imgEl).top + 20 let position = x, y // 截流 this.interceptionFunc(()=> // 修改放大视图位置 this.changeMagnifyingGlassViewPosition(position) // 获取需要放大的像素 this.getNeedMasgnifyingGlassPiexl(clientX: (event.clientX - this.getElementPosition(this.imgEl).left),clientY: (event.clientY - this.getElementPosition(this.imgEl).top)) ) //截流 interceptionFunc(cb) if(this.interceptionTimer) return this.interceptionTimer = setTimeout(() => cb() this.interceptionTimer = null , 20); // 鼠标滑出事件 addMouseLeaveToImageEl() this.imgEl.onmouseleave = ()=> // 移除放大框 this.magnifyingGlassView.style.display = \'none\' // 修改放大视图位置 changeMagnifyingGlassViewPosition(position) this.magnifyingGlassView.style.left = position.x + \'px\' this.magnifyingGlassView.style.top = position.y + \'px\' this.magnifyingGlassView.style.display = \'block\' // 获取元素在屏幕的位置 getElementPosition(element) var top = element.offsetTop var left = element.offsetLeft var currentParent = element.offsetParent; while (currentParent !== null) top += currentParent.offsetTop left += currentParent.offsetLeft currentParent = currentParent.offsetParent return top,left // 保存原像素(操作像素点时候用) async getOriginalPiexls() if(this.originalPiexls.length == 0) var image = new Image(); image.src = this.imgEl.src; // 等待IMG标签加载完成后保存像素值 await new Promise((resolve)=> image.onload = resolve ) let width = image.width let height = image.height let canvas = document.createElement(\'canvas\') canvas.setAttribute(\'width\',`$widthpx`) canvas.setAttribute(\'height\',`$heightpx`) var ctx = canvas.getContext("2d") ctx.fillStyle = ctx.createPattern(image, \'no-repeat\'); ctx.fillRect(0, 0, width, height); try //保存像素 this.originalPiexls = ctx.getImageData(0,0,width,height) catch (error) console.log(error) // 获取需要放大的像素 async getNeedMasgnifyingGlassPiexl(event) //获取原始像素 this.getOriginalPiexls() //如果像素为空,不进行操作 if(this.originalPiexls.length == 0) return //获取待放大IMG的宽度,用来计算像素 let imageWidth = this.imgEl.offsetWidth //获取当前鼠标点的范围 let diffusionLength = 100 //鼠标触点 let mouseX = event.clientX let mouseY = event.clientY //规定区域的上下、左右宽度 let sepX = parseInt(diffusionLength) let sepY = parseInt(diffusionLength) // 需要开始的点 let startPoint = x:(mouseX - parseInt(sepX / 2.0)),y:(mouseY - parseInt(sepY / 2.0)) // 需要结束的点 let endPoint = x:(mouseX + parseInt(sepX / 2.0)),y:(mouseY + parseInt(sepY / 2.0)) // 最终要展示的像素集合(乘以4是单一像素值宽度) let finallyOriginalPiexls = new Uint8ClampedArray(sepX * sepY * 4) let currentIndex = 0 //操作像素 for(let i = startPoint.y;i < endPoint.y;i++) for(let j = startPoint.x; j < endPoint.x;j++) for(let k = 0;k < 4;k++) let index = (i * imageWidth + j) * 4 + k if(index > 0 && index < this.originalPiexls.data.length) // 超过宽度部分需要进行其他色值填充 if(j < imageWidth) finallyOriginalPiexls[currentIndex] = this.originalPiexls.data[index] else finallyOriginalPiexls[currentIndex] = 199 else finallyOriginalPiexls[currentIndex] = 199 currentIndex += 1 //先绘制一个100*100单位长的小图 if(!this.smallCanvas) this.smallCanvas = document.createElement(\'canvas\') this.smallCanvas.setAttribute(\'width\',`$diffusionLengthpx`) this.smallCanvas.setAttribute(\'height\',`$diffusionLengthpx`) let smallCtx = this.smallCanvas.getContext("2d") //初始化ImageData let finallyImageData = new ImageData(finallyOriginalPiexls,sepX,sepY) // 当前范围内需要放大的像素 smallCtx.putImageData(finallyImageData,0,0,0,0,diffusionLength,diffusionLength) let url = this.smallCanvas.toDataURL(\'image/jpeg\',1) //将小图绘制到200*200的预览图上 var image = new Image(); image.src = url; await new Promise((resolve)=> image.onload = resolve ) var magnifyingGlassCtx = this.magnifyingGlassView.getContext("2d") magnifyingGlassCtx.drawImage(image, 0,0,200,200);
上面的就是全部逻辑,实现方法肯定不是最优的,但是其中可以联想到通过像素点的操作实现任意效果。
三、获取像素信息跨域问题怎么解决?
可以启动一个 node 本地服务,首先见一个包含 index.js 和 package.json 的入口文件的文件夹。
package.json 内容如下:
"name": "youname", "version": "1.0.0", "description": "description", "main": "index.js", "scripts": "test": "node ./index.js" , "author": "wsl", "license": "ISC", "dependencies": "express": "^4.17.3", "express-static": "^1.2.6", "http": "^0.0.1-security"
index.js 内容如下:
var express = require(\'express\') var app = express() var http = require(\'http\').Server(app) //公共页面访问设置 app.use(express.static(\'www\')) //开启服务 http.listen(3000,function() console.log(\'开始了\') )
终端执行 npm install 后再执行启动服务命令 node ./index.js:
css+jquery 实现图片局部放大预览
今天有时间开始动手,使用css+jquery实现了图片局部放大的组件,首先看看效果图:
界面设计思路如下:
1.两个div,左边放图片的缩略图
2.在左边缩略图鼠标移动的时候,区域(效果图中的网格)
3.右边放大图div,背景为缩略图的大图,在鼠标移入缩略图中,通过获取鼠标的坐标,将右侧背景图片移动到跟鼠标坐标对应的位置
4.设计时尽量,获取原大图的尺寸,和缩略图视窗计算比例,更大精度的做到左侧缩略图上表示的区域,和右侧放大部分匹配
本示例大部分编码在javascript脚本,以下列出各部分的源码:
<div class="all-region"> <div class="image-wrap">
<!--缩略图div--> <div class="little-img"> <img src="./images/show-window/timg.jpg"> </div>
<!--图片放大div--> <div class="large-img"> </div>
<!--缩略图上展示被放大的区域,网格区域--> <div class="relative-region"></div> </div> </div>
css:
.all-region { width: 100%; height: auto; } .all-region .image-wrap { width: 1300px; margin: 0px auto; height: 300px; line-height: 300px; overflow: hidden; vertical-align: center; background: #FBFBFB; border-left: 1px solid #ebebeb; position: relative; } .image-wrap .little-img img { width: 600px; height: 300px; } .image-wrap .large-img { width: 600px; height: 300px; background-image: url("./images/show-window/timg.jpg"); border: 1px solid transparent; background-size: inherit; background-repeat: no-repeat; background-position-x: 0px; background-position-y: 0px; position: relative; top: -301px; left: 605px; float: left; z-index: 10; opacity: 0; display: none; transition: opacity 2s linear; overflow: hidden; } .relative-region { background: linear-gradient(45deg, rgba(46, 46, 46, 0.5) 50%, transparent 0), linear-gradient(135deg, rgba(200, 200, 200, .5) 70%, transparent 0); display: none; position: relative; z-index: 99; background-size: 5px 5px; }
Javascript:
class Elements { constructor() { //缩略图区域 this.sourceImage = $(".little-img"); //放大区域 this.aimImage = $(".large-img"); //视图图片,与图片实际尺寸比例 this.sourceToAimRate = 0.01; //原图高度 this.sourceHeight = 0; //原图宽度 this.sourceWidth = 0; //视图高度,div的高度,本例是300px this.containerHeight = this.sourceImage.children().height(); this.containerWidth = this.sourceImage.children().width(); //鼠标在缩略图上的坐标 offsetX this.cursor_x = 0; this.cursor_y = 0; //标志被放大的区域 this.region = $(".relative-region"); this.mouseMove = this.mouseMove.bind(this); this.regionPosition = this.regionPosition.bind(this); this.regionMove = this.regionMove.bind(this); this.caculatorRate = this.caculatorRate.bind(this); } //计算原图尺寸,思路是内存加载原图,获得尺寸,并计算容器视图和原图的比例 caculatorRate() { console.log(this.sourceImage.children().attr("src")); $("<img/>").attr("src", this.sourceImage.children().attr("src")).load((e) => { //let sourceImageWidth=e.target.width; this.sourceWidth = e.target.width; this.sourceHeight = e.target.height; //计算图片和容器的像素比例 this.sourceToAimRate = this.sourceWidth / this.containerWidth; }); } //鼠标在缩略图上移动时计算,放大图的背景位置,并且定位标识被放大的区域 mouseMove(e) { //console.log(`x:${e.offsetX},y:${e.offsetY}`); //偏离region的位置 //由于鼠标实际上是在标识被放大区域(网格区域)的div里面,所以通过e获取的实际上是缩略图内,网格标识的offsetX 要用网格区域的offsetX+offsetLeft-缩略图的offsetleft才是鼠标对应到缩略图上的位置 let r_x = e.offsetX; let r_y = e.offsetY; let s_t = this.sourceImage.offset().top; let s_l = this.sourceImage.offset().left; let r_t = this.region.offset().top; let r_l = this.region.offset().left; let x = r_l - s_l + r_x; let y = r_t - s_t + r_y; //在原图上显示,被放大的区域 let w = this.region.width(); let h = this.region.height(); //由于鼠标在网格区域的中心,所以在计算放大图的top和left的时候,实际是从网格的左上角位置 this.cursor_x = (x - w / 2) * this.sourceToAimRate; this.cursor_y = (y - h / 2) * this.sourceToAimRate; if (this.cursor_x + this.containerWidth > this.sourceWidth) { this.cursor_x = this.sourceWidth - this.containerWidth; } if (this.cursor_y + this.containerHeight > this.sourceHeight) { this.cursor_y = this.sourceHeight - this.containerHeight; } if (this.cursor_y < 0) { this.cursor_y = 0; } if (this.cursor_x < 0) { this.cursor_x = 0; } this.aimImage.css({ "background-position-x": -this.cursor_x + "px", "background-position-y": -this.cursor_y + "px" }); this.regionMove(w, h, x, y); } regionPosition(r_w, r_h, e) { let left = e.offsetX - r_w / 2; let top = e.offsetY - r_h / 2; if (left < 0) { left = 0; } if (left + r_w > this.containerWidth) { left = this.containerWidth - r_w; } if (top < 0) { top = 0; } if (top + r_h > this.containerHeight) { top = this.containerHeight - r_h; } this.region.css({ "top": (top - this.containerHeight) + "px", "left": left+ "px", "cursor": "crosshair" }); } regionMove(r_w, r_h, x, y) { let left = x - r_w / 2; let top = y - r_h / 2; if (left < 0) { left = 0; } if (left + r_w > this.containerWidth) { left = this.containerWidth - r_w; } if (top < 0) { top = 0; } if (top + r_h > this.containerHeight) { top = this.containerHeight - r_h; } this.region.css({"top": (top - this.containerHeight) + "px", "left": left + "px"}); } init() { this.caculatorRate(); //鼠标移入缩略图区域,由缩略图区域的hover事件初始化,将鼠标放入网格区域的中心 this.sourceImage.children().mouseover((e) => { this.aimImage.css({"display": "block", "opacity": "1"}); let r_w = this.containerWidth / this.sourceToAimRate; let r_h = this.containerHeight / this.sourceToAimRate; let x = e.offsetX; let y = e.offsetY; this.regionPosition(r_w, r_h, e); this.region.css({"display": "block", "height": r_h + "px", "width": r_w + "px"}); }); //修复鼠标在region上,右侧放大区域闪动 this.region.mousemove(this.mouseMove); this.region.mouseleave(() => { this.aimImage.css({"display": "none", "opacity": "0"}); this.region.css({"display": "none"}); }); } } $(function () { var e = new Elements(); e.init(); })
由于原图是1920*1080不是缩略视窗严格的2:1,计算中有小数等原因,使网格标识的区域,和放大区域展示的完全匹配
在下一篇将尝试,放大镜逆应用为缩小镜,实现图片裁剪的时候,标识裁剪的部分位于原图的位置和区域.
以上是关于记录-JS简单实现购物车图片局部放大预览效果的主要内容,如果未能解决你的问题,请参考以下文章