如何使用 SVG 元素的变换矩阵来计算目标坐标?
How can I use an SVG element’s transformation matrix to calculate destination coordinates?
我怀疑有某种方法可以使用元素的变换矩阵来计算变换后的坐标,但我不知道该怎么做。
示例图对此进行了最好的解释:
恐怕我没有走数学路线进入编程。我可以在某种程度上了解转换矩阵正在做什么的表面细节,但我的理解有点像能够一次读一个音符,而且速度非常慢;高层次的旋律我不是很懂,所以一个完整乐句的声音我不是很懂,更别提旋律了。
同样,我不明白变换矩阵是如何工作的。我曾尝试搜索 grok 变换矩阵的解释,但我发现的所有内容都充满了我不理解的 more 数学术语。我只知道它们的工作方式有点像函数,而且它们是非常灵活的工具,但仅此而已。
在 SVGMatrix
可用的所有方法中(据说已弃用 DOMMatrix
,但 Firefox Dev.ed. 仍在使用 SVGMatrix
),我不知道是否 .inverse()
或 .multiply()
是我想要的,不知道如何从该矩阵中提取一组简单的 x
和 y
坐标。
注:
- 我对在此处将屏幕坐标转换为 SVG 坐标不感兴趣。
- 我只关心 SVG(用户-space)坐标。
您可以使用简单的三角变换:
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, center, 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', 5)
.style('fill', 'blue');
// Rotate 30 deg
const p30 = rotatePoint(start, center, Math.PI * 30 / 180);
svg.append('circle')
.attr('cx', p30.x)
.attr('cy', p30.y)
.attr('r', 5)
.style('fill', 'green');
// Rotate 90 deg
const p90 = rotatePoint(start, center, Math.PI * 90 / 180);
svg.append('circle')
.attr('cx', p90.x)
.attr('cy', p90.y)
.attr('r', 5)
.style('fill', 'orange');
// Rotate 123 deg
const p123 = rotatePoint(start, center, Math.PI * 123 / 180);
svg.append('circle')
.attr('cx', p123.x)
.attr('cy', p123.y)
.attr('r', 5)
.style('fill', 'yellow');
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="250" height="200"></svg>
一旦你有了一个 SVG 圆圈,
您可以使用标准 getPointAtLength
和 getTotalLength
函数计算圆上的任何 SVG 点。
请注意圆 开始的位置 绘图(绿点)
路径长度转换为度数:
<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 { x , y } = CIRCLE.getPointAtLength( degree * ( circle_length / 360 ) );
let group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.innerHTML = `<circle cx="${x}" cy="${y}" r="3%" fill="blue"/>` +
`<text x="${x}" y="${y}">${degree}</text>`;
SVG.append(group)
}
</script>
我怀疑有某种方法可以使用元素的变换矩阵来计算变换后的坐标,但我不知道该怎么做。
示例图对此进行了最好的解释:
恐怕我没有走数学路线进入编程。我可以在某种程度上了解转换矩阵正在做什么的表面细节,但我的理解有点像能够一次读一个音符,而且速度非常慢;高层次的旋律我不是很懂,所以一个完整乐句的声音我不是很懂,更别提旋律了。
同样,我不明白变换矩阵是如何工作的。我曾尝试搜索 grok 变换矩阵的解释,但我发现的所有内容都充满了我不理解的 more 数学术语。我只知道它们的工作方式有点像函数,而且它们是非常灵活的工具,但仅此而已。
在 SVGMatrix
可用的所有方法中(据说已弃用 DOMMatrix
,但 Firefox Dev.ed. 仍在使用 SVGMatrix
),我不知道是否 .inverse()
或 .multiply()
是我想要的,不知道如何从该矩阵中提取一组简单的 x
和 y
坐标。
注:
- 我对在此处将屏幕坐标转换为 SVG 坐标不感兴趣。
- 我只关心 SVG(用户-space)坐标。
您可以使用简单的三角变换:
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, center, 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', 5)
.style('fill', 'blue');
// Rotate 30 deg
const p30 = rotatePoint(start, center, Math.PI * 30 / 180);
svg.append('circle')
.attr('cx', p30.x)
.attr('cy', p30.y)
.attr('r', 5)
.style('fill', 'green');
// Rotate 90 deg
const p90 = rotatePoint(start, center, Math.PI * 90 / 180);
svg.append('circle')
.attr('cx', p90.x)
.attr('cy', p90.y)
.attr('r', 5)
.style('fill', 'orange');
// Rotate 123 deg
const p123 = rotatePoint(start, center, Math.PI * 123 / 180);
svg.append('circle')
.attr('cx', p123.x)
.attr('cy', p123.y)
.attr('r', 5)
.style('fill', 'yellow');
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="250" height="200"></svg>
一旦你有了一个 SVG 圆圈,
您可以使用标准 getPointAtLength
和 getTotalLength
函数计算圆上的任何 SVG 点。
请注意圆 开始的位置 绘图(绿点)
路径长度转换为度数:
<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 { x , y } = CIRCLE.getPointAtLength( degree * ( circle_length / 360 ) );
let group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.innerHTML = `<circle cx="${x}" cy="${y}" r="3%" fill="blue"/>` +
`<text x="${x}" y="${y}">${degree}</text>`;
SVG.append(group)
}
</script>