代码之家  ›  专栏  ›  技术社区  ›  amos

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

  •  0
  • amos  · 技术社区  · 8 年前

    我想在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 回复  |  直到 8 年前
        1
  •  2
  •   mmlr    8 年前

    主要问题是 y 上的属性 foreignObject 指定 顶部 y 上的属性 text 指定 基线 文本的。

    在给定的示例中 外来物体 因此,将从40岁开始,向下增长至65岁,而 文本 其基线从40开始,分别从40向上和向下上升和下降。

    这种行为可以通过 the alignment-baseline property . 使用 before-edge 移动EM框,以便 y 指定 文本 同时,使两个元素兼容。

    除此之外,浏览器默认样式还有一个问题。这个 body 外来物体 将具有特定于浏览器的默认样式,这可能会偏移表单和复选框,使其再次对齐。例如,在Chrome中,这会增加8px的边距。

    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'
    });
    #chart {
      border: 1px solid green;
    }
    
    svg {
      background: #AABBFF;
      border: 2px solid #8899EE;
    }
    
    text {
      alignment-baseline: before-edge;
    }
    
    foreignObject body {
      all: unset;
      display: block;
    }
    <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>

    我使用CSS设置 路线基线 ,但使用相应的属性也可以。

    用于抵消 身体 默认样式我使用了以下组合 all: unset 删除所有浏览器样式,然后恢复 display: block .