SVG上的倍数转换矩阵,获取光标点

时间:2019-06-18 00:34:56

标签: javascript svg matrix css-transforms cartesian-coordinates

这个问题可能与 svg 本身有关的数学更多。

在主svg中,通过viewBox属性(来自不同事件)将svg转换为多个。

在这些svg中,其他元素分组在g中,并使用matrix transformations进行了修改。

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

目标可能是绘制一个点或获得一个相关的点,作为一个曲线图。

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

这对一个转换水平有效吗?

如何链接倍数矩阵变换?

1 个答案:

答案 0 :(得分:1)

如果要相对于变换区域的点,则应应该反映为它们相应的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>

如果您希望转换任意值,请使用this Answer中描述的技术,该技术包括在元素上分派此类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>

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