Let's say I have a 2D array, for example, that is [7][7], all zeros, like so:
0000000
0000000
0000000
0000000
0000000
0000000
0000000
I'm trying to figure out how to take any number range (example: 0 to 3) and create a radial gradient of sorts from the center out, like so:
0000000
0011100
0122210
0123210
0122210
0011100
0000000
Basically the edges should always be the lowermost value and the center of the array should be the highest. It would be awesome to control the 'intensity' of the center (more threes with a faster fall-off) but I can probably figure that part out.
I'm really struggling to understand the math behind something like this. I thought it would be achieved using sine waves or something, but have no idea where to begin or how to apply that to a 2D array of values.
(Note - what I'm really trying to do is create a grid of DIVs in HTML, and then use Javascript to set the alpha of every element, such that the center is the most opaque, and the edges are the most transparent. It's easier for me to understand using simple round numbers like this in the meantime).
Let's say I have a 2D array, for example, that is [7][7], all zeros, like so:
0000000
0000000
0000000
0000000
0000000
0000000
0000000
I'm trying to figure out how to take any number range (example: 0 to 3) and create a radial gradient of sorts from the center out, like so:
0000000
0011100
0122210
0123210
0122210
0011100
0000000
Basically the edges should always be the lowermost value and the center of the array should be the highest. It would be awesome to control the 'intensity' of the center (more threes with a faster fall-off) but I can probably figure that part out.
I'm really struggling to understand the math behind something like this. I thought it would be achieved using sine waves or something, but have no idea where to begin or how to apply that to a 2D array of values.
(Note - what I'm really trying to do is create a grid of DIVs in HTML, and then use Javascript to set the alpha of every element, such that the center is the most opaque, and the edges are the most transparent. It's easier for me to understand using simple round numbers like this in the meantime).
Share Improve this question asked Jun 24, 2014 at 15:35 user72245user72245 7871 gold badge7 silver badges9 bronze badges3 Answers
Reset to default 4The only answer on this thread wasn't really satisfying for me, I ended up figuring it out on my own, here's the method I used:
First I created an array of empty values
var values = [];
for(var x = 0; x < 8; x++) {
values[x] = [];
for(var y = 0; y < 6; y++) {
values[x].push(0);
}
}
Then I decided on the center coordinates of my gradient, I decided to use the center of the array.
var centerX = values.length / 2;
var centerY = values.length / 2;
Then I decided how large I wanted my gradient to be. I decided that the best radius would be 3 (make sure that this is not more than half of your widest point in the array, or else it won't fit.)
var radius = 3;
var maxRadius = radius + 1;
My plan was to draw a circle, then reduce the radius and draw a circle inside that, until the radius was 0, at which point I couldn't draw any more and I would have a sloping gradient.
To draw a circle I needed to figure out what the coordinates of the circle would be. So I looked it up and it turns out you can use this equation to calculate where a coordinate on a circle will be:
x = centerX + radius * cos(angle)
y = centerY + radius * sin(angle)
So if we were to start with an angle of 0 and increment it, until it was 360, we would have a full circle.
function drawCircle(r) {
while(angle < 360) {
x = centerX + r * Math.cos(angle);
y = centerY + r * Math.sin(angle);
values[x][y] = maxRadius - r;
angle += 1;
}
}
drawCircle(radius);
This will put the first circle into our array. So it will now look like this:
[[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0],
[0, 1, 0, 0, 0, 1],
[0, 1, 0, 0, 0, 1],
[0, 1, 0, 0, 0, 1],
[0, 0, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0]]
Now we just need to reduce the radius to draw a circle inside that. Whilst it does draw a square in this array, it's simply because it's only a small example, with bigger examples it does begin to look more like a circle, see the screenshot at the bottom of the post for a bigger example.
I wrote a loop to reduce the radius so that we could get our gradient effect.
while(radius > 0) {
drawCircle(radius);
angle = 0;
radius --;
}
Et voila. Run that loop and you'll have something that looks like this:
[ [ 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 1, 1, 1, 0 ],
[ 0, 1, 2, 2, 2, 1 ],
[ 0, 1, 2, 3, 2, 1 ],
[ 0, 1, 2, 2, 2, 1 ],
[ 0, 0, 1, 1, 1, 0 ],
[ 0, 0, 0, 0, 0, 0 ] ]
Here's a bigger example:
Radial Gradient in an array
HTH
I've already left one answer on here, however there's a different (and better) way to do this.
This solution assumes that the centre of the array is the source of the gradient (the highest point).
The premise is that you iterate over each item in the array and calculate it's distance to the middle point using the Euclidean distance.
This essentially states that the distance between two points can be found by calculating the square root of ∆x2 + ∆y^2.
Here's the implementation for a 9x9
array:
var grid = []
var gridWidth = 9
var gridHeight = 9
var euclideanDistance = (point1, point2) => {
return Math.sqrt(
Math.abs(Math.pow(point1.x - point2.x, 2)) +
Math.abs(Math.pow(point1.y - point2.y, 2))
)
}
var centrePoint = {x: Math.floor(gridWidth / 2), y: Math.floor(gridHeight / 2)}
var furthestDistanceFromCentre = euclideanDistance(
{x: 0, y: 0}, centrePoint
)
for (var x = 0; x < gridWidth; x++) {
grid[x] = []
for (var y = 0; y < gridHeight; y++) {
grid[x][y] = Math.floor(
furthestDistanceFromCentre - euclideanDistance(
{x: x, y: y}, centrePoint
)
)
}
}
Here's the output:
[0, 0, 1, 1, 1, 1, 1, 0, 0]
[0, 1, 2, 2, 2, 2, 2, 1, 0]
[1, 2, 2, 3, 3, 3, 2, 2, 1]
[1, 2, 3, 4, 4, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 4, 4, 3, 2, 1]
[1, 2, 2, 3, 3, 3, 2, 2, 1]
[0, 1, 2, 2, 2, 2, 2, 1, 0]
[0, 0, 1, 1, 1, 1, 1, 0, 0]
The reason this works better is because you don't miss any points, every cell in the grid is accounted for. If you're using the other solution I posted, you may end up with gaps here and there which is less than ideal.
This will give you a smooth, gapless result every time.
I wrote an article on a use case of this here.
Here's a gradient that the points on a circle technique generates:
Here's a gradient that the euclidean distance technique generates:
One possibility is to do a Gaussian gradient. Because a Gaussian function is separable, you can apply it on the x values and on the y values independently.
You can just take the formula on this page and implement it in code. https://en.wikipedia/wiki/Gaussian_function#Two-dimensional_Gaussian_function
In order to do that, your x0 and y0 would be the indexes of the center of your array (3,3). You would just iterate through your array and calculate the value of the linked function for each array element. That would provide your alpha factor.
Finally, this is only one type of gradient falloff function. It's a normal curve, so it gives you a pleasant gradation from most intense to least intense. If you'd like a different kind of curve, you can use the d = sqrt((x-x0)^2 + (y-y0)^2)
template for the distance from your matrix's center to construct functions based on d