论坛用户好时光。我提前为我的英语道歉。我找不到答案(我决定去问英语观众)。
嵌套在组中的元素相对于父容器 () 的绝对定位(坐标)。
<svg width="100%" height="100%" viewBox="0 0 1000 1000" preserveAspectRatio="xMidYMin slice" x="0" y="0" tabindex="1">
<g transform="translate(100 100)">
<g transform="translate(100 100)">
<circle r="50" cx="25" cy="25" fill="yellow" />
</g>
</g>
<svg>
我想使用 ES6 + 相对于 SVG 的圆坐标。即 x = 100 + 100 + 25,y = 100 + 100 + 25 对于 .
如何获得这些坐标? (最多可以无限嵌套组)。谢谢你的帮助。
cx
和 cy
值function getCirclePosition(circleElemId)
{
var elem = document.getElementById(circleElemId);
var svg = elem.ownerSVGElement;
// Get the cx and cy coordinates
var pt = svg.createSVGPoint();
pt.x = elem.cx.baseVal.value;
pt.y = elem.cy.baseVal.value;
while (true)
{
// Get this elements transform
var transform = elem.transform.baseVal.consolidate();
// If it has a transform, then apply it to our point
if (transform) {
var matrix = elem.transform.baseVal.consolidate().matrix;
pt = pt.matrixTransform(matrix);
}
// If this element's parent is the root SVG element, then stop
if (elem.parentNode == svg)
break;
// Otherwise step up to the parent element and repeat the process
elem = elem.parentNode;
}
return pt;
}
var pos = getCirclePosition("thecircle");
console.log("Coordinates are: " + pos.x + "," + pos.y);
<svg width="100%" height="100%" viewBox="0 0 1000 1000" preserveAspectRatio="xMidYMin slice" x="0" y="0" tabindex="1">
<g transform="translate(100 100)">
<g transform="translate(100 100)">
<circle id="thecircle" r="50" cx="25" cy="25" fill="yellow" />
</g>
</g>
<svg>
更新
正如@Vad0k指出的,有一个更简单但不太准确的方法,可以用来代替:
function getCirclePosition(circleElemId)
{
var elem = document.getElementById(circleElemId);
var svg = elem.ownerSVGElement;
// Get the cx and cy coordinates
var pt = svg.createSVGPoint();
pt.x = elem.cx.baseVal.value;
pt.y = elem.cy.baseVal.value;
return pt.matrixTransform(getTransformToElement(elem, svg));
}
function getTransformToElement(fromElement, toElement) {
return toElement.getCTM().inverse().multiply(fromElement.getCTM());
};
var pos = getCirclePosition("thecircle");
console.log("Coordinates are: " + pos.x + "," + pos.y);
<svg width="100%" height="100%" viewBox="0 0 1000 1000" preserveAspectRatio="xMidYMin slice" x="0" y="0" tabindex="1">
<g transform="translate(100 100)">
<g transform="translate(100 100)">
<circle id="thecircle" r="50" cx="25" cy="25" fill="yellow" />
</g>
</g>
<svg>
获取孩子和父母的顶部和左侧并获得差异
const circleLeft = circleElement.getBoundingRect().offsetLeft
const circleTop = circleElement.getBoundingRect().top
const parentLeft = circleElement.parentElement.getBoundingRect().offsetLeft
const parentTop = circleElement.parentElement.getBoundingRect().top
const changeInX = parentLeft - cirleLeft
const changeInY = parentTop - circleTop
如果要在此元素上注册事件,请通过将
true
作为第三个参数传递给 addEventListener
将它们注册为捕获事件而不是冒泡事件
我刚刚发现,您可以在 SVG 元素上使用 getBBox() 来获取其可见矩形。
var rect = document.getElementById("myrect");
var visibleRect = rect.getBBox();
console.log("x=" + visibleRect.x + ", y=" + visibleRect.y + ", width=" + visibleRect.width + ", height=" + visibleRect.height);
我想在 Paul LeBeau 的出色回答中附加一个更通用的方法(不仅适用于 SVGCircle),并且还考虑到可能的旋转(如果您需要知道角而不是中心,则需要特殊处理):
export interface AbsolutePosition {
x: number
y: number
}
export function getAbsoluteCenterSVG(element: SVGGraphicsElement): AbsolutePosition {
const svgRoot = element.ownerSVGElement!;
const center = svgRoot.createSVGPoint();
center.x = element.getBBox().x + element.getBBox().width / 2;
center.y = element.getBBox().y + element.getBBox().height / 2;
const result = center.matrixTransform(getTransformToElement(element, svgRoot));
return {
x: result.x,
y: result.y,
};
}
export function getAbsoluteTopLeftPositionSVG(element: SVGGraphicsElement): AbsolutePosition {
const corners = getAbsoluteDiagonalCorners(element);
return {
x: Math.min(corners[0].x, corners[1].x),
y: Math.min(corners[0].y, corners[1].y),
};
}
export function getAbsoluteTopRightPositionSVG(element: SVGGraphicsElement): AbsolutePosition {
const corners = getAbsoluteDiagonalCorners(element);
return {
x: Math.max(corners[0].x, corners[1].x),
y: Math.min(corners[0].y, corners[1].y),
};
}
function getAbsoluteDiagonalCorners(element: SVGGraphicsElement): AbsolutePosition[] {
const svgRoot = element.ownerSVGElement!;
const bbox = element.getBBox();
const topLeft = svgRoot.createSVGPoint();
topLeft.x = bbox.x;
topLeft.y = bbox.y;
const bottomRight = svgRoot.createSVGPoint();
bottomRight.x = bbox.x + bbox.width;
bottomRight.y = bbox.y + bbox.height;
const transformMatrix = getTransformToElement(element, svgRoot);
return [topLeft.matrixTransform(transformMatrix), bottomRight.matrixTransform(transformMatrix)];
}
export function getTransformToElement(fromElement: SVGGraphicsElement, toElement: SVGGraphicsElement) {
return toElement.getCTM()!.inverse().multiply(fromElement.getCTM()!);
}
使用这些方法,您可以执行以下操作:
const absolutePosition = getAbsoluteTopRightPositionSVG(targetDOMElement);
如果您想要/需要在此位置添加新的 SVG 元素:
const absolutePosition = getAbsoluteTopRightPositionSVG(targetDOMElement);
const newElementGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
newElementGroup.setAttribute("transform", `translate(${absolutePosition.x}, ${absolutePosition.y})`);
targetDOMElement.ownerSVGElement.appendChild(newElementGroup);
然后,在
newElementGroup
内部,您可以添加相对于其组的重叠元素(如果您有多个元素,这将消除大量计算)。