2013-06-21 186 views
2

这是我的第一个D3项目(我不是程序员,因此一次学习所有东西)。D3.js如何在路径上旋转文本

我正在尝试制作一个手动绘制数年的圆形日历,这是一个巨大的痛苦。

大多数位现在工作,但我不知道如何获得文本转弯90度在这个弧上。

一旦我得到文本转向,那么我需要弄清楚如何让它在圆周上等间隔。

我的目标是让它看起来像这样手工绘制的例子:

Goal for the text

这里是它看起来像现在:

Current text

我可能已经下了死通过将文本放置在路径上结束,因此欢迎任何和所有建议。

编辑:我创建了一个的jsfiddle这里jsfiddle.net/LMF9h/1/

这里是我的代码至今:

<!DOCTYPE html> 
<meta charset="utf-8"> 
<style> 
body { font: 12px Arial;} 
path { 
    stroke: red; 
    stroke-width: 1; 
    fill: none; 
} 
.axis path, 
.axis line { 
    fill: none; 
    stroke: grey; 
    stroke-width: 1; 
    shape-rendering: crispEdges; 
} 
</style> 

<body> 
    <script type="text/javascript" src="d3/d3.v3.js"></script> 

    <script type="text/javascript"> 

var margin = {top: 25, right: 25, bottom: 25, left: 25}, 
width = 950 - margin.left - margin.right, 
height = 950 - margin.top - margin.bottom; 

// Build Day Numbers 
function pad(n) { 
    return (n < 10) ? ("0" + n) : n; 
} 

function getDaysArray(year) { 
    var numDaysInMonth, daysInWeek, daysIndex, index, i, l, daysArray; 

    numDaysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; 
    daysInWeek = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; 
    daysIndex = { 'Sun': 0, 'Mon': 1, 'Tue': 2, 'Wed': 3, 'Thu': 4, 'Fri': 5, 'Sat': 6 }; 

    daysArray = []; 

for (m=0; m < 12; m++) { 
     index = daysIndex[(new Date(year, m, 1)).toString().split(' ')[0]]; 
    for (i = 0, l = numDaysInMonth[m]; i < l; i++) { 
     daysArray.push(pad((i + 1)) + ' ' + daysInWeek[index++]); 
     if (index == 7) index = 0; 
    } 
} 
    return daysArray; 
} 


var year = 2014 

var days = getDaysArray(year) 

var svg = d3.select("body").append("svg") 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g"), 
    pi = Math.PI; 


var arc = d3.svg.arc() 
    .innerRadius(850) 
    .outerRadius(851) 
    .startAngle(0) 
    .endAngle(-pi*1.99999) 

var path = svg.append("path") 
    .attr("d", arc) 
    .attr("id", "path1") 
    .attr("transform", "translate(900,900)") 
    .attr("fill","#f00") 


// Draw lines 
function daysInYear(year) { 
    if(year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) { 
     // Leap year 
     return 366; 
    } else { 
     // Not a leap year 
     return 365; 
    } 
} 

var dt = new Date(year+"/01/01"); 
var day = dt.getDay(); 
var startrads = (2*pi/daysInYear(year)) * day; 
    //---center point(width,height)--- 
     var cx=width 
     var cy=height 
     var r=850 //--radius-- 
     var radialLines=52 //---create 52 lines--- 
     var angle=2*Math.PI/radialLines //---angle between each line--- 
     var radialPoints=[] 
     for(var k=startrads;k<radialLines;k++) 
     { 
       var x2=r*Math.cos(angle*k)+cx 
       var y2=r*Math.sin(angle*k)+cy 
       radialPoints.push([x2,y2]) 
     } 
    //---your d3 SVG parent element--- 
     svg.selectAll("line")//---an empty selection--- 
     .data(radialPoints) 
     .enter().append("svg:line") 
     .attr("x1",cx) 
     .attr("y1",cy) 
     .attr("x2",function(p){return p[0]}) 
     .attr("y2",function(p){return p[1]}) 
     .attr("stroke","red"); 



// Add day labels. 
var text1 = svg.append("text"); 


text1 
    .selectAll("body") 
    .data(days) 
    .enter() 
    .append("textPath") 
    .attr("xlink:href","#path1") 
    .text(function(d) { return d; }); 



    </script> 

</body> 

回答

1

来获取文本的权利,你只需要简单地计算出它的位置和旋转与计算径向线末端的方式相同。该代码会是这样的

svg.selectAll("text").data(days).enter() 
.append("text") 
.attr("transform", function(d, i) { 
    return "translate(" + (850*Math.cos(i*2*Math.PI/365)+width) + 
      "," + (850*Math.sin(i*2*Math.PI/365)+height) + ")" + 
      "rotate(" + (i*360/365) + ")"; 
}) 
.text(function(d) { return d; }); 

注意,对在您的jsfiddle可见的圆边,文字是颠倒的。您可以通过在rotate值中加上180来解决此问题。修改jsfiddle here