我有一个项目,我正在将一些数据可视化为包含RECT元素的SVG元素. 因此,我想要做的是在SVG的特定RECT元素上添加一个标签,为此,我必须获得RECT元素的位置,以便将标签放置在这个位置.

因此,为了实现这一点,我首先通过使用getBorbingClientRect()javascrip方法来获得SVG位置,然后使用相同的方法来获得RECT元素位置.

之后,我得到了SVG和RECT元素的位置之差,我得到的值是要放置标签的位置.

这是代码,以便获得每个元素的位置,然后计算标签的新位置.

父项ID参数是SVG元素的ID,而子ID参数是RECT元素的ID

function getElemementRelativePosition(parentId, childId) {
    var parentPos = document.getElementById(parentId).getBoundingClientRect();
    var childPos = document.getElementById(childId).getBoundingClientRect();
    var relativePos = {};

    relativePos.top = childPos.top - parentPos.top;
    relativePos.right = childPos.right - parentPos.right;
    relativePos.bottom = childPos.bottom - parentPos.bottom;
    relativePos.left = childPos.left - parentPos.left;

    return relativePos;
}

GetElemementRelativePosition函数为标签返回正确的值,但问题是标签的占位符在其初始位置保持粘滞,因此即使我更改了它的位置,标签的高度也会将SVG元素向下推.

包含标签的div元素具有以下属性

<div style="position:relative;z-index:10;top:@ relativePos.top; left:@ relativePos.left;">
MyLabel
</div>

对于如何在不移动SVG的情况下实现这一点,有什么建议吗?

提前谢谢!

推荐答案

正如@Maciek所指出的:您可以将SVG和Label都包装在一个带有position:relative的div中,然后将position:absolute应用于您的SVG和Label.

Alternative: svg <text> labels

If you need only simple single-line labels – <text> has some advantages: You just need to get the center x and y coordinates of the <rect> element.
By applying text-anchor:middle and dominant-baseline:middle the text will be vertically and horizontally centered relative to the rect's center.

You get the center coordinates using getBBox() method (similar to getBoundingClientRect() - but specifically for svg elements).
A simple label helper might look like this:

function setSvgLabelPos(rect, label){
  let bb = rect.getBBox();
  let [x, y, width, height] = [bb.x, bb.y, bb.width, bb.height];
  label.setAttribute('x', (x+width/2) )
  label.setAttribute('y', (y+height/2) )
}

同样巧妙的是:带有父SVG元素的font-size will scale.

缺点

<text>个元素的行为不像块元素:

  • 无车线绕线
  • 不支持背景色和框状外观

示例

// 1. svg text approach
setSvgLabelPos(rect2, labelSvg);

function setSvgLabelPos(rect, label) {
  let bb = rect.getBBox();
  let [x, y, width, height] = [bb.x, bb.y, bb.width, bb.height];
  label.setAttribute('x', (x + width / 2))
  label.setAttribute('y', (y + height / 2))
}


// 2. HTML relative/absolute layout
let posLabel = getElemementRelativePosition('svg', 'rect', 'label')
label.setAttribute('style', `top: ${posLabel.top}px; left: ${posLabel.left}px`);


function getElemementRelativePosition(parentId, childId, labelId) {
  var parentPos = document.getElementById(parentId).getBoundingClientRect();
  var childPos = document.getElementById(childId).getBoundingClientRect();
  var labelPos = document.getElementById(labelId).getBoundingClientRect();
  var relativePos = {};

  relativePos.top = childPos.top - parentPos.top;
  relativePos.right = childPos.right - parentPos.right;
  relativePos.bottom = childPos.bottom - parentPos.bottom;
  relativePos.left = childPos.left - parentPos.left;
  return relativePos;
}
svg {
  width: 20em;
  border: 1px solid #ccc;
  background: #eee;
}

.svgWrap {
  position: relative;
}

.svgWrap>* {
  position: absolute;
}

.label {
  padding: 0.3em;
  display: inline-block;
  background: rgba(0, 0, 0, 0.5);
  color: #fff;
}
<div class="svgWrap">
  <svg id="svg" viewBox="0 0 100 100">
    <rect id="rect" x="25%" y="50%" width="20" height="20" fill="red" />
    <rect id="rect2" x="50%" y="25%" width="20" height="20" fill="green" />
    <text id="labelSvg" class="label" x="50%" y="50%" style="font-size:4.5px; font-family:sans-serif;fill:currentColor " text-anchor="middle" dominant-baseline="middle">Svg label</text>
  </svg>
  <div id="label" class="label" style="">MyLabel</div>
</div>

Css相关问答推荐

SVG文本在移动浏览器上增长并溢出

将特定样式应用于递归Angular 元素

如何使用 Ant Design 为不同的屏幕尺寸制作自定义组件样式

为什么 KaTeX 的彩虹文本只能在 Firefox 上运行?

使用 CSS 定位悬停/弹出 div - 字形浏览器网页

如何使用 :has() 父 Select 器 Select 父元素的子元素,在父元素和子元素之间没有中间层的情况下?

创建一个CSS动画的对角线线条.

在 dbc.Container 上方包含横幅 - Dash

最多 2 行的 Flex 水平滚动

Angular (13) material - 覆盖 CSS 文件不起作用

React Typescript 中的自动 typewriter 效果

使用 MUI 动态绘制多个边框

我怎样才能在某些区域制作一个单独的文本行,而在其他区域制作一个实心填充?

你如何调试可打印的 CSS?

删除在 ios safari / chrome / firefox 中单击的链接上的灰色背景

CSS:固定到底部并居中

使用边距:0 自动;在 Internet Explorer 8 中

flex-wrap 如何与 align-self、align-items 和 align-content 一起使用?

在渲染网页之前等待字体加载

模拟显示:React Native 中的内联