How to draw a distribution of equidistant points along an Archimedean Spiral using D3.js. The solution was taken from this stackoverflow discussion.
forked from fabiovalse's block: Equidistant Points Along an Archimedean Spiral
license: mit |
How to draw a distribution of equidistant points along an Archimedean Spiral using D3.js. The solution was taken from this stackoverflow discussion.
forked from fabiovalse's block: Equidistant Points Along an Archimedean Spiral
svg { | |
background: white; | |
} | |
.spiral { | |
fill: none; | |
stroke: #303030; | |
stroke-width: 3px; | |
} |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta name="description" content="Points Along an Archimedean Spiral" /> | |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | |
<script type="text/javascript" src="http://d3js.org/d3.v2.js"></script> | |
<link href="index.css" rel="stylesheet" type="text/css"> | |
</head> | |
<body> | |
<div id="chart"></div> | |
<script type="text/javascript" src="index.js"></script> | |
</body> | |
</html> |
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"); |