fine 很好 苦心专研 弄出来了

VUE2 - 移动端(h5)的SVG 缩放拖拽
一开始想着用一些插件 组件实现 ,但是我是虚拟DOM挂载的 (可能技术有限 没搞懂),自己手写了一个,嘿嘿
下面是代码 包括上篇文章的 PC的SVG拖拽缩放在一块。

思路很简单 一开始给想复杂了

1.还是xml的形式去获取SVG文件dom
2.拿到DOM解析后 在SVG上进行 事件绑定 就是(手指事件)触摸,滑动,松开
3.去控制SVG的位置 (我用的定位left 和 top 更好是tranform 比较好,后续我在优化,先实现功能)
4.按下的时候去分别记录 单指 双指的操作(存元素位置,和手指按下的位置 下面代码有详细注释)
5.反正 emm 直接看代码!!!

<template>
    <div>

        <div id="svgTemplate"></div>

    </div>
</template>
<script>

import Vue from "vue/dist/vue.esm.js";
import * as d3 from "d3"; //在vue文件里面引入d3
export default {
    name: "svg-2D",

    data() {
        return {
            /* 全局 */
            svgUrl: "", // svg的url
            svgDom: null, // 获取到的svg元素
            /* svg的变量 */
            photoResult: {
                resultVal: 0, // 测试结果 - 值
                resultMsg: "未检测", // 测试结果 - 字段
                resultColor: "#dcdee2" // 测试结果 - 字段背景色
            },
            svgimg: require('../../assets/test10.svg'),
            // stroke:'',
            // stroke: [6124, 6123],
            // linkShow: '1',
            oldMousePos: {},
            oldMousePos2: {},
            isTouch: false,
            num: 1
        };
    },
    async mounted() {
        // 方法绑定到window下面,提供给外部调用
        // svg rect点击事件
        window["handleClick"] = (e, objectAll) => {
            let tag = e.srcElement || e.target;
            let data = JSON.parse(objectAll)
            this.takePhoto(tag, data);
        };
        // svg 缩放 移动事件
        window['havcZooming'] = (e) => {
            // this.zoomimg(e);
        };
        window['touchstart'] = (e) => {
            this.touchstart(e);
        }
        window['touchMove'] = (e) => {
            this.touchMove(e);
        }
        window['touchEnd'] = (e) => {
            this.touchEnd(e);
        }

        document.addEventListener('gesturestart', function (event) {
            event.preventDefault()
        })



    },
    created() {
        this.getSvg();


    },

    methods: {
        // handleZoom(event) {
        //     const scale = event.transform.k; // 获取缩放比例
        //     const translate = [event.transform.x, event.transform.y]; // 获取平移距离

        //     // 计算SVG的中心点
        //     const centerX = this.svgWidth / 2;
        //     const centerY = this.svgHeight / 2;

        //     // 根据缩放和平移距离计算中心点的位置
        //     const center = [
        //         centerX / scale - translate[0] / scale,
        //         centerY / scale - translate[1] / scale,
        //     ];

        //     // 将中心点设置为可视区域
        //     this.d3Instance.translateTo(event.target, center[0], center[1]);
        // },
        // 初始化svg
        getSvg() {
            /* 创建xhr对象 */
            const xhr = new XMLHttpRequest();
            this.svgUrl = this.svgimg;
            xhr.open("GET", this.svgUrl, true);
            xhr.send();
            /* 监听xhr对象 */
            xhr.addEventListener("load", () => {
                /* 1. 获取 dom */
                const resXML = xhr.responseXML;
                this.svgDom = resXML.documentElement.cloneNode(true);
                //  给svg 设置 id 属性
                this.svgDom.setAttribute("id", "svgcanvas");
                //  给svg添加鼠标 滚动 缩放 事件   // PC 鼠标滚动  移动端 手指事件
                this.svgDom.setAttribute("v-on:mousewheel", "this.havcZooming($event)");

                // this.svgDom.setAttribute("v-on:touchstart", "this.havcZooming($event)");
                this.svgDom.setAttribute("v-on:touchstart", "this.touchstart($event)");
                this.svgDom.setAttribute("v-on:touchmove", "this.touchMove($event)");
                this.svgDom.setAttribute("v-on:touchend", "this.touchEnd($event)");
                this.svgDom.style.width = '97vw'
                this.svgDom.style.height = '97vh'
                this.svgDom.style.zIndex = '9'
                this.svgDom.style.position = 'absolute';
                // /* 2.SVG对象添加click事件 */
                let btnTakePhotoDom = this.svgDom.querySelectorAll("rect");
                let btnTakePhotoDomPath = this.svgDom.querySelectorAll("path");
                // 设置SVG》img的初始坐标系
                let svgImage = this.svgDom.querySelector('image')
                // svgImage.setAttribute('z-index', '1')


                // /* 3.SVG对象 逻辑处理 */
                //;逻辑处理 starts -----
                if (this.linkShow == '1') {
                    // 创建新的 、rect 标签 添加到虚拟dom 重新渲染
                    this.createRect()
                }
                //如果促销车位是一个数组 
                let strokes = [6124, 6123]
                for (let i of btnTakePhotoDom) {
                    //判断某ID 是否存在或多个ID 改变背景颜色和 边框颜色
                    // console.log(i['id'], 'id')
                    //去掉循环
                    for (let arrkey of strokes) {
                        //i['id'] == this.stroke
                        if (i['id'] == arrkey) {
                            i.setAttribute('stroke', 'red')
                        }
                    }
                    let objectAll = {
                        currNodeId: i.getAttribute('id'),
                        currNodeX: i.getAttribute('x'),
                        currNodeY: i.getAttribute('y'),
                        currNodeWidth: i.getAttribute('width'),
                        currNodeHeight: i.getAttribute('height'),
                    }
                    i.setAttribute('z-index', '9')
                    i.setAttribute('fill', 'pink')
                    i.setAttribute("v-on:click", "this.handleClick($event,'" + JSON.stringify(objectAll) + "')");
                }
                for (let i of btnTakePhotoDomPath) {
                    let objectAll = {
                        currNodeId: i.getAttribute('id'),
                    }
                    i.setAttribute("v-on:click", "this.handleClick($event,'" + JSON.stringify(objectAll) + "')");
                }
                // end----



                // /* 4.将svgDom对象转换成vue的虚拟dom */
                var oSerializer = new XMLSerializer();
                var sXML = oSerializer.serializeToString(this.svgDom);
                var Profile = Vue.extend({
                    template: "<div id='svgTemplate' ref='svgAll' style='z-index: 2;position: fixed;left: 0;top: 0;width:100%;height:100%;'>" + sXML + "</div>"
                });
                // 创建实例,并挂载到元素上
                new Profile().$mount("#svgTemplate");
            });
        },
        // 事件
        takePhoto(e, data) {
            console.log(data)
            this.$emit('searchShowTrue', data)


        },
        //svg 缩放
        zoomimg(e) {
            console.log('111111545')

            
            // ----------------
            let svg = d3.select("#svgcanvas"); //svgcanvas这个是svg这个标签的id
            var zoom = d3.zoom().on("zoom", function () { // svg放大缩小的事件
                d3.select(this).selectAll("rect").attr("transform", d3.zoomTransform(svg.node()));
                d3.select(this).selectAll("path").attr("transform", d3.zoomTransform(svg.node()));
                d3.select(this).selectAll("image").attr("transform", d3.zoomTransform(svg.node()));
            });
            svg.call(zoom);

        },
        // 页面按钮
        Promotion(id) {
            console.log(id)
            this.linkShow = '2'
            this.getSvg()
            
        },
        createRect() {
            const coordinate = [
                {
                    id: 'B1F_CW_8125_2',
                    x: '10835',
                    y: '14129',
                    width: '137',
                    height: '56',
                    fill: 'red',
                },


            ]
            for (let i of coordinate) {
                let divSFYX = document.createElement("rect")
                divSFYX.setAttribute('id', i.id)
                divSFYX.setAttribute('x', i.x)
                divSFYX.setAttribute('y', i.y)
                divSFYX.setAttribute('width', i.width)
                divSFYX.setAttribute('height', i.height)
                divSFYX.setAttribute('fill', i.fill)
                // divSFYX.style.transform = 'rotate(405deg)'
                this.svgDom.appendChild(divSFYX)
            }
            // let divSFYX = document.createElement("rect")
            // divSFYX.setAttribute('id', '6448')
            // divSFYX.setAttribute('x', '6008')
            // divSFYX.setAttribute('y', '6458')
            // divSFYX.setAttribute('width', '50')
            // divSFYX.setAttribute('height', '50')
            // divSFYX.setAttribute('fill', 'red')
            // divSFYX.setAttribute('stroke', 'red')
            // this.svgDom.appendChild(divSFYX)

        },
        touchstart(e) {
            console.log('按下', e.touches.length)
            if (e.touches.length > 0 && e.touches.length < 2) {
                //单指按下
                this.isTouch = true;
                const selectDom = e.currentTarget;
                const { pageX, pageY } = e.touches[0]; // 手指位置
                const offsetLeft = document.getElementById('svgcanvas').style.left
                const offsetTop = document.getElementById('svgcanvas').style.top
                // 手指原始位置
                this.oldMousePos = {
                    x: pageX,
                    y: pageY,
                };
                // 元素原始位置
                this.oldNodePos = {
                    x: offsetLeft == '' ? 0 : parseInt(offsetLeft.replace('px', '')),
                    y: offsetTop == '' ? 0 : parseInt(offsetTop.replace('px', '')),
                };
                // console.log(pageX, pageY, this.oldNodePos, '第一次点击的位置')
            } else {
                //双指按下
                const selectDom = e.currentTarget;
                const { pageX, pageY } = e.touches[0]; // 手指位置
                const { pageX2, pageY2 } = e.touches[1];//2
                // 手指原始位置
                this.oldMousePos = {
                    x: pageX,
                    y: pageY,
                };
                this.oldMousePos2 = {
                    x: pageX2,
                    y: pageY2,
                }
                let point1 = e.touches[0];
                let point2 = e.touches[1];
                let xLen = Math.abs(point2.pageX - point1.pageX);
                let yLen = Math.abs(point2.pageY - point1.pageY);
                let sqrtS = Math.sqrt(xLen * xLen + yLen * yLen)
                this.sqrt = sqrtS
                console.log(sqrtS, '点击的时候两个点的距离')
                // 元素原始位置
            }
        },
        touchMove(e) {
            console.log('拖到')
            //----
            const selectDom = e.currentTarget;
            // e.preventDefault(); // 取消事件的默认动作。
            // 移动操作
            if (e.touches.length === 1 && this.isTouch) {
                console.log('单指')
                const selectDom = e.currentTarget;
                const { pageX, pageY } = e.touches[0]; // 手指位置
                selectDom.style.left = `${pageX - this.oldMousePos.x + this.oldNodePos.x}px`
                selectDom.style.top = `${pageY - this.oldMousePos.y + this.oldNodePos.y}px`
                // console.log(pageX - this.oldMousePos.x, this.oldNodePos.x, '移动后的位置')
            } else {
                let point1 = e.touches[0];
                let point2 = e.touches[1];
                let xLen = Math.abs(point2.pageX - point1.pageX);
                let yLen = Math.abs(point2.pageY - point1.pageY);
                console.log(xLen, yLen, 'lianggdian')
                let sqrtS = Math.sqrt(xLen * xLen + yLen * yLen)
                console.log(sqrtS, '两个点的距离')
                this.num <= 1 ? this.num = 1 : this.num
                if (this.sqrt < sqrtS) {
                    this.num += 0.03
                    selectDom.style.transform = "scale(" + this.num + ")";
                } else {
                    this.num -= 0.03
                    selectDom.style.transform = "scale(" + this.num + ")";
                }
            }
        },
        touchEnd(ev) {
            console.log('松开')
            if (this.isTouch) {
                this.isTouch = false;
            }
        },
    },
    beforeDestroy() {
        this.svgDom = null;
    },
    watch: {
        photoResult: {
            handler(newVal, oldVal) {
                this.getSvg();
            },
            deep: true
        }
    }
};
</script>
<style scoped>
/* .back {
    width: 100vw;
    height: 100vh;
    position: fixed;
    left: 0;
    top: 0;
    z-index: 1;
    background: rgba(0, 0, 0, 0.2);
} */

#svgTemplate {
    z-index: 2;
    position: fixed;
    left: 0;
    top: 0;
}

.city {
    position: relative;
    min-width: 100vw;
    min-height: 100vh;
    color: white;
}

.home {}
</style>

实现了这个东西第一时间就发出来了,很苦恼这个东西

希望可以帮助 有这方面需求的小伙伴去解决

加油,今天周六我在 加班中~~~ 哦莫

哦对了 附在一个视频

移动端

还有个问题 H5在微信游览器 我缩放偶尔会 缩放网页 !!!

2023-3-8. 13:17
很好 解决了

 <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0,user-scalable=no"/>

meta标签加上这个

根页面加上 去监听限时 网页缩放 APP.vue

window.onload = function() {
    document.addEventListener('touchstart', function(e) {
      console.log("1手指",)
      if (e.touches.length > 1) {
        e.preventDefault()
      }
    })
    document.addEventListener('gesturestart', function(e) {
      console.log("2指")
      e.preventDefault()
    })
  }

此文章是手动实现的缩放效果不太友好,后面使用了一些库实现了,效果极佳

点击查看最新更新SVG缩放拖拽

GitHub 加速计划 / vu / vue
85
16
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:5 个月前 )
9e887079 [skip ci] 3 个月前
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 7 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐