SVG文字换行 - 是否阻碍显示?

26

我在业余时间尝试实现一个SVG浏览器客户端,以增加我的乐趣。

但是遇到了一个似乎是巨大的障碍。没有自动换行!!

有人知道任何解决方法吗(我在想一些JavaScript或我不知道的特殊标记)?

如果没有,我要么走xhtml路线并在我的SVG中插入HTML元素(痛苦),要么再等十年,直到SVG 1.2准备好。

8个回答

18
这个SVG的东西很令人困惑,不是吗?幸运的是,你可以取得一些不错的结果,但需要比使用HTML 5更多的工作。下面是我的ASP.Net / SVG应用程序的截图,其中包含一些“伪造”的换行效果。

enter image description here

下面的函数将为您创建一个SVG 文本元素,分成tspan块,每行长度不超过20个字符。
<text x="600" y="400" font-size="12" fill="#FFFFFF" text-anchor="middle">
    <tspan x="600" y="400">Here a realy long </tspan>
    <tspan x="600" y="416">title which needs </tspan>
    <tspan x="600" y="432">wrapping </tspan>
</text>

虽然不完美,但它简单快速,用户永远不会察觉到差异。

我的createSVGtext() JavaScript函数需要三个参数:x位置、y位置和要显示的文本。字体、每行最大字符数和文本颜色都在函数中硬编码,但这很容易更改。

要显示如上截图中所示的右侧标签,您可以使用以下方式调用该函数:

var svgText = createSVGtext("Here a realy long title which needs wrapping", 600, 400);
$('svg').append(svgText);

这里是JavaScript函数:

function createSVGtext(caption, x, y) {
    //  This function attempts to create a new svg "text" element, chopping 
    //  it up into "tspan" pieces, if the caption is too long
    //
    var svgText = document.createElementNS('http://www.w3.org/2000/svg', 'text');
    svgText.setAttributeNS(null, 'x', x);
    svgText.setAttributeNS(null, 'y', y);
    svgText.setAttributeNS(null, 'font-size', 12);
    svgText.setAttributeNS(null, 'fill', '#FFFFFF');         //  White text
    svgText.setAttributeNS(null, 'text-anchor', 'middle');   //  Center the text

    //  The following two variables should really be passed as parameters
    var MAXIMUM_CHARS_PER_LINE = 20;
    var LINE_HEIGHT = 16;

    var words = caption.split(" ");
    var line = "";

    for (var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + " ";
        if (testLine.length > MAXIMUM_CHARS_PER_LINE)
        {
            //  Add a new <tspan> element
            var svgTSpan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
            svgTSpan.setAttributeNS(null, 'x', x);
            svgTSpan.setAttributeNS(null, 'y', y);

            var tSpanTextNode = document.createTextNode(line);
            svgTSpan.appendChild(tSpanTextNode);
            svgText.appendChild(svgTSpan);

            line = words[n] + " ";
            y += LINE_HEIGHT;
        }
        else {
            line = testLine;
        }
    }

    var svgTSpan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
    svgTSpan.setAttributeNS(null, 'x', x);
    svgTSpan.setAttributeNS(null, 'y', y);

    var tSpanTextNode = document.createTextNode(line);
    svgTSpan.appendChild(tSpanTextNode);

    svgText.appendChild(svgTSpan);

    return svgText;
}

单词换行的逻辑基于这个HTML5 Canvas教程

希望你会发现这很有用!

Mike

http://www.MikesKnowledgeBase.com

更新

我忘了提到一件事。

我展示的“工作流程图”屏幕最初只是使用HTML 5 画布编写的。它运行得非常好,图标可以被拖动,当您单击它们时,弹出菜单可以出现,即使是IE8也似乎很满意。

但我发现,如果图表变得“太大”(例如4000 x 4000像素),则所有浏览器中的canvas都无法初始化,什么也不会出现 - 但是 - 就JavaScript代码而言,一切正常。

因此,即使进行错误检查,我的图表也会显示为空白,并且我无法检测到此严重问题何时发生。

var canvasSupported = !!c.getContext;
if (!canvasSupported) {
    //  The user's browser doesn't support HTML 5 <Canvas> controls.
    prompt("Workflow", "Your browser doesn't support drawing on HTML 5 canvases.");
    return;
}

var context = c.getContext("2d");
if (context == null) {
    //  The user's browser doesn't support HTML 5 <Canvas> controls.
    prompt("Workflow", "The canvas isn't drawable.");
    return;
}

//  With larger diagrams, the error-checking above failed to notice that
//  the canvas wasn't being drawn.

因此,我不得不重写JavaScript代码以使用SVG。它似乎更能应对较大的图表。


啊,我今天拼“really”都拼不对!也许我应该修改我的函数,在我的字幕上做一些拼写检查! - Mike Gledhill
1
今天在我的项目中使用了这个,谢谢Mike,运行得非常完美! - JasonMHirst
很酷,不错的东西。(当有一个可借鉴的工作示例时,生活是不是更容易了!) - Mike Gledhill
@MikeGledhill,你提出了一个很好的观点。SVG图表的呈现比HTML图表更加平滑。也许是因为一些浏览器使用GPU对SVG进行呈现。https://developer.chrome.com/blog/hardware-accelerated-animations/ - user160357
1
很棒的解决方案。我喜欢它!我正在尝试将函数的结果插入到一个更大的SVG元素中,该元素添加了一个矩形等:我正在做这个:var svgText = createSVGtext('{{ thisMarker[3] }}',50,70); var svgMarkup = '<svg width="50" height="68" viewBox="0 0 50 68" xmlns="http://www.w3.org/2000/svg">' + <rect stroke="grey" fill="{{ thisMarker[2] }}" x="1" y="1" width="50" height="68" />' + svgText + '</svg>';但是我得到了:'<svg ... />[object SVGTextElement]</svg>'有什么想法吗?我对SVG和JS还很陌生。非常感谢! - PiBer2
@PiBer2 我也遇到了这个问题... 你解决了吗?我猜测它没有渲染 <text> 和 <tspan> 的 svg 对象,只是试图显示整个无法渲染的对象。 - Tom Rudge

17

还有foreignObject标签。这样就可以在SVG中嵌入HTML,从而获得最大的灵活性。HTML非常适合文档布局,并已被黑客使用来支持应用程序布局、绘图以及我们开发人员想要的一切。但它的强项是自动换行和文档布局。让HTML发挥其所长,让SVG发挥其所长。

http://www.w3.org/TR/SVG/extend.html

这适用于大多数浏览器,如FireFox、Opera、Webkit,除了IE(截至IE11)。 :-( 看来这就是Web的故事?


1
这就是mxgraph为标签(可选)使用的技术。看到在主<body>中包含了一个<body>有点令人不安,但它可以很好地工作并增加了许多灵活性。 - peteorpeter
第二个链接已经失效。 - Rich Apodaca
值得一提的是,MS Edge支持<foreignObject>,但似乎MSIE永远不会得到支持。 - Christopher Schultz

11

6
天啊,我迫不及待地想要那个规格被采纳! - peteorpeter
13年过去了,Chrome或Firefox仍然没有支持。 - user160357

10
根据这份文档,看起来tspan可以模拟换行效果:

tspan标签与text标签相同,但可以嵌套在text标签和其自身中。结合'dy'属性,这使得SVG 1.1可以产生字词换行的错觉。注意,'dy'是相对于上一个绘制的字符而言的。


1
David,感谢您的回复。我看到了TSPAN,并在这里找到了一个脚本来动态处理事情 - http://www.xml.com/pub/a/2002/09/11/quint.html - ChrisInCambo

2

链接已损坏。看起来你已经将它合并到svg.js中了?https://github.com/wout/svg.js - Steve Bennett
我已经停止了这个插件的开发并选择了另一种方式。该插件仍然可以在这里找到:https://gist.github.com/wout/6352742 - wout

0
这些天,flowPara 可以进行自动换行,但我还没有找到一个正常支持它的浏览器。

不,flowPara是SVG 1.2草案的一部分,但SVG 1.2从未发布,并且它不是SVG 1.1、SVG Tiny 1.2或SVG 2的一部分。 - Fred

0

另一种方法是使用Andreas Neuman的text box对象。


0

我已经花了很多小时(或者很多天)寻找有关svg文字换行的解决方案。 如果您能在您的应用程序中编辑代码以放置一些tspan或任何其他方法,就可以使用它。

文本换行将在1.2版本中实现,但除了Opera之外,没有浏览器完全实现它(4年了,规范在W3上...)。

因为我必须使用一些对齐设置,所以我不能使用许多论坛提供的任何代码(没有foreign object,也没有carto script或其他任何东西)。

如果我发布这个消息,只是为了在谷歌搜索svg文字换行时对一些其他人有用,因为这篇帖子排在首位,在许多情况下,这篇帖子并没有帮助。

这里有一个很酷,简单和轻量级的解决方案: http://dev.w3.org/SVG/profiles/1.1F2/test/svg/text-dom-01-f.svg


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