Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make 3 circles with a different radius "stick" together? (with example image)

I have a graph that is represented by three different sized circles, based on the presence of a given element in the result set. The first circle is always set to 100%, being this is the largest the circle can be, the other two are relative % to the largest one.

The problem is that I am trying to use css to render them and I do not know the math necessary to figure out how to make them all "stick" together along their sides.

The known pieces will be the radius of each circle, and the largest one is always returned first.

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

enter image description here

How can I accomplish this mathematically such that i can supply each circle with a margin-top and margin-left that will position them in this way?

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

like image 594
Steve-O-Rama Avatar asked Feb 17 '23 17:02

Steve-O-Rama


2 Answers

Build triangle with sides radius0, radius1 and radius2 and calculate the third vertex coordinate (smallest circle center). I've used formula (23) from here in my calculation. 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's 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);

example output: enter image description here

like image 145
MBo Avatar answered Mar 30 '23 00:03

MBo


Ok, lets go through each one... lets assume your 100% A circle has radius x (so B be would be Bx and c might be Cx, B = .7 and C = .3 as an example).

As another aside I would actually have a <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

ANYWAYS. Obviously will have top/left = 0.

From your picture it looks like the centers of A and B line up... This would mean B would have left = 2x and top = (1 - B)x

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

First lets use the Law of Cosines to find the angle at A

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

cosA = (BC - B - C - 1)/(BC + B + C + 1)

Using normal Trigonometry we can also get the height...

sin A = h / (1 + C)

Using the rule

sin² A + cos² A = 1

We can combine and get

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 trig again we can get the left side...

cos A = l / (1 + C)

l = (1 + C)cos A

Of course to get left we have to add 1 and take C...

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

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

like image 24
Felix Avatar answered Mar 29 '23 22:03

Felix