<center><canvas id=c1 width=400 height=400></canvas>
<script>
ctx = c1.getContext('2d')
ctx.fillStyle = '#7ef' // draw blue background with the darker frame
ctx.fillRect(0, 0, 400, 400)
ctx.fillStyle = '#9ff'
ctx.fillRect(10, 10, 400-20, 400-20)
var X = 75, W = 50, G = 20
ctx.lineWidth = 10
var colors = ['blue', 'black', 'red', 'yellow', 'green']
var args = [
[X,X,W],
[X+W+W+G,X,W],
[X+W+W+G+W+W+G,X,W],
[X+W+G/2,X+W,W],
[X+W+G/2+W+W+G,X+W,W]]
while (colors.length > 0) {
ctx.strokeStyle = colors.shift()
ctx.beginPath()
ctx.arc.apply(ctx, args.shift().concat([0,Math.PI*2,true]))
ctx.stroke()
}
</script>
Above is my code at this moment. My goal is to amuse children, there are 12 year old boys, but my code is not amazing enough, is it possible to make it less boring by removing all hand-coded coordinates? Also it would be cool to make rings "interconnected", but how to achieve that?
Here is the output of my current code:
And this is what Olympics rings are supposed to look like:
For the 12 year olds!
I wrote some code for you which is not necessarily boring or amusing, easy or difficult, but it gets the job done:
var canvas = document.getElementById('c1').getContext('2d');
var radius = 50;
var circles = [
{
color:'blue',
x : 2*radius - radius/2,
y : 2*radius,
isTop: true
} , {
color:'black',
x : 4*radius,
y : 2*radius,
isTop: true
} , {
color:'red',
x : 6*radius + radius/2,
y : 2*radius,
isTop: true
} , {
color:'yellow',
x : 3*radius - radius/4,
y : 3*radius,
isTop: false
} , {
color:'green',
x : 5*radius + radius/4,
y : 3*radius,
isTop: false
}
];
function drawArc(canvas, color, x, y, start, end) {
if (color !== 'white') drawArc(canvas, 'white', x, y, start, end);
canvas.lineWidth = color === 'white' ? 16 : 10;
canvas.strokeStyle = color;
canvas.beginPath();
canvas.arc(x, y, radius, start - Math.PI/2, end - Math.PI/2, true);
canvas.stroke();
}
circles.forEach(function(circle){
drawArc(canvas, circle.color, circle.x, circle.y, 0, Math.PI*2);
});
circles.forEach(function(circle){
if (circle.isTop) {
drawArc(canvas, circle.color, circle.x, circle.y, Math.PI, Math.PI*2/3);
drawArc(canvas, circle.color, circle.x, circle.y, Math.PI*5/3, Math.PI*4/3);
} else {
drawArc(canvas, circle.color, circle.x, circle.y, 0, Math.PI/3);
drawArc(canvas, circle.color, circle.x, circle.y, Math.PI*2/3, Math.PI/3);
}
});
http://jsbin.com/IrOJOhIg/1/edit
If i were to explain the code, i'd start with the circles variable, which is an array which says for each circle it's color, center and whether it is on the top row or not. I would comment out the += radius/2
and radius/4
parts and run the code for them, showing that the circles are too tight together, and uncomment them to show that changing the x coordinate moves them apart.
I would then explain the drawArc
function which draws a part of a circle, first with white and then with the actual color, in different line widths. This is pretty much the most difficult part of the whole script.
Finally, i would run the script again with the final forEach commented out, to show that the last rings drawn completely cover the previous ones and ask the 12 year olds for a solution. The solution you should aim for is drawing the circles in parts.
I have split the circle in 6 pieces starting from the top and if you take a good glance at them you will see that the same part can be either covered or on top if the circle is on the top row or not. The final for each redraws the 2 parts of each circle that must be on top in intersections.
Finally, bonus points for the 12 year old who notices that the intersections are actually reversed in my code and more bonus points for the one who comes up with a solution. (Obviously the simplest solution is to fiddle with the last forEach). EDIT: Actually just putting the condition as !circle.isTop
is ever simpler.
PS: There are some rounding errors that result in thin white lines where the arcs meet. They can be fixed, but i didn't bother with them.
JSFIDDLE
var canvas = document.getElementById('c1').getContext('2d');
var radius = 50;
var circles = [
{ color:'blue', x: 2*radius - radius/2, y: 2*radius, q: [1,2,3,0] },
{ color:'black', x: 4*radius, y: 2*radius, q: [2,0,1,3] },
{ color:'red', x: 6*radius + radius/2, y: 2*radius, q: [2,0,1,3] },
{ color:'yellow', x: 3*radius - radius/4, y: 3*radius, q: [3,0,1,2] },
{ color:'green', x: 5*radius + radius/4, y: 3*radius, q: [3,0,1,2] }
];
function drawArc(canvas, circle, q) {
var s = (circle.q[q]+0.5)/2 * Math.PI,
e = (circle.q[q]-0.5)/2 * Math.PI;
canvas.lineWidth = 16;
canvas.strokeStyle = 'white';
canvas.beginPath();
canvas.arc( circle.x, circle.y, radius, s, e, true );
canvas.stroke();
canvas.lineWidth = 10;
canvas.strokeStyle = circle.color;
canvas.beginPath();
canvas.arc( circle.x, circle.y, radius, s, e, true );
canvas.stroke();
}
for ( var q = 0; q < 4; ++q ){
circles.forEach(function(circle){
drawArc( canvas, circle, q );
})
}
At each step of the for
loop a quarter arc (quadrant) is drawn for each circle - circle.q
determines the order in which the quadrants are drawn around the circle and by careful ordering you can get it to draw the quadrants going under another ring before that other ring is drawn on top.
(Thanks to Tibos for the initial code)
If you want to make it more "interesting" then you can make the arc lengths smaller and add a delay between each draw to "animate" the appearance of the rings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With