D3中的垂直文本(未旋转)

6

我正在尝试使用d3在svg中垂直显示文本。但是,我不想将其旋转:我希望字母保持水平,但一个字母在另一个字母的上方。设置 writing-mode = tb 似乎没有起作用。以下是我的尝试:

svg.append("text")
  .attr("x", 1000)
  .attr("y", 400)
  .attr("id", "title")
  .attr("font-size", 50)
  .attr("style", "font-family: arial; fill: lightgreen; writing-mode: tb")
  .text("Top 100 Mentions");

文本显示位置正确,字体等格式也正确,但是水平方向的。


1
在Chrome中可以运行,但在Firefox中无法运行:http://jsfiddle.net/hx5Th/ - methodofaction
1
谢谢,那就是问题所在。我在Chrome中尝试了一下,它可以工作,但我需要将glyph-orientation-vertical: 0添加到样式中以防止文本旋转。 - Samarth
5个回答

18

在讨论旋转SVG文本时,有多个不同方面:

  • 浏览器如何基于前一个字符的位置来确定下一个字符的位置;

  • 字符相对于基线的旋转方式(rotate属性);

  • 整个文本块相对于坐标系的旋转方式(transform属性)。

这里是完整但难以理解的规范

'writing-mode'属性应该可以改变第一个方面而不影响其他方面,但正如你发现的在Firefox中根本没有实现,而IE会旋转文本但不遵守水平字形规则。

从理论上讲,通过组合旋转和变换属性,您应该能够获得相同的效果:将整个<text>元素转换为垂直位置,然后将单个字符反向旋转以使其恢复水平。 但实际操作起来比较麻烦...

首先,双重旋转导致文本最终位于点(x,y)的左侧,因此如果(x,y)为(0,0),它将在SVG外被剪切掉而不需要额外的移位。由于变换的影响,您需要使用负的dy将文本移回到锚点的右侧。

其次,旋转应用于每个字符本身,字符间距没有调整以考虑“l”的高度远大于宽度的事实。 因此,除非使用等宽字体,否则文本看起来很混乱。您应该可以使用kerningletterspacing属性更改字母间距,但是浏览器对此的支持也很差:IE11似乎不承认字距值,Firefox两者都不承认。

最后一种选择是自己控制布局:使用d3的强大功能和字符串的.split("")方法将标题分解为单个字符的<tspan>元素,这些元素可以一个接一个地放置并且可以在<text>元素内进行整齐居中。 缺点是这会添加额外的DOM元素,您仍然可以像选择HTML段落中的短语一样选择整个文本块,即使每个字母都被样式化为单独的<span>。 不确定屏幕阅读器是否会自动假定字母之间有空格......

对比

这个fiddle尝试了三种方法来获得垂直文本标签中的水平字符(writing-mode vs double rotate vs splitting into <tspan>s):
http://jsfiddle.net/hx5Th/11/

代码:

var svg = d3.select("body").append("svg");

//Green text, uses writing-mode property //
svg.append("text")
  .attr("x", 40)
  .attr("y", 40)
  .attr("id", "title")
  .attr("font-size", 50)
  .attr("style", "fill: lightgreen; writing-mode: tb; glyph-orientation-vertical: 0")
  .text("Top 100 Mentions");

//Black text, uses a double rotate //
svg.append("text")
  .attr("x", 40)
  .attr("y", 40)
  .attr("id", "title")
  .attr("font-size", 50)
  .attr("rotate", -90)
  .attr("dx", "1em")
  .attr("dy", "-1em")
  .attr("kerning", 0)
  .attr("letter-spacing", "0.5em")
  .attr("transform", "translate(150,0) rotate(90)")
  .text("Top 100 Mentions");

//Blue text, uses d3 to create a series of tspans//
svg.append("text")
  .attr("x", 40)
  .attr("y", 40)
  .attr("font-size", 50)
  .attr("id", "title")
  .style("fill", "blue")
  .attr("transform", "translate(300,0)")
  .attr("text-anchor", "middle")
  .selectAll("tspan")
      .data("Top 100 Mentions".split(""))
  .enter().append("tspan")
      .attr("x", 0)
      .attr("dy", "0.8em")
      .text(function(d){return d;});

结果(都在 Windows 7 系统上):

Chrome 33 输入图像描述

IE 11 输入图像描述

Firefox 输入图像描述

我认为这是D3的胜利...


开玩笑的...又一个@AmeliaBR解释库的新成员!你的粉丝群正在增加 :-) - FernOfTheAndes

1

在SVG中嵌入的HTML:

<svg
  x="0px" y="0px"
  width="200px" height="200px" 
  viewbox="0 0 200 200"
>

  <foreignObject
    x="20" y="20"
    width="160" height="160"
  >

    <!-- we must set xmlns attribute
      for foreignObject.childNode -->
    <div
      xmlns="http://www.w3.org/1999/xhtml"
      style="

        /* HTML-CSS vertical text */
        writing-mode: vertical-lr;
        text-orientation: upright;

        line-height: 2em;
        font-family: sans-serif;
        font-size: 150%;
      "
    >Hello<br/>&nbsp;World</div>

  </foreignObject>

</svg>


0

对于Firefox,我能找到的唯一实现的东西是textLength,截至FF 30。我添加了第四个文本附加到AmeliaBR的jsfiddle中进行演示。虽然它看起来仍然很糟糕,但D3仍然是赢家。http://jsfiddle.net/hx5Th/11/

//Black text, uses a double rotate //
svg.append("text")
  .attr("x", 40)
  .attr("y", 40)
  .attr("id", "title")
  .attr("font-size", 50)
  .attr("rotate", -90)
  .attr("dx", "1em")
  .attr("dy", "-1em")
  .attr("textLength", "12.8em")
  .attr("transform", "translate(450,0) rotate(90)")
  .text("Top 100 Mentions");

0

您可以通过将文本绑定到路径元素来控制其位置和方向。以下是一个示例,其中包含一个{{link1:在jsFiddle上运行的版本}}:

var svg = d3.select("body").append("svg"),
    pi = Math.PI;

var arc = d3.svg.arc()
    .innerRadius(150)
    .outerRadius(180)
    .startAngle(0)
    .endAngle(-pi/2)

var path = svg.append("path")
    .attr("id","path1")
    .attr("d","M150 150 L150 20 Z")
    .attr("style","stroke:rgb(255,0,0);stroke-width:2")

// Add a text label.
var text = svg.append("text")
    .attr("x", 6)
    .attr("dy", 15);

text.append("textPath")
   .attr("stroke","black")
   .attr("xlink:href","#path1")
   .text("abc");

谢谢回复,但是那会旋转文本。我之前尝试过那个方法,也尝试了标准的.attr("transform", "translate(1000,250) rotate(90)"),它们都能达到同样的效果。不过我想让文本垂直而不是旋转。 - Samarth

0

这应该可以做到你想要的效果(虽然我不知道如何在d3中表达它):

<text x="100" y="100" transform="rotate(90, 100, 100)" style="glyph-orientation-horizontal: 270;">一些未旋转的垂直文本</text>

显然,将x和y坐标更改为您自己的值。


在Chrome中可以工作,但在IE或Firefox中无法工作。尽管与使用“writing-mode”相比,它具有一个好处,即至少整个标签在每个浏览器中都被定位在同一位置,因此看起来不会非常“破碎”。 - AmeliaBR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接