首页 如何把鼠标坐标转换成svg内部坐标
文章
取消

如何把鼠标坐标转换成svg内部坐标

1. 概述

最近在工作中碰到了一个问题,当 svg 的父元素存在 transform 属性(旋转、缩放、平移或倾斜)时,如何把当前鼠标所在的坐标转换成 svg 内部坐标。这个问题在 stackoverflow 中得到了解答。

同时也发现了在 firefox 中存在 BUG ,因为 svg.getScreenCTM() 并没有计入 svg 父元素的 transform 。这个 BUG 于 2020 年在 bugzilla.mozilla.org 中就被提出来了,目前仍未修复。

不过可以把 transform 属性放在 svg 元素上来暂时规避上述 BUG 。

2. 如何把鼠标坐标转换成svg内部坐标

  1. 获取 SVG 元素:
    1
    
    var svg = document.querySelector('svg');
    
  2. 创建 SVGPoint ,稍后会用到其 matrixTransform 方法:
    1
    
    var pt = svg.createSVGPoint();
    
  3. 计算鼠标位置在 SVG 元素内对应的坐标:
    1
    2
    3
    4
    
    function cursorPoint(evt){
      pt.x = evt.clientX; pt.y = evt.clientY;
      return pt.matrixTransform(svg.getScreenCTM().inverse());
    }
    

    其中:

    • svg.getScreenCTM() 返回一个 DOMMatrix,代表将当前 svg 元素的坐标系转换为 SVG 文档片段的 SVG 视口坐标系的矩阵。
    • DOMMatrix.inverse() 返回一个该矩阵的逆矩阵。
    • pt.matrixTransform() 将在 pt 对象上应用一个指定的矩阵变换。
  4. 在 svg 元素上监听 mousemove 并调用 cursorPoint 方法:
    1
    2
    3
    4
    
    svg.addEventListener('mousemove',function(evt) {
      var loc = cursorPoint(evt);
      // Use loc.x and loc.y here
    }, false);
    

3. Demo

3.1 SVG 父元素没有 transform 属性

下方 demo 中 svg 父元素(div)没有 transform 属性。在 chrome 和 firefox 中均正常:SVG 中的黑点会跟随鼠标移动。

3.2 SVG 父元素有 transform 属性

下方 demo 中 svg 父元素(div)有 transform 属性 transform: translate(100px, 100px);。在 firefox 中不正常:SVG 中的黑点会跟随鼠标移动,但是黑点在鼠标右下方 100px 处

3.2 SVG 元素有 transform 属性

下方 demo 中 svg 元素有 transform 属性 transform: translate(100px, 100px);。在 chrome 和 firefox 中均正常。

本文由作者按照 CC BY 4.0 进行授权