如何使用d3.js在弧内的textPath上右/末对齐文本?

时间:2014-03-06 22:05:23

标签: svg d3.js

这是小提琴:http://jsfiddle.net/DevChefOwen/CZ6Dp/

var text = g.append("text")
            .style("font-size",30)
            .style("fill","#000")
            .attr("dy",0)
            .append("textPath")
            .attr("xlink:href","#yyy")
            .style("text-anchor","left") // using "end", the entire text disappears
            .text("some text");

我尝试了许多不同的事情但无济于事。左对齐是简单的部分。但是,如果你做了一个中间,你只看到“文本”而不​​是“某些文本”,暗示“某些”只是被隐藏,因为它对于给定的弧“超出了范围”。

但是,如果我添加:

        .attr("startOffset","39%")

(如此处:http://jsfiddle.net/DevChefOwen/2H99c/

它看起来是正确的对齐,但在编程之外尝试获取文本元素的宽度/高度并寻找宽度/高度的急剧变化(这似乎是错误的并且可能容易出错),我似乎无法找到一种正确对齐文本的方法。

我也尝试过使用SVG路径(本质上是一条曲线弧线),当“text-anchor”设置为“left”时,文本也会发生相同的消失行为。

感谢你的时间!

3 个答案:

答案 0 :(得分:9)

这个问题有些令人困惑。问题是没有在路径末尾对齐文本 - 这对于"text-anchor"="end""startOffset"="100%"很容易。

但是,将这些设置与d3弧函数创建的路径一起使用时,最终会在内部曲线末端和左侧直边附近进行文本转弯,直到由弧函数定义的路径末尾: http://jsfiddle.net/CZ6Dp/8/

真正的问题是您希望文本对齐的路径(形状的外部圆弧)只是定义形状的路径的一个部分。

(顺便说一下,“left”和“right”不是“text-anchor”属性的有效值,只会被忽略)。

@ defghi1977的答案提供了一种解决问题的方法,通过计算你想要使用的路径段的长度并相应地调整起始偏移量。

解决此问题的另一种方法是创建一个单独的路径(未在屏幕上绘制),该路径仅表示您希望用于定位文本的路径部分。

有许多方法可以创建仅表示外部弧(some example code here)的路径。 @ defghi1977用正则表达式从现有路径中获取它的方法可能对你的情况最有效。但是,实际上我不得不创建一个临时元素来计算长度,而是必须将新路径添加到DOM,以便它可以用作<textPath>元素的引用路径。 (我认为这种方法的缺点是DOM元素的两倍!)

var path = g.append("svg:path")
    .attr("d", arct)
    .style("fill","#ccc")
    .attr("transform", "translate("+cfg.w/2+","+cfg.h/2+")")
    .each(function(d,i) {
        var justArc = /(^.+?)L/; 
        //grab everything up to the first Line statement
        var thisSelected = d3.select(this);
        var arcD = justArc.exec( thisSelected.attr("d") )[1];
        defs.append("path")
            .attr("id", "yyy") //normally the id would be based on the data or index  
            .attr("d", arcD)
            .attr("transform", thisSelected.attr("transform") );
            //if you can avoid using transforms directly on the path element, 
            //you'll save yourself having to repeat them for the text paths...
    });

var text = g.append("text")
            .style("font-size",30)
            .style("fill","#000")
            .attr("dy",0)
            .append("textPath")
            .attr("xlink:href","#yyy")
            .style("text-anchor","end") 
            .attr("startOffset","100%")
            .text("some text");

http://jsfiddle.net/CZ6Dp/9/

同样,考虑额外的DOM加载@ defghi1977的方法可能稍微偏爱一点,尽管这个版本的好处是不依赖浏览器对getTotalLength的支持。但据我所知,该方法实施得相当好。

因此,为了完整起见,请考虑这种替代方法。

答案 1 :(得分:3)

此路径由4(或5)个路径段构成 因此,这个问题将被解决以获得第一个弧长路径 但我不知道如何通过使用d3.js获得子路径长度,因此我直接使用svgdom 我试图修复你的代码。如果这个代码不是您所希望的,我很抱歉。

  1. path-anchor属性结束。
  2. 定义函数以获取startOffset值。

  3. var path = g.append("svg:path")
        .attr("id","yyy")
        .attr("d", arct)
        .style("fill","#ccc")
        .attr("transform", "translate("+cfg.w/2+","+cfg.h/2+")");
    
    var text = g.append("text")
            .style("font-size",30)
            .style("fill","#000")
            .attr("dy",0)
            .append("textPath")
            .attr("xlink:href","#yyy")
            //.style("text-anchor","left") // using "end", the entire text disappears
            .attr("text-anchor", "end")
            .text("some text")
            .attr("startOffset",function(){
                var d = document.getElementById("yyy").getAttribute("d");
                var tmp = document.createElementNS("http://www.w3.org/2000/svg" ,"path");
                //get the arc segment of path
                var arc = d.match(/(^.+?)L/)[1];
                tmp.setAttribute("d", arc);
                //return offset position
                return tmp.getTotalLength();
            });
    

答案 2 :(得分:1)

我认为混淆来自于text-anchor的含义 - 它不是“相对于父母的位置我会证明”,而是“我应该将哪一部分与开始对齐”。

您尝试使用startOffset移动原点是正确的。由于路径的外半径长于内半径,因此正确的起始偏移量略大于路径的一半(约53%)。

再多一点你的设置,你应该拥有它。 Here's a fiddle我对你要找的东西的解释。