svg 不同比例缩放后 拖拽事件的鼠标位置转换为svg图纸中的位置

摘要:
让我们尽量弄清楚下图中svg元素的宽度与浏览器的宽度不同,画布的宽度和高度也不同(1366*768)。然而,转换更容易,X/1366(画布的宽度)=100/1200(svg元素的宽度)。同样,点y在画布中的比例是相等的(如果红色点位于右下角,请考虑图1中的情况,这样您就可以获得红色点在画布中对应的位置。

说起来可能有点绕,下面尽可能的把我想表达的表述清楚吧

来看下下面这张图

svg 不同比例缩放后 拖拽事件的鼠标位置转换为svg图纸中的位置第1张

svg元素的宽度和浏览器的宽度是不一样的,事实上,还有一个宽度,那就是svg画布的宽度

为什么会有这么多不一样的宽度呢,直接浏览器的宽高就是svg标签的宽高,同时也设置同样的画布宽高,不就不用转换拖拽事件鼠标的坐标位置了吗?

是这么个道理,一开始我也是这么干的,可是后来发现,不同客户用不同的电脑、不同的浏览器,会有不同的宽高,如果一个用户在1366*768的环境下设置好了一张画布,那么这个画布就得按照1366*768的尺寸来设置画布的宽高,但是当另一个用户来修改这张画布的内容时,他的浏览器宽高可能是1200*600,宽高比例不一样的话就会出现上图中的样子,或者是直接让svg变形填充,像下图这样:

svg 不同比例缩放后 拖拽事件的鼠标位置转换为svg图纸中的位置第2张

 图形好像都扁了一点点,好像也不影响观看,但是事实上也只是svg元素的宽高和浏览器的宽高相等了(1200*600),画布的宽高是不一样的(1366*768)

不过这种情况转换还是好计算些的,只要拿两个宽高的比例来计算下就行,逻辑见下图的分析

svg 不同比例缩放后 拖拽事件的鼠标位置转换为svg图纸中的位置第3张

 如果鼠标拖拽到100,150的地方后,直接在画布里100,150的地方放置图像,那么就会发现与我拖拽的位置是不一致的,有偏移,这样的体验效果是不好的,该如何计算呢?

可见想要求的x和y有这样的公式:

x / 1366(画布的宽度) = 100 / 1200 (svg元素的宽度)

同样 : y / 768 = 150 / 600

什么意思呢,就是浏览器中100,150这个点在浏览器中的比例,应该是与x, y这个点在画布中的比例是相等的(想一想如果这个红色的点在最右下角,就能理解这个等比了),这样就能获取红色点对应在画布中的位置

更复杂的情况就是图1中的情况,svg元素的宽度(elementW)、浏览器的宽度(HtmlWi)、svg画布的宽度(W)都不一样(当然也有可能是高度都不一样,具体要看原来的尺寸后来的客户的尺寸的差别)

可以发现 elementW 比 HtmlWi 小,两边都有留出空的区域,暂且称这个宽度为 gapX, 见下图:

svg 不同比例缩放后 拖拽事件的鼠标位置转换为svg图纸中的位置第4张

 当鼠标处于页面上的某一个位置时(比如100,150),那么这个点在svg标签上的位置,y 是相同的(150),但是 x 小一些,x 是 100 减去 gapX 后的值,见下图:

svg 不同比例缩放后 拖拽事件的鼠标位置转换为svg图纸中的位置第5张

 然后这个100 - gapX 同样满足 x / W(画布的宽度) = (100 - gapX) / elementW(svg元素的宽度)

这样看来好像也并不复杂了,下面贴代码

    var elementW = W * HtmlHe / H; // 元素的宽高是自适应的,需要根据页面的宽高和画布的宽高来计算出来
    if (elementW < HtmlWi) { // 只有当元素的宽高小于页面的宽高时,才需要计算gap的值
        var gapX = (HtmlWi - elementW) / 2;
        SvgX = (e) => {
            if (MyPreserveAspectRatio == "") { // 不为空的话,是全屏显示,图形会被拉伸,也就不涉及gap值的处理了
                return (e.clientX - gapX) * W / elementW;
            } else {
                return e.clientX * W / HtmlWi;
            }
        };
    }

 同样,当高度不一样时,也是需要处理 y 的值的:

    var elementH = H * HtmlWi / W;
    if (elementH < HtmlHe) {
        var gapY = (HtmlHe - elementH) / 2;
        SvgY = (e) => {
            if (MyPreserveAspectRatio == "") {
                return (e.clientY - gapY) * H / elementH;
            } else {
                return e.clientY * H / HtmlHe;
            }
        };
    }

 到此就结束了

免责声明:文章转载自《svg 不同比例缩放后 拖拽事件的鼠标位置转换为svg图纸中的位置》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇JSON-RPC轻量级远程调用协议介绍及使用.deb文件打包下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C# TimeSpan 时间计算

本文告诉大家简单的方法进行时间计算 实际上使用 TimeSpan 可以做到让代码比较好懂,而代码很简单。 例如我使用下面的代码表示 5 秒 const int needCount = 5 * 1000; 因为后面使用的是延迟,延迟的代码很简单 Task.Delay(needCount) 这时传入的是一个毫秒,但是很多小伙伴问,为什么是 5*1000 表...

项目管理系统 TAIGA 部署

题记 使用了 MantisBT 一段时间,觉得功能太少,只局限在错误跟踪,而且操作体验比较差,界面很糟糕,很早就想将其换掉。 偶然发现一个很不错的新选择:Taiga,于是就试着将其部署下来,发现绝对是一个好东西,对于实践 Scrum 项目管理方法的,更是不可多得的利器! 产品官网:https://taiga.io/ GITHUB:https://githu...

RabbitMQ 发布/订阅

  我们会做一些改变,就是把一个消息发给多个消费者,这种模式称之为发布/订阅(类似观察者模式)。       为了验证这种模式,我们准备构建一个简单的日志系统。这个系统包含两类程序,一类程序发动日志,另一类程序接收和处理日志。       在我们的日志系统中,每一个运行的接收者程序都会收到日志。然后我们实现,一个接收者将接收到的数据写到硬盘上,与此同时,另...

撩课-Web大前端每天5道面试题-Day4

1. 如何实现瀑布流? 瀑布流布局的原理: 1) 瀑布流布局要求要进行布置的元素等宽, 然后计算元素的宽度, 与浏览器宽度之比,得到需要布置的列数; 2) 创建一个数组,长度为列数, 里面的值为已布置元素的总高度(最开始为0); 3) 然后将未布置的元素依次布置到高度最小的那一列, 就得到了瀑布流布局; 4) 滚动加...

JDK自带方法实现AES对称加密

请看代码。 1 package jdbc.pro.lin; 2 3 import java.security.InvalidAlgorithmParameterException; 4 import java.security.InvalidKeyException; 5 import java.security.NoS...

使用多线程时,传递 request 对象丢失

1.原因描述 我们在工作中遇到耗时的一些操作时我们会使用多线程或者mq来解决以便提高程序的响应速度。但是使用多线程时遇到一个问题,我单独开一个线程去进行其他逻辑处理时,在发送消息之前(未开启多线程时)我们是可以获取到 request 信息的,但是在新开的线程中确是无法获取到 request 信息(request is  null)。 2.代码演示 主线程代...