微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用 SVG 元素的变换矩阵来计算目标坐标?

如何解决如何使用 SVG 元素的变换矩阵来计算目标坐标?

我怀疑有某种方法可以使用元素的变换矩阵来计算变换后的坐标,但我不知道该怎么做。

示例图最好地解释了这一点:


A circle with points A,B,and a rotation center. A is the reference/starting point. B is like point A,but with a rotation applied around the rotation center. (All of the above is in a containing SVG,which is much larger in all directions. No assumptions can be made that the circle’s left bounding box matches the root SVG’s bounding box.) A: I know the distance from the rotation center,as well as the exact x and y coordinates. B: I can get a transformation matrix via B.getCTM(),but its x and y coordinates remain identical to those of A. Using the transformation matrix from B,I need to determine the x and y coordinates after transformation. In other words,I need the ability to create an element that appears in the same spot as B,but with no transformations applied.


恐怕我没有走数学路线进入编程。我可以在某种程度上遵循转换矩阵正在做什么的表面级细节,但我的理解有点像能够一次读一个音符,而且速度非常慢;我不太了解更高层次的曲调,所以我不太了解完整乐句的声音——更不用说旋律了。

同样,我不明白变换矩阵是如何工作的。我曾尝试寻找对 grok 变换矩阵的解释,但我发现的所有内容都充满了更多我不明白的数学术语。我只知道它们的工作方式有点像函数,而且它们是非常灵活的工具,仅此而已。

SVGMatrix 可用的所有方法中(据说已弃用,支持 DOMMatrix,但 Firefox Dev.ed. 仍在使用 SVGMatrix),我不知道 {{1 }} 或 .inverse() 是我想要的,不知道如何从该矩阵中调出一组简单的 .multiply()x 坐标。

注意:

  • 我对在这里将屏幕坐标转换为 SVG 不感兴趣。
  • 我只关心 SVG(用户空间)坐标。

解决方法

您可以使用简单的三角变换:

const rotatePoint = (point,center,rotateAngle) => {
  const dx = point.x - center.x;
  const dy = point.y - center.y;
  const distance = Math.hypot(dx,dy);
  const currentAngle = Math.atan(dy / dx);
  const nextAngle = currentAngle - rotateAngle;
  const nextDX = distance * Math.cos(nextAngle);
  const nextDY = distance * Math.sin(nextAngle);
  return {x: center.x + nextDX,y: center.y + nextDY};
};

该片段显示蓝色点围绕红色点的旋转(逆时针旋转 30 / 90 / 123 度)

const rotatePoint = (point,angle) => {
    const dx = point.x - center.x;
  const dy = point.y - center.y;
  const distance = Math.hypot(dx,dy);
  const current = Math.atan(dy / dx);
  const next = current - angle;
  const nextDX = distance * Math.cos(next);
  const nextDY = distance * Math.sin(next);
  return {x: center.x + nextDX,y: center.y + nextDY};
};

const center = {x: 150,y: 150};
const start = {x: 200,y: 30};
const svg = d3.select('svg');

svg.append('circle')
    .attr('cx',center.x)
  .attr('cy',center.y)
  .attr('r',5)
  .style('fill','red');
svg.append('circle')
    .attr('cx',start.x)
  .attr('cy',start.y)
  .attr('r','blue');  

// Rotate 30 deg
const p30 = rotatePoint(start,Math.PI * 30 / 180); 
svg.append('circle')
    .attr('cx',p30.x)
  .attr('cy',p30.y)
  .attr('r','green');  
// Rotate 90 deg
const p90 = rotatePoint(start,Math.PI * 90 / 180); 
svg.append('circle')
    .attr('cx',p90.x)
  .attr('cy',p90.y)
  .attr('r','orange');
// Rotate 123 deg
const p123 = rotatePoint(start,Math.PI * 123 / 180); 
svg.append('circle')
    .attr('cx',p123.x)
  .attr('cy',p123.y)
  .attr('r','yellow');  
  
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="250" height="200"></svg>

,

一旦你有了一个 SVG 圆,

您可以使用标准的 getPointAtLengthgetTotalLength 函数计算圆上的任何 SVG 点。

只需注意圆圈开始绘制的位置(绿点)

pathLength 转换为度数:

<style>
  svg{ height:300px }
  text {
    font-size: 3px;
    fill: white;
    text-anchor: middle;
    dominant-baseline: middle;
  }
</style>
<svg id="SVG" viewBox="0 0 100 100">
  <circle cx="50%" cy="50%" r="50%" fill="pink"></circle>
  <circle id="CIRCLE" cx="50%" cy="50%" r="40%" 
          fill="none" stroke="black" stroke-dasharray="2"></circle>
  <circle cx="90%" cy="50%" r="5%" fill="green"></circle>
</svg>
<script>
  let circle_length = CIRCLE.getTotalLength();
  for (let degree = 0; degree < 360; degree += 45) {
    let len = degree * ( circle_length / 360 );
    let point = CIRCLE.getPointAtLength(len);
    let circle = document.createElementNS("http://www.w3.org/2000/svg","circle");
    circle.setAttribute("cx",point.x);
    circle.setAttribute("cy",point.y);
    circle.setAttribute("r","3%");
    circle.setAttribute("fill","blue");
    let text = document.createElementNS("http://www.w3.org/2000/svg","text");
    text.setAttribute("x",point.x);
    text.setAttribute("y",point.y);
    text.innerHTML = degree;
    SVG.append(circle,text)
  }
</script>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。