使用JS获取SVG中元素的绝对坐标

问题描述 投票:0回答:4

论坛用户好时光。我提前为我的英语道歉。我找不到答案(我决定去问英语观众)。

嵌套在组中的元素相对于父容器 () 的绝对定位(坐标)。

<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 对于 .

如何获得这些坐标? (最多可以无限嵌套组)。谢谢你的帮助。

enter image description here

javascript svg ecmascript-6
4个回答
7
投票
  1. 找到圆的
    cx
    cy
  2. 应用圆的任何变换
  3. 逐步找到每个祖先元素并应用找到的任何变换
  4. 到达根 SVG 元素时停止

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>


1
投票

获取孩子和父母的顶部和左侧并获得差异

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

将它们注册为捕获事件而不是冒泡事件

0
投票

我刚刚发现,您可以在 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);

0
投票

我想在 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
内部,您可以添加相对于其组的重叠元素(如果您有多个元素,这将消除大量计算)。

© www.soinside.com 2019 - 2024. All rights reserved.