Record-JS simply realizes partial zoom-in preview effect of shopping cart picture

Here I will share with you some of the knowledge I have summarized on the Internet, I hope it will be helpful to everyone

1. Realize the effect

Screen recording 2023-02-18 8.21.50 pm.gif

2. Code implementation

There are not many codes. Let’s take a look at the structure of the HTML. The structure is very simple. Initialize the MagnifyingGlass object to associate an IMG tag to achieve magnification.

<!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" alt="">
</div>
</body>
    <script src="./magnifyingGlass.js"></script>
<script>
    //针对某个标签进行图片放大处理
    let magnifyingGlass = new MagnifyingGlass(document.getElementById('clothes'))
</script>

</html>

Take another look at 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',`${200}px`)
        this.magnifyingGlassView.setAttribute('height',`${200}px`)
        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',`${width}px`)
            canvas.setAttribute('height',`${height}px`)
            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',`${diffusionLength}px`)
            this.smallCanvas.setAttribute('height',`${diffusionLength}px`)
        }
        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);
    }
}

The above is all the logic, and the implementation method is definitely not optimal, but it can be associated with achieving any effect through the operation of pixels.

3. How to solve the cross-domain problem of obtaining pixel information?

You can start a node local service, first see a folder containing the entry files of index.js and package.json .

The content of package.json is as follows:

{
    "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"
    }
}

The content of index.js is as follows:

var express = require('express')
var app = express()
var http = require('http').Server(app)
//公共页面访问设置
app.use(express.static('www'))
//开启服务
http.listen(3000,function(){
    console.log('开始了')
})

Execute npm install on the terminal and then execute the start service command node ./index.js:

3. How to solve the cross-domain problem of obtaining pixel information?

image.png

Note that the front-end files are placed in the directory under the www folder

image.png

In this way, the cross-domain problem is solved.

This article is reproduced in:

https://juejin.cn/post/7201437314693906491

If it is helpful to you, you are welcome to pay attention. I will update the technical documents regularly, and we will discuss and learn together and make progress together.

 

Guess you like

Origin blog.csdn.net/qq_40716795/article/details/130279552