以挪动一个SVG图形为例,残缺代码如下:

<!doctype html><html>    <head>        <style>body {    margin: 0;}/* 最外层容器 */#content {    /* 阻止页面大小随着SVG挪动而变动 */    overflow: hidden;}/* 固定Header */#header {    left: 0;    right: 0;    position: fixed;    height: 50px!important;    background-color: rgb(124, 252, 45);    z-index: 10;}/* 包容须要追随手势挪动的SVG的容器 */#panel_container {    height: 100vh;        z-index: 5;    background-color: rgb(248, 213, 98);}/* 固定Footer */#footer {    left: 0;    right: 0;    bottom: 0;    position: fixed;    height: 50px!important;    background-color: rgb(124, 252, 45);    z-index: 10;}/* 须要追随手势挪动的SVG */svg {    background-color: rgb(250, 250, 153);    width: 100%;    height: 100%;}        </style>        <script>// 须要追随手势挪动的SVG。页面加载后赋值var svg = null;// 用户操作后冀望的SVG缩放比例var scale = 1;// 用户操作后冀望的SVG中心点的横向偏移var posX = 0;// 用户操作后冀望的SVG中心点的纵向偏移var posY = 0;// 咱们不心愿SVG比例过小或偏出屏幕,所以在SVG被挪动或缩放到合乎用户冀望的比例和地位后,还须要让SVG回弹到以下合乎咱们冀望的比例和地位// 通过修改后的SVG缩放比例var finalScale = 1;// 通过修改后的SVG中心点的横向偏移var finalPosX = 0;// 通过修改后的SVG中心点的纵向偏移var finalPosY = 0;// 上次依据用户操作进行渲染的工夫戳。每次执行render()时被设置。用户的操作优先于零碎的回弹修改,所以只有以后工夫间隔该工夫戳曾经过来了一段时间(200毫秒)后,咱们才能够开始对SVG进行回弹修改。详见bounce()var lastRenderingTime;// 监听页面加载实现事件。为SVG加点元素以便地位参考window.addEventListener("load", function() {    svg = document.querySelector("svg");    // 简略加一个小方块    let newRect = document.createElementNS("http://www.w3.org/2000/svg", "rect");    newRect.setAttribute("x", "150");    newRect.setAttribute("y", "150");    newRect.setAttribute("width", "100");    newRect.setAttribute("height", "100");    newRect.setAttribute("fill", "#5cceee");    svg.appendChild(newRect);});// 依据用户的操作进行渲染var render = () => {    // 更新渲染的工夫戳    lastRenderingTime = new Date().getTime();    window.requestAnimationFrame(() => {        // 依据新的地位和缩放比例渲染SVG        svg.style.transform = `translate3D(${posX}px, ${posY}px, 0px) scale(${scale})`;        // 如果不想要回弹成果,以下代码能够去掉        // 让零碎稍后尝试回弹修改(有必要的话)        setTimeout(bounce, 500);    });};// 如果不想要回弹成果,以下bounce()代码能够去掉// 依据修改值回弹修改SVGvar bounce = () => {    // 用户操作后的缩放和地位没有问题,用户冀望与零碎冀望雷同,间接返回    if (scale == finalScale && posX == finalPosX && posY == finalPosY) return;        // 用户可能还在操作中,按优先级规定不进行零碎操作,而是期待片刻再尝试    if (new Date().getTime() - lastRenderingTime < 200) {        // 期待500毫秒        setTimeout(bounce, 500);        // 返回        return;    }    // 包容SVG的容器。联合SVG和包容SVG的容器的绝对地位和大小来计算回弹量    var ref = document.getElementById("panel_container").getBoundingClientRect();    // SVG以后的缩放比例    var lastScale = svg.getBoundingClientRect().width / ref.width;    // SVG以后的中心点横向偏移    var lastPosX = svg.getBoundingClientRect().x + svg.getBoundingClientRect().width / 2 - ref.width / 2;    // SVG以后的中心点纵向偏移    var lastPosY = svg.getBoundingClientRect().y + svg.getBoundingClientRect().height / 2 - ref.height / 2;    // 该次回弹的指标比例。与最终修改值差距过小则间接置为最终修改值    var stepScale = Math.abs(finalScale - lastScale) > 0.1 ? (lastScale + Math.sign(finalScale - lastScale) * 0.1) : finalScale;    // 该次回弹的指标中心点横向偏移。与最终修改值差距过小则间接置为最终修改值    var stepPosX = Math.abs(finalPosX - lastPosX) > 10 ? (lastPosX + (finalPosX - lastPosX) / 10 + Math.sign(finalPosX - lastPosX) * 10) : finalPosX;    // 该次回弹的指标中心点纵向偏移。与最终修改值差距过小则间接置为最终修改值    var stepPosY = Math.abs(finalPosY - lastPosY) > 10 ? (lastPosY + (finalPosY - lastPosY) / 10 + Math.sign(finalPosY - lastPosY) * 10) : finalPosY;    window.requestAnimationFrame(() => {        // 依据指标地位和缩放比例渲染SVG        svg.style.transform = `translate3D(${stepPosX}px, ${stepPosY}px, 0px) scale(${stepScale})`;    });    // 如果曾经修改实现则返回    if (stepScale == finalScale && stepPosX == finalPosX && stepPosY == finalPosY) return;    // 持续尝试进行下一次修改    setTimeout(bounce, 500);};// 监听触控板手势事件。理论为鼠标滚轮事件window.addEventListener('wheel', (e) => {    // 包容SVG的容器。联合SVG和包容SVG的容器的绝对地位和大小来计算修改值    var ref = document.getElementById("panel_container").getBoundingClientRect();    // SVG以后的缩放比例    var lastScale = svg.getBoundingClientRect().width / ref.width;    // SVG以后的中心点横向偏移    var lastPosX = svg.getBoundingClientRect().x + svg.getBoundingClientRect().width / 2 - ref.width / 2;    // SVG以后的中心点纵向偏移    var lastPosY = svg.getBoundingClientRect().y + svg.getBoundingClientRect().height / 2 - ref.height / 2;    if (e.ctrlKey) {        // 缩放事件        // 依据操作确定缩放值。地位不变        finalScale = scale = lastScale - e.deltaY * 0.01;        finalPosX = posX = lastPosX;        finalPosY = posY = lastPosY;    } else {        // 挪动事件        // 依据操作确定地位。缩放值不变        finalScale = scale = lastScale;        finalPosX = posX = lastPosX - e.deltaX * 2;        finalPosY = posY = lastPosY - e.deltaY * 2;    }    // 如果不想要回弹成果,以下对finalXXX的赋值能够间接批改为对XXX的赋值      // 不容许SVG过小(缩放值小于1)    if (scale < 1) finalScale = 1;    // 不容许SVG右边界进入屏幕内    var minPosX = ref.width / 2 - ref.width * finalScale / 2;    // 不容许SVG左边界进入屏幕内    var maxPosX = ref.width * finalScale / 2 - ref.width / 2;    // 不容许SVG下边界进入屏幕内    var minPosY = ref.height / 2 - ref.height * finalScale / 2;    // 不容许SVG上边界进入屏幕内    var maxPosY = ref.height * finalScale / 2 - ref.height / 2;    // 依据以上限度值确定零碎最终修改值    if (posX < minPosX) finalPosX = minPosX;    if (posX > maxPosX) finalPosX = maxPosX;    if (posY < minPosY) finalPosY = minPosY;    if (posY > maxPosY) finalPosY = maxPosY;    // 依据用户操作进行渲染    render();});        </script>    </head>    <body>        <!-- 最外层容器 -->        <div id='content'>            <!-- 搁置一个固定Header为肉眼察看位移作参考 -->            <div id='header'>                Header            </div>            <!-- 包容须要追随手势挪动的SVG的容器 -->            <div id='panel_container'>                <!-- 须要追随手势挪动的SVG -->                <svg></svg>            </div>            <!-- 搁置一个固定Footer为肉眼察看位移作参考 -->            <div id='footer'>                Footer            </div>        </div>    </body></html>