svg - 将一个 svg 元素居中于另一个元素时的比例关系
问题描述
我编写了这些函数以将一个 svg 元素居中于另一个元素中:
import { Matrix, translate } from 'transformation-matrix';
export const getElementCenter = (element: SVGGraphicsElement) => {
const bBox = element.getBBox();
return { x: bBox.x + bBox.width / 2, y: bBox.y + bBox.height / 2 };
};
export const centerElementInOther = (
element: SVGGraphicsElement,
other: SVGGraphicsElement,
scaleFactor: number = 1
): Matrix => {
const elementCentre = getElementCenter(element);
const otherCentre = getElementCenter(other);
const x = elementCentre.x - otherCentre.x;
const y = elementCentre.y - otherCentre.y;
// how can I work out the scaleFactor? If it the actual scale is 0.5 then I need to divide by 2 but if it is 1 then I need to divide by 1
return translate(-x / scaleFactor, -y / scaleFactor);
};
除非元素被缩放,否则一切正常,然后我需要应用一些数学,但我不明白这个比例。
一切正常,直到我将元素的比例更改为 0.5,然后我不得不将中心 x 和中心 y 除以 2。
解决方案
我很想看到 SVG 代码。
将 svg 元素置于另一个已转换元素中的一种方法是将两个元素包装在 a 中<g>
并将转换应用于组,如下所示:
const bBox1 = theRect1.getBBox();
c1.setAttributeNS(null,"cx",bBox1.x + bBox1.width / 2)
c1.setAttributeNS(null,"cy",bBox1.y + bBox1.height / 2);
svg{border:1px solid;}
<svg viewBox="0 0 200 100">
<g transform="scale(.5,.5) translate(150,50) rotate(30,30,10)">
<rect id="theRect1" x="30" y="10" width="80" height="40" />
<circle id="c1" r="2" fill="red" />
</g>
</svg>
如果无法将元素包装在一个组中,则可以对要居中的元素应用相同的转换
const bBox2 = theRect2.getBBox();
// get the transformation applied to the rect
let theTransformation = theRect2.getAttribute("transform")
c2.setAttributeNS(null,"cx",bBox2.x + bBox2.width / 2)
c2.setAttributeNS(null,"cy",bBox2.y + bBox2.height / 2);
//apply the same transformation to the circle
c2.setAttributeNS(null,"transform",theTransformation)
svg{border:1px solid;}
<svg viewBox="0 0 200 100">
<rect id="theRect2" x="30" y="10" width="80" height="40" transform="scale(.5,.5) translate(150,50) rotate(30,30,10)" />
<circle id="c2" r="2" fill="red" />
</svg>
如果您只想缩小 rect 而不是圆圈,您可以将圆圈包裹在 group<g>
中,使用 group 并将圆圈放大适当的数量:
const bBox3 = theRect3.getBBox();
// get the transformation applied to the rect
let theTransformation = theRect3.getAttribute("transform");
// get the scale applied
let scaleRy = theTransformation
.split("scale(")[1]
.split(")")[0]
.split(","); //[".5", ".5"]
//calculate the circle's scale
let circleScale = `scale(${1 / Number(scaleRy[0])}, ${1 / Number(scaleRy[1])})`;
theUse.setAttributeNS(null, "x", bBox3.x + bBox3.width / 2);
theUse.setAttributeNS(null, "y", bBox3.y + bBox3.height / 2);
//apply the same transformation to the circle
theUse.setAttributeNS(null, "transform", theTransformation);
//scale the circle
c3.setAttributeNS(null, "transform", circleScale);
svg{border:1px solid;}
<svg viewBox="0 0 200 100">
<defs>
<g id="cWrap">
<circle id="c3" r="2" fill="red" transform="scale(2,2)" ></circle>
</g>
</defs>
<rect id="theRect3" x="30" y="10" width="80" height="40" transform="scale(.5,.5) translate(150,50) rotate(30,30,10)" />
<use id="theUse" xlink:href="#cWrap" />
</svg>
推荐阅读
- docker - 为什么dockerfile中的CMD命令没有运行?
- java - 使用 ENUM 中定义的返回类型的 GSON 反序列化
- highcharts - Highchart - 柱形图在导出 api 中不正确作为图像
- javascript - 按下提交按钮时如何防止 React 回发
- angular - 使用 Angular 的自定义过滤器
- pandas - 通过连接 subid 值和其他列名从分组行展开/创建 pandas 列
- python - 在 Python 中使用 VLOOKUP 和合并
- python - Fetching data after a certain time interval(10 sec) from a continuously increasing database like mysql using flask
- swift - SwiftUI PresentationButton 无法构建 - 调用中的参数 #1 缺少参数
- javascript - 上传多张图片时如何获得响应