如何将svg foreignObject与文本元素对齐?

时间:2018-01-26 21:11:36

标签: d3.js svg

我想在我的d3 svg中添加带标签的复选框。我希望它们位于单独的g元素中,因为出于某种原因,如果标签位于foreignObject中,则字体呈现与svg的其余部分不匹配(与我的问题无关,尽管我是也很满意那里的解释。

然而,我无法弄清楚如何让它们垂直对齐。是的,我可以介绍一些软糖因素,但似乎只能对应一个特定大小的svg,这可能会改变。我该怎么做?

let y=40;
svg.append("g")
    .append("foreignObject")
    .attr("x", "4ex")
    .attr("y", y)
    .attr("width", 75)
    .attr("height", 25)
    .append("xhtml:body")
    .html("<form><input type=checkbox id=check/>text1</form>");
//seems I must render this outside the foreignObject in order to match font rendering of the svg
svg.append("g")
    .append("text")
    .attr("y", y)
    .attr("height", 25)
    .attr("x", "7ex")
    .text("text2")

也就是说,我希望文本与复选框对齐,就好像文本已经在foreignObject的html中一样。看起来我应该能够为两者设置y的相同值。

misaligned elements

http://jsfiddle.net/48rdrp6a/2/

如果是设置vertical-align的问题,我无法弄清楚放在哪里。

1 个答案:

答案 0 :(得分:1)

主要问题是y上的foreignObject属性指定了框中的顶部,而y上的text属性}指定文本的基线

在给定的示例中,foreignObject因此从40开始向下增长到65,而text的基线从40开始,上升和下降分别从40上升和下降

可以通过the alignment-baseline property更改此行为。使用before-edge移动EM框,以便y指定text的上边缘,使两个元素兼容。

除了这个根本区别之外,浏览器默认样式还存在问题。 body中的foreignObject将具有特定于浏览器的默认样式,可能会偏移表单和复选框,使其再次不对齐。例如,在Chrome中,这会增加8px的保证金。

&#13;
&#13;
var svg = d3.select("#chart").append("svg")
  .attr("width", 200)
  .attr("height", 200);

let y = 40;
svg.append("g")
  .append("foreignObject")
  .attr("x", "4ex")
  .attr("y", y)
  .attr("width", 75)
  .attr("height", 25)
  .append("xhtml:body")
  .html("<form><input type=checkbox id=check/></form>");

svg.append("g")
  .append("text")
  .attr("y", y)
  .attr("height", 25)
  .attr("x", "6ex")
  .text("text2")

// svg repositioning
$("svg").css({
  top: 200,
  left: 200,
  position: 'absolute'
});
&#13;
#chart {
  border: 1px solid green;
}

svg {
  background: #AABBFF;
  border: 2px solid #8899EE;
}

text {
  alignment-baseline: before-edge;
}

foreignObject body {
  all: unset;
  display: block;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<div id="chart"></div>
&#13;
&#13;
&#13;

我使用CSS来设置alignment-baseline,但使用相应的属性也可以。

为了抵消body默认样式,我使用all: unset组合删除所有浏览器样式,然后恢复display: block