How can I make 3 circles with different radius “stick” together? (with an example image)

I have a graph, which is represented by three circles of different sizes, based on the presence of this element in the result set. The first circle is always 100%, because this is the largest circle, the other two are% to the largest.

The problem is that I am trying to use css to render them, and I don’t know the math needed to figure out how to make them stick together around.

Known fragments will be the radius of each circle, and the largest will always be returned first.

Here is an example of what I'm trying to accomplish:

enter image description here

How can I do this mathematically so that I can supply each circle with an edge-edge and a left mark that will place them this way?

I can position the largest circle at 0.0, and the second largest at half the difference between the two diameters, forcing the center points to line up. The real challenge is the third smallest circle, knowing where to position it, based on the positions of the other two circles.

+4
source share
4 answers

Build a triangle with a radius of sides 0, radius1 and radius2 and calculate the third coordinate of the vertices (the smallest center of the circle). I used the formula (23) from here in my calculations. There is Delphi code, but I hope the principle is clear.

var r0, r1, r2: Integer; x0, x1, x2, y0, y1, y2: Integer; a, b, c, ca: Double; begin //some intialization Canvas.FillRect(ClientRect); Randomize; r0 := 200; r1 := Round(r0 * (0.25 + 0.75 * Random)); r2 := Round(r1 * (0.25 + 0.75 * Random)); //circle centers' coordinates //biggest x0 := r0; y0 := r0; //second x1 := x0 + r0 + r1; y1 := y0; //triangle sides c := r0 + r1; b := r0 + r2; a := r1 + r2; //x-shift ca := (c * c + b * b - a * a) / (2.0 * c); x2 := x0 + Round(ca); //y-shift is the height of triangle //Pythagor rule y2 := y0 + Round(Sqrt(b * b - ca * ca)); //draw calculated circles Canvas.Ellipse(x0 - r0, y0 - r0, x0 + r0 + 1, y0 + r0 + 1); Canvas.Ellipse(x1 - r1, y1 - r1, x1 + r1 + 1, y1 + r1 + 1); Canvas.Ellipse(x2 - r2, y2 - r2, x2 + r2 + 1, y2 + r2 + 1); 

Output Example: enter image description here

+5
source

Ok, skip each one of them ... let's assume that your 100% circle has radius x (so B will be Bx, and c could be Cx, B = .7 and C = .3 as an example).

As the other side, I would have <div style="position: relative"></div> and then your circles would be <div style="position: absolute, top: 0, left: 0"></div> instead of using margin-top / margin-left

Any. Obviously will have top / left = 0.

From your image, it looks like the centers A and B are lining up ... This would mean that B would have left = 2x and top = (1 - B)x

C is the hard part ... I'll just put a brief paint triangle for reference

You can first use Cosines Law to find the angle at point A

 (B + C)² = (1 + B)² + (1 + C)² - 2(1 + B)(1 + C)cos A cosA = (BC - B - C - 1)/(BC + B + C + 1) 

Using regular Trigonometry , we can also get the height ...

 sin A = h / (1 + C) 

Using the rule

 sin² A + cos² A = 1 

We can combine and receive

 h = (1 + C) √ (1 - cos² A) 

Of course, to get the top, we need to add 1 and minus C

 top = ((1 + C) √ (1 - cos² A) + 1 - C)x 

Using the trigger again, we can get the left side ...

 cos A = l / (1 + C) l = (1 + C)cos A 

Of course, to leave, we need to add 1 and take C ...

 left = ((1 + C)cos A + 1 - C)x 

I created an example using border-radius to create circles with B = .7 and C = .3 and x = 50px: http://jsfiddle.net/FelixJorkowski/xArpR/

+3
source

Here is my python implementation of @MBo code

  r0 = 100
 r1 = 50
 r2 = 25

 #circles
 #biggest
 x0 = r0
 y0 = r0

 # 2nd
 x1 = x0 + r0 + r1
 y1 = y0

 #sides
 c = r0 + r1
 b = r0 + r2
 a = r1 + r2

 # x-shift
 ca = (c * c + b * b - a * a) / (2.0 * c)
 x2 = x0 + round (ca)

 # y-shift is the height of triangle
 y2 = y0 + round (math.sqrt (b * b - ca * ca))

 left_a = x0 - r0
 top_a = y0 - r0
 width_a = r0 * 2
 border_radius_a = width_a / 2

 left_b = x1 - r1
 top_b = y1 - r1
 width_b = r1 * 2
 border_radius_b = width_b / 2

 left_c = x2 - r2
 top_c = y2 - r2
 width_c = r2 * 2
 border_radius_c = width_c / 2 
0
source

A solution using the Canvas element in case another stumbles upon this.

http://jsfiddle.net/5mgLY/

 var centerpoint = 50; var radius = randomFromInterval(30, 50); //starting circle between 30 and 50 var radius2 = radius * randomFromInterval(5, 9) / 10; //between .5 and .9 of starting circle var radius3 = radius2 * randomFromInterval(3, 8) / 10; //between .3 and .8 of medium circle var c=document.getElementById("myCanvas"); var ctx=c.getContext("2d"); //draw the big circle ctx.beginPath(); ctx.arc(centerpoint,centerpoint,radius,0,2*Math.PI,false); ctx.fillStyle = 'green'; ctx.fill(); ctx.stroke(); //draw the medium circle ctx.beginPath(); ctx.arc(centerpoint + radius + radius2,50,radius2,0,2*Math.PI); ctx.fillStyle = 'red'; ctx.fill(); ctx.stroke(); //find the length of each side of the triangle that forms between the three circles var hypotenuse = radius + radius2; var side1 = radius + radius3; var side2 = radius2 + radius3; //get x and y offsets var xOffset = ((hypotenuse*hypotenuse) + (side1*side1) - (side2*side2)) / (2 * hypotenuse); var yOffset = Math.sqrt(side1 * side1 - xOffset * xOffset); //draw the small circle ctx.beginPath(); ctx.arc(centerpoint + xOffset,centerpoint + yOffset,radius3,0,2*Math.PI); ctx.fillStyle = 'blue'; ctx.fill(); ctx.stroke(); function randomFromInterval(from,to) { return Math.floor(Math.random()*(to-from+1)+from); } function toDegrees (angle) { return angle * (180 / Math.PI); } 
0
source

All Articles