首页 > 解决方案 > SVG上的倍数变换矩阵,获取光标点

问题描述

这个问题可能与数学有关,而不是svg本身。

在主 svg 中,通过viewBox属性获得了多个转换后的 svg(来自不同的事件)。

在这些 svg 中,其他元素被分组在 a 中g,使用矩阵转换进行修改。

如何获取鼠标指针变换后的元素上的点。

目标可以是绘制一个点或获取相关点,作为图表。

let point = document.getElementById("main").createSVGPoint();

// The mouse cursor points
point.x = 180
point.y = 63
mouse = point.matrixTransform(sub.getCTM())

// console.log(mouse)
// Output 
//  "x": 611.75439453125,
//  "y": 68.71578979492188


// Testing:
circle.setAttribute("cx", 611.75439453125)
circle.setAttribute("cy", 68.71578979492188)
// Not working
<!-- Parent svg -->
<!-- Not preserving aspect ratios -->
<svg id="main" viewBox="0 0 300 400">

  <!-- Includes others svg, transformed with a viewBox -->
  <!-- Not preserving aspect ratios -->
  <svg id="group1" viewBox="7 54 10 570">
       
      <!-- Group element modified with a matrix -->
      <!-- Using css to define the matrix behave identicaly -->
      <!-- All elements in this group are transformed by this matrix -->
      <g id="sub" transform="matrix(4.5,0,0,0.84,-140,99)">
        
        <!-- Exemple element in group -->
        <polyline points="4 65.94338623003772 5 78 6 50.10565885410098 7 40.95007190251531 8 53.698867220021675 9 49.43265131064406 10 44.36112722960851 11 56.329540580770356 12 49.785452985846554 13 44.10803037565898 14 40.537830814642945 15 41.84933269419995 16 38.33857254585345 17 43.590332265307744 18 49.16421525342487 19 49.49017332290519 20 42.51658803643061 21 46.943865580139814 22 36.27544970608283 23 38.070136488634255 24 43.46186643792423 25 42.20788657062835 26 48.37424628503659 27 25.58210762671243 28 23.927391073996347 29 22.349370537628886 30 30.592274894669004 31 21.97356005752208 32 24.960869894290738 33 23.221787723591348 34 17.41781668642936 35 2 36 19.335217095138404 37 39.60405681560149 38 38.49579937936788 39 32.47132729520408 40 25.016474506143126 41 27.037414536922626 42 27.541690844412955 43 20.37253071624997 44 9.872846078159213 45 17.79362716653617 46 13.107500567651172 47 24.955117693064494 48 24.247596942250766 49 19.728284178923616 50 11.341574791230315 51 8.248807931982782 52 10.697328253903962 " ></polyline>
   
        <!-- This circle should be at the cursor -->
        <circle id="circle" cx="50" cy="50" r="50"fill="blue">

      </g>
      
  </svg>

   <!-- Rectangles symbolizing the mouse cursor -->
   <rect width="1000" height="1" x="0" y="63" ></rect>
   <rect width="1" height="500" x="180" y="0"></rect>
   
</svg>

Svg 有许多与变换相关的绑定,我们可以使用 getCTM() 和getBBox()检索每个元素的变换矩阵,并使用matrixTransform

这适用于一级转换?

如何链接多个矩阵变换?

标签: javascriptsvgmatrixcss-transformscartesian-coordinates

解决方案


如果您想要相对于转换区域的点,那么它应该反映为它们相应 MouseEvents 的offsetXoffsetY属性。

但是,Webkit / Blink 浏览器中似乎存在这方面的错误,所以这实际上只适用于 Firefox (也许是 IE?)......

const poly = document.querySelector('polyline');
poly.addEventListener('mousemove', evt => {
  circle.setAttribute("cx", evt.offsetX + 2.5);
  circle.setAttribute("cy", evt.offsetY + 2.5);
});
<!-- Parent svg -->
<!-- Not preserving aspect ratios -->
<svg id="main" viewBox="0 0 300 400">

  <!-- Includes others svg, transformed with a viewBox -->
  <!-- Not preserving aspect ratios -->
  <svg id="group1" viewBox="7 54 10 570">
       
      <!-- Group element modified with a matrix -->
      <!-- Using css to define the matrix behave identicaly -->
      <!-- All elements in this group are transformed by this matrix -->
      <g id="sub" transform="matrix(4.5,0,0,0.84,-140,99)">
        
        <!-- Exemple element in group -->
        <polyline points="4 65.94338623003772 5 78 6 50.10565885410098 7 40.95007190251531 8 53.698867220021675 9 49.43265131064406 10 44.36112722960851 11 56.329540580770356 12 49.785452985846554 13 44.10803037565898 14 40.537830814642945 15 41.84933269419995 16 38.33857254585345 17 43.590332265307744 18 49.16421525342487 19 49.49017332290519 20 42.51658803643061 21 46.943865580139814 22 36.27544970608283 23 38.070136488634255 24 43.46186643792423 25 42.20788657062835 26 48.37424628503659 27 25.58210762671243 28 23.927391073996347 29 22.349370537628886 30 30.592274894669004 31 21.97356005752208 32 24.960869894290738 33 23.221787723591348 34 17.41781668642936 35 2 36 19.335217095138404 37 39.60405681560149 38 38.49579937936788 39 32.47132729520408 40 25.016474506143126 41 27.037414536922626 42 27.541690844412955 43 20.37253071624997 44 9.872846078159213 45 17.79362716653617 46 13.107500567651172 47 24.955117693064494 48 24.247596942250766 49 19.728284178923616 50 11.341574791230315 51 8.248807931982782 52 10.697328253903962 " ></polyline>
   
        <!-- This circle should be at the cursor -->
        <circle id="circle" cx="5" cy="5" r="5" fill="blue" pointer-events="none">

      </g>
      
  </svg>

   <!-- Rectangles symbolizing the mouse cursor -->
   <rect width="1000" height="1" x="0" y="63" ></rect>
   <rect width="1" height="500" x="180" y="0"></rect>
   
</svg>

如果您希望转换任意值,那么您可以使用此答案中描述的技术,该技术包括在您的元素上调度这样的 MouseEvent:

const point = {x:180, y:63};
const poly = document.querySelector('polyline');
poly.addEventListener('mousemove', evt => {
  point.x = evt.offsetX;
  point.y = evt.offsetY;
}, {once: true});
const evt = new MouseEvent('mousemove', {
  clientX: point.x, 
  clientY: point.y
});
poly.dispatchEvent(evt);
console.log(point);
circle.setAttribute("cx",  point.x);
circle.setAttribute("cy", point.y);
<!-- Parent svg -->
<!-- Not preserving aspect ratios -->
<svg id="main" viewBox="0 0 300 400">

  <!-- Includes others svg, transformed with a viewBox -->
  <!-- Not preserving aspect ratios -->
  <svg id="group1" viewBox="7 54 10 570">
       
      <!-- Group element modified with a matrix -->
      <!-- Using css to define the matrix behave identicaly -->
      <!-- All elements in this group are transformed by this matrix -->
      <g id="sub" transform="matrix(4.5,0,0,0.84,-140,99)">
        
        <!-- Exemple element in group -->
        <polyline points="4 65.94338623003772 5 78 6 50.10565885410098 7 40.95007190251531 8 53.698867220021675 9 49.43265131064406 10 44.36112722960851 11 56.329540580770356 12 49.785452985846554 13 44.10803037565898 14 40.537830814642945 15 41.84933269419995 16 38.33857254585345 17 43.590332265307744 18 49.16421525342487 19 49.49017332290519 20 42.51658803643061 21 46.943865580139814 22 36.27544970608283 23 38.070136488634255 24 43.46186643792423 25 42.20788657062835 26 48.37424628503659 27 25.58210762671243 28 23.927391073996347 29 22.349370537628886 30 30.592274894669004 31 21.97356005752208 32 24.960869894290738 33 23.221787723591348 34 17.41781668642936 35 2 36 19.335217095138404 37 39.60405681560149 38 38.49579937936788 39 32.47132729520408 40 25.016474506143126 41 27.037414536922626 42 27.541690844412955 43 20.37253071624997 44 9.872846078159213 45 17.79362716653617 46 13.107500567651172 47 24.955117693064494 48 24.247596942250766 49 19.728284178923616 50 11.341574791230315 51 8.248807931982782 52 10.697328253903962 " ></polyline>
   
        <!-- This circle should be at the cursor -->
        <circle id="circle" cx="5" cy="5" r="5" fill="blue" pointer-events="none">

      </g>
      
  </svg>

   <!-- Rectangles symbolizing the mouse cursor -->
   <rect width="1000" height="1" x="0" y="63" ></rect>
   <rect width="1" height="500" x="180" y="0"></rect>
   
</svg>

请注意,WebKit / Blink 确实在 HTML 元素上正确设置了它,如本 Q/A ...


推荐阅读