4
votes

I'm trying to plot data on a timeline using an Archimedean spiral as an axis using D3.js.

Axis

So what I need is a Javascript function where I pass it

  • D a distance for each step
  • S a number of steps
  • X the distance between each spiral arm

The function will traverse the spiral arc for the distance of s*d and give me the x and y Cartesian coordinates (point S in the diagram where s=10). The first point at the centre of the spiral is at 0,0.

2
This kind of solves it but I'm not sure if its the most efficient way to do it for what I need. This generates a series of points for you to plot a spiral. In my case thats not necessary as I only need the xy coordinates of a single point. Is there some way to do it without iterating all of the points before it?Ralphicus
It's my understanding (I may be wrong) that the full solution to the equation involves integrals, so solving it numerically requires an iterative summation as well. So the approximated algorithm (given by the Python code) is actually better because it's arithmetically simpler. There are a couple of improvements you can make to have the loop advnace very quickly along the path until the target step and return only the one cartesian point.belwood

2 Answers

2
votes

Thanks for all your help belwood. I tried plotting your example but it gets a bit strange when I plotted 5 consecutive points (see image at bottom).

I managed to find the answer at the link below. It looks like you were very close though.

Algorithm to solve the points of a evenly-distributed / even-gaps spiral?

My final implementation based on the link above.

function archimedeanSpiral(svg,data,circleMax,padding,steps) {
    var d = circleMax+padding;
    var arcAxis = [];
    var angle = 0;
    for(var i=0;i<steps;i++){
        var radius = Math.sqrt(i+1);
        angle += Math.asin(1/radius);//sin(angle) = opposite/hypothenuse => used asin to get angle
        var x = Math.cos(angle)*(radius*d);
        var y = Math.sin(angle)*(radius*d);
        arcAxis.push({"x":x,"y":y})
    }
    var lineFunction = d3.svg.line()
        .x(function(d) { return d.x; })
        .y(function(d) { return d.y; })
        .interpolate("cardinal");

    svg.append("path")
        .attr("d", lineFunction(arcAxis))
        .attr("stroke", "gray")
        .attr("stroke-width", 5)
        .attr("fill", "none");


    var circles = svg.selectAll("circle")
        .data(arcAxis)
        .enter()
        .append("circle")
        .attr("cx", function (d) { return d.x; })
        .attr("cy", function (d) { return d.y; })
        .attr("r", 10);

    return(arcAxis);
}

http://s14.postimg.org/90fgp41o1/spiralexample.jpg

1
votes

Doesn't hurt to try : (pardon my novice javascript)

function spiralPoint(dist, sep, step) {
    this.x = 0;
    this.y = 0;

    var r = dist;
    var b = sep / (2 * Math.PI);
    var phi = r / b;
    for(n = 0; n < step-1; ++n) {
        phi += dist / r;
        r = b * phi;
    }
    this.x = r * Math.cos(phi);
    this.y = r * Math.sin(phi);

    this.print = function() { 
        console.log(this.x + ', ' + this.y);
    };
}

new spiralPoint(1,1,10).print();