我有一个元素,我将一些数据可视化为包含矩形元素的 SVG 元素。 所以我想做的是在 SVG 的特定矩形元素上添加标签,为了做到这一点,我必须获取矩形元素的位置,以便将标签放置在这个确切的位置。
因此,为了首先实现这一点,我使用 getBoundingClientRect() javascrip 方法获取 SVG 位置,然后使用相同的方法获取 rect 元素位置。
之后我得到了 svg 和 rect 元素的位置之间的差异,我得到的值就是标签要放置的位置。
这是获取每个元素的位置,然后计算标签的新位置的代码。
parentId参数是svg元素的id,childId参数是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 所指出的:您可以使用 position:relative
将 svg 和 label 包装在 div 中并申请position:absolute
到您的 svg 和标签。
替代:svg <text>
标签
如果您只需要简单的单行标签 – <text>
有一些优点:
您只需要获取 <rect>
的中心 x 和 y 坐标元素。
通过申请text-anchor:middle
和dominant-baseline:middle
文本将相对于矩形的中心垂直和水平居中。
您可以使用 getBBox()
获取中心坐标方法(类似于 getBoundingClientRect()
- 但专门用于 svg 元素)。
一个简单的标签助手可能如下所示:
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 元素缩放。
缺点
<text>
元素的行为与 block 元素不同:
- 没有自动换行
- 分别不支持背景颜色和盒状外观
示例
// 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 元素上方添加标签而不使 SVG 元素移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74615924/