4

我有一个图表,它由三个不同大小的圆圈表示,基于结果集中给定元素的存在。第一个圆圈始终设置为 100%,这是最大的圆圈,其他两个是相对于最大圆圈的百分比。

问题是我正在尝试使用 css 来渲染它们,但我不知道如何让它们沿着它们的两侧“粘”在一起所需的数学。

已知的部分将是每个圆的半径,并且总是首先返回最大的部分。

这是我要完成的示例:

在此处输入图像描述

我怎样才能在数学上完成这一点,以便我可以为每个圆圈提供一个边距顶部和左边距,从而以这种方式定位它们?

我可以将最大的圆定位在 0,0 处,将第二大的圆定位在两个直径之差的一半处,使中心点对齐。真正的挑战是第三个最小的圆圈,即根据其他两个圆圈的位置知道将其放置在哪里。

4

4 回答 4

5

用半径 0、半径 1 和半径 2 构建三角形并计算第三个顶点坐标(最小圆心)。我在计算中使用了这里的公式(23)。有Delphi代码,但希望原理清楚。

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);

示例输出: 在此处输入图像描述

于 2013-01-29T04:09:19.743 回答
3

好的,让我们逐一介绍...假设您的 100% A 圆的半径为 x(例如,B 是 Bx,c 可能是 Cx,B = .7 和 C = .3)。

另外,我实际上会有一个<div style="position: relative"></div>,然后你的圈子将<div style="position: absolute, top: 0, left: 0"></div>不是使用 margin-top/margin-left

无论如何。显然,top/left = 0。

从您的图片来看,A 和 B 的中心似乎排成一行……这意味着 B 将拥有left = 2x并且top = (1 - B)x

C 是最难的部分...我将快速绘制三角形以供参考

首先让我们使用余弦定律找到 A 处的角度

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

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

使用正常的三角函数,我们也可以得到高度......

sin A = h / (1 + C)

使用规则

sin² A + cos² A = 1

我们可以结合得到

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

当然要得到顶部,我们需要加 1 和减 C

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

再次使用 trig 我们可以得到左侧...

cos A = l / (1 + C)

l = (1 + C)cos A

当然要离开,我们必须加 1 并取 C ......

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

我创建了一个示例,使用边界半径来创建 B = .7 和 C = .3 和 x = 50px 的圆圈:http: //jsfiddle.net/FelixJorkowski/xArpR/

于 2013-01-29T04:40:20.893 回答
0

这是我的@MBo 代码的python 实现

r0 = 100
r1 = 50
r2 = 25

#界
#最大
x0 = r0
y0 = r0

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

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

#x 班次
ca = (c * c + b * b - a * a) / (2.0 * c)
x2 = x0 + 圆形(ca)

#y-shift 是三角形的高度
y2 = y0 + round(math.sqrt(b * b - ca * ca))

left_a = x0 - r0
top_a = y0 - r0
宽度_a = r0 * 2
边界半径_a = 宽度_a / 2

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

left_c = x2 - r2
top_c = y2 - r2
宽度_c = r2 * 2
边界半径_c = 宽度_c / 2
于 2013-01-29T16:38:21.543 回答
0

使用 Canvas 元素的解决方案,以防其他人偶然发现。

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);
}
于 2013-01-30T05:04:14.883 回答