js 以鼠标滚轮位置为中心缩放、放大以及边界判断

前言

项目需求为页面上实现拖拽节点和可以在页面中通过滑动滚轮来缩放节点显示(以鼠标位置为缩放中心点)从而放大到可以看到详细的信息,节点有10000个。特此记录下实现细节

效果图

fb49c-p848x.gif

js

初始化变量

    const container = document.querySelector('.container');
    const ul = document.querySelector('.ul');
    // 变量
    let result,
        x = 0,
        y = 0,
        scale = 1,
        ulWidth = 1500,
        ulHeight = 1200,
        minScale = 1,
        maxScale = 4,
        isDown = false, // 按下标识
        diff = { x: 0, y: 0 }, // 相对于上一次lastPointermove移动差值
        lastPointermove = { x: 0, y: 0 }; // 用于计算diff
    ul.style.width = ulWidth + 'px';
    ul.style.height = ulHeight + 'px';
    ul.style.transform = 'matrix(1, 0, 0, 1, 0, 0)';

为节点绑定拖拽事件,拖拽事件的边界使用Math进行判断,比起if判断更加清晰快捷。

鼠标抬起采用document全局判断,避免鼠标移动到节点外未触发鼠标抬起事件

 // 绑定鼠标点击
    ul.addEventListener('mousedown', function (e) {
        e.preventDefault();
        e.stopPropagation();
        isDown = true;
        lastPointermove = { x: e.clientX, y: e.clientY };

    });
    // 绑定鼠标移动
    ul.addEventListener('mousemove', function (e) {
        e.preventDefault();
        e.stopPropagation();
        if (isDown) {
            const current1 = { x: e.clientX, y: e.clientY };
            diff.x = current1.x - lastPointermove.x;
            diff.y = current1.y - lastPointermove.y;
            lastPointermove = { x: current1.x, y: current1.y };
            x += diff.x;
            y += diff.y;
            //边界判断
            let offsetX = Math.min(Math.max(x, ulWidth - ulWidth * (scale + 1) / 2), + ulWidth * (scale - 1) / 2);
            let offsetY = Math.min(Math.max(y, ulHeight - ulHeight * (scale + 1) / 2), + ulHeight * (scale - 1) / 2);
            ul.style.transform = `matrix(${scale}, 0, 0, ${scale}, ${offsetX}, ${offsetY})`;
        }

    });
    // 绑定鼠标抬起
    document.addEventListener('mouseup', () => {
        isDown = false;
    })

滚轮缩放、放大逻辑

X轴的(window.innerWidth - ulWidth) * 0.5)主要判断节点距离左边边距,y轴同样

同样采用Math判断边界

ul.addEventListener('wheel', function (e) {
        let ratio = 1.1;
        // 缩小
        if (e.deltaY > 0) {
            ratio = 1 / 1.1;
        }
        // 限制缩放倍数
        const onscale = scale * ratio;
        if (onscale > maxScale) {
            ratio = maxScale / scale;
            scale = maxScale;
        } else if (onscale < minScale) {
            ratio = minScale / scale;
            scale = minScale;
        } else {
            scale = onscale;
        }
        const origin = {
            x: (ratio - 1) * ulWidth * 0.5,
            y: (ratio - 1) * ulHeight * 0.5
        };
        // 计算偏移量
        x -= (ratio - 1) * (e.clientX - x - (window.innerWidth - ulWidth) * 0.5) - origin.x;
        y -= (ratio - 1) * (e.clientY - y) - origin.y;
        let offsetX = Math.min(Math.max(x, ulWidth - ulWidth * (scale + 1) / 2), ulWidth * (scale - 1) / 2);
        let offsetY = Math.min(Math.max(y, ulHeight - ulHeight * (scale + 1) / 2), + ulHeight * (scale - 1) / 2);
        x = offsetX;
        y = offsetY;
        ul.style.transform = `matrix(${scale}, 0, 0, ${scale}, ${offsetX}, ${offsetY})`;

    });

总结

自此功能开发完毕,使用原生方法实现也是加深对js的理解,基本上js上面能实现的移植到React、Vue也是一样的道理。小弟才疏学浅,大佬们见笑了,有帮到你的小伙伴可以点个赞,谢谢。

全部代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    body {
        margin: 0;
        padding: 0;
    }
    .main {
        width: 100%;
        display: flex;
        justify-content: center;
    }
    ul {
        width: 1500px;
        height: 1200px;
        background-color: antiquewhite;
        list-style: none;
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
        margin: 0;
        padding: 0;
    }
    li {
        width: 100px;
        height: 80px;
        background-color: orange;
        margin-right: 20px;
    }
    li:nth-child(12n) {
        margin-right: 0px;
    }

    li:hover {
        background-color: darkblue;
    }
    .container {
        position: relative;
        width: 1500px;
        height: 1200px;
        overflow: hidden;
    }
</style>
<body>
    <div class="main">
        <div class="container">
            <ul class="ul">
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>

        </div>
    </div>
</body>
<script>
    const container = document.querySelector('.container');
    const ul = document.querySelector('.ul');
    // 变量
    let result,
        x = 0,
        y = 0,
        scale = 1,
        ulWidth = 1500,
        ulHeight = 1200,
        minScale = 1,
        maxScale = 4,
        isDown = false, // 按下标识
        diff = { x: 0, y: 0 }, // 相对于上一次lastPointermove移动差值
        lastPointermove = { x: 0, y: 0 }; // 用于计算diff
    ul.style.width = ulWidth + 'px';
    ul.style.height = ulHeight + 'px';
    ul.style.transform = 'matrix(1, 0, 0, 1, 0, 0)';

    // 拖拽查看
    // 绑定鼠标点击
    ul.addEventListener('mousedown', function (e) {
        e.preventDefault();
        e.stopPropagation();
        isDown = true;
        lastPointermove = { x: e.clientX, y: e.clientY };
    });
    // 绑定鼠标移动
    ul.addEventListener('mousemove', function (e) {
        e.preventDefault();
        e.stopPropagation();
        if (isDown) {
            const current1 = { x: e.clientX, y: e.clientY };
            diff.x = current1.x - lastPointermove.x;
            diff.y = current1.y - lastPointermove.y;
            lastPointermove = { x: current1.x, y: current1.y };
            x += diff.x;
            y += diff.y;
            //边界判断
            let offsetX = Math.min(Math.max(x, ulWidth - ulWidth * (scale + 1) / 2), + ulWidth * (scale - 1) / 2);
            let offsetY = Math.min(Math.max(y, ulHeight - ulHeight * (scale + 1) / 2), + ulHeight * (scale - 1) / 2);
            ul.style.transform = `matrix(${scale}, 0, 0, ${scale}, ${offsetX}, ${offsetY})`;
        }
    });
    // 绑定鼠标抬起
    document.addEventListener('mouseup', () => {
        isDown = false;
    })

    // 滚轮缩放、放大逻辑
    ul.addEventListener('wheel', function (e) {
        // e.preventDefault();
        let ratio = 1.1;
        // 缩小
        if (e.deltaY > 0) {
            ratio = 1 / 1.1;
        }
        // 限制缩放倍数
        const onscale = scale * ratio;
        if (onscale > maxScale) {
            ratio = maxScale / scale;
            scale = maxScale;
        } else if (onscale < minScale) {
            ratio = minScale / scale;
            scale = minScale;
        } else {
            scale = onscale;
        }
        const origin = {
            x: (ratio - 1) * ulWidth * 0.5,
            y: (ratio - 1) * ulHeight * 0.5
        };
        // 计算偏移量
        x -= (ratio - 1) * (e.clientX - x - (window.innerWidth - ulWidth) * 0.5) - origin.x;
        y -= (ratio - 1) * (e.clientY - y) - origin.y;
        let offsetX = Math.min(Math.max(x, ulWidth - ulWidth * (scale + 1) / 2), ulWidth * (scale - 1) / 2);
        let offsetY = Math.min(Math.max(y, ulHeight - ulHeight * (scale + 1) / 2), + ulHeight * (scale - 1) / 2);
        x = offsetX;
        y = offsetY;
        ul.style.transform = `matrix(${scale}, 0, 0, ${scale}, ${offsetX}, ${offsetY})`;

    });
</script>

</html>

猜你喜欢

转载自blog.csdn.net/qq_44001572/article/details/129199616