var nodesCount = 32; var width = 960, height = 500; var centerX = width/2, centerY = height/2, radius = 500, coils = 10; var placeholderR=22; var textArea={width: 30, height: 15}; var iconArea={width: 15, height: 15}; var direction = 1; //RTL = -1, LTR =1 var textIconGap = 5; var rotation = - 2*Math.PI; var thetaMax = coils * 2 * Math.PI; var awayStep = radius / thetaMax; var chord = placeholderR*2; var initialAdjustment = chord / awayStep; var a_time = []; for ( theta = chord / awayStep; theta <= thetaMax; ) { if (a_time.length == nodesCount) break; away = awayStep * theta; around = theta + rotation; around*= direction; theta += chord / away; a_time.push({around: around, away: away}); } console.log("around=" + around + " theta=" + theta + " away=" + away); console.log(a_time); fmod = function (a,b) { return Number((a - (Math.floor(a / b) * b)).toPrecision(8)); }; var finalAngle = fmod(around, 2*Math.PI); console.log( "finalAngle= " + finalAngle ); var adjustAngle = finalAngle-initialAdjustment; //var adjustAngle = 0; var new_time = []; for (var i = 0; i < a_time.length; i++) { x = centerX + Math.cos ( a_time[i].around + adjustAngle) * a_time[i].away; y = centerY + Math.sin ( a_time[i].around + adjustAngle) * a_time[i].away; xArc = centerX + Math.cos ( a_time[i].around + adjustAngle) * (a_time[i].away-placeholderR); yArc = centerY + Math.sin ( a_time[i].around + adjustAngle) * (a_time[i].away-placeholderR); new_time.push({x: x, y: y, xArc: xArc, yArc: yArc}); } var svg = d3.select("#chart").append("svg") .attr("width", width) .attr("height", height) .append("g"); var lineFunction = d3.svg.line() .x(function(d) { return d.xArc; }) .y(function(d) { return d.yArc; }) .interpolate("cardinal"); svg.append("path") .attr("d", lineFunction(new_time)) .attr("stroke", "gray") .attr("stroke-width", 0.5) .attr("fill", "none"); svg.append("circle") .attr("class", "node-placeholder") .attr("cx", centerX) .attr("cy", centerY) .attr("r", 0.5) .attr("fill", "red"); var node = svg.selectAll("circle") .data(new_time) .enter() .append("g"); node.append("circle") .attr("class", "node-placeholder") .attr("cx", function (d) { return d.x; }) .attr("cy", function (d) { return d.y; }) .attr("fill", "lightgrey") .attr("r", placeholderR) node.append("circle") .attr("class", "TL-dot") .attr("cx", function (d) { return d.xArc; }) .attr("cy", function (d) { return d.yArc; }) .attr("fill", "black") .attr("r", 2) node.append("rect") .attr("class", "text-placeholder") .attr("x", function (d) { return d.x - textArea.width/2; }) .attr("y", function (d) { return d.y; }) .attr("width", textArea.width) .attr("height", textArea.height) .attr("fill", "#919191"); node.append("rect") .attr("class", "icon-placeholder") .attr("x", function (d) { return d.x - iconArea.width/2; }) .attr("y", function (d) { return d.y - iconArea.height-textIconGap; }) .attr("width", iconArea.width) .attr("height", iconArea.height) .attr("fill", "#919191");