AJB - 5 months ago 41
jQuery Question

# Fibonacci Drawing in html5 canvas

Currently I'm looking at this code but can't figure out what's wrong.

`````` function fibNumbers() {
return [0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
}

function continiusFib(a) {
var b = fibNumbers(),
c = Math.floor(a),
d = Math.ceil(a);
if (d >= b.length)
return null;
a = Math.pow(a - c, 1.15);
return b[c] + (b[d] - b[c]) * a
}

function drawSpiral(pointA, pointB) {
var b = pointA;
var c = pointB;
ctx.translate(b.x, b.y);
b = Math.sqrt(((c.x - b.x) * (c.x - b.x)) + ((c.y - b.y) * (c.y - b.y)));
d = 1 / Math.sqrt(((c.x - b.x) * (c.x - b.x)) + ((c.y - b.y) * (c.y - b.y)));
c = Math.acos(c.x - b.x);
0 > Math.asin(c.y - b.y) && (c = 2 * Math.PI - c);
ctx.rotate(c);
ctx.scale(b / 5, b / 5);
var d = Math.PI / 100;
ctx.moveTo(0, 0);
for (var e = 0; e < 50 * (fibNumbers().length - 1) ; e++) {
var f = e * d, g = continiusFib(e / 50),
h = Math.cos(f) * g,
f = Math.sin(f) * g;
ctx.lineTo(h, f);
}
ctx.scale(5 / b, 5 / b);
ctx.rotate(-c);
//ctx.stroke();
}
``````

What I want is to draw Fibonacci Spiral which is different from Golden Spiral

I also have this question for other reference.

In your function `drawSpiral`, in the fourth line you do:

``````b = Math.sqrt(((c.x - b.x) * (c.x - b.x)) + ((c.y - b.y) * (c.y - b.y)));
``````

So, `b` should be a scalar now, but then you try to access `b.x` and `b.y` in the next line, which don't exist anymore:

``````d = 1 / Math.sqrt(((c.x - b.x) * (c.x - b.x)) + ((c.y - b.y) * (c.y - b.y)));
``````

This happens again with `c` in the 6-7th lines. This might be why your code isn't working.

I tried to make it work with my own code. I'm not sure at all about the math, but I based my algorithm on the snippet you posted on the question, using some of the mouse-tracking code from @Blindman67's answer.

## The spiral

This is the important part. It returns an array with the spiral's points (I use another function to actually render them). The idea is to draw a spiral using the continuous-fibonacci function you provided. It starts at point A and forces the scaling so that the radius at one turn is the distance between point A and point B. It also adds an angle offset so the angle at one turn is the angle between point A and B.

Edited to address comment: I changed the `for` loop to a `while` loop that continues drawing until the spiral reaches a maximum radius. I also changed some names and added comments to try to make the algorithm clearer.

``````var getSpiral = function(pA, pB, maxRadius){
// 1 step = 1/4 turn or 90ยบ
var precision = 50; // Lines to draw in each 1/4 turn
var stepB = 4; // Steps to get to point B

var angleToPointB = getAngle(pA,pB); // Angle between pA and pB
var distToPointB = getDistance(pA,pB); // Distance between pA and pB

var fibonacci = new FibonacciGenerator();

// Find scale so that the last point of the curve is at distance to pB
var scale = distToPointB / radiusB;

// Find angle offset so that last point of the curve is at angle to pB
var angleOffset = angleToPointB - stepB * Math.PI / 2;

var path = [];
var i, step , radius, angle;

// Start at the center
i = step = radius = angle = 0;

// Continue drawing until reaching maximum radius

path.push({
x: scale * radius * Math.cos(angle + angleOffset) + pA.x,
y: scale * radius * Math.sin(angle + angleOffset) + pA.y
});

i++; // Next point
step = i / precision; // 1/4 turns at point
angle = step * Math.PI / 2; // Radians at point
}
return path;
};
``````

## Fibonacci sequence

The code to generate the continuous fibonacci numbers is basically yours, but I changed some names to help me understand it. I also added a generator function so it could work up to any number:

``````var FibonacciGenerator = function(){
var thisFibonacci = this;

thisFibonacci.array = [0, 1, 2];

thisFibonacci.getDiscrete = function(n){

// If the Fibonacci number is not in the array, calculate it
while (n >= thisFibonacci.array.length){
var length = thisFibonacci.array.length;
var nextFibonacci = thisFibonacci.array[length - 1] + thisFibonacci.array[length - 2];
thisFibonacci.array.push(nextFibonacci);
}

return thisFibonacci.array[n];
};

thisFibonacci.getNumber = function(n){
var floor = Math.floor(n);
var ceil = Math.ceil(n);

if (Math.floor(n) == n){
return thisFibonacci.getDiscrete(n);
}

var a = Math.pow(n - floor, 1.15);

var fibFloor = thisFibonacci.getDiscrete(floor);
var fibCeil = thisFibonacci.getDiscrete(ceil);

return fibFloor + a * (fibCeil - fibFloor);
};

return thisFibonacci;
};
``````

## Distance and angle between points

To make code clearer, I used a couple helper functions to work with 2D points:

``````var getDistance = function(p1, p2){
return Math.sqrt(Math.pow(p1.x-p2.x, 2) + Math.pow(p1.y-p2.y, 2));
};

var getAngle = function(p1, p2){
return Math.atan2(p2.y-p1.y, p2.x-p1.x);
};
``````

The whole thing: JSFiddle and Updated-to-address-comment JSFiddle

Source (Stackoverflow)