【问题标题】:Positioning divs in a circle using JavaScript使用 JavaScript 将 div 定位在一个圆圈中
【发布时间】:2018-02-28 06:50:18
【问题描述】:

我试图将 15 个div 元素均匀地放置在半径为150px 的圆中。我正在使用以下代码,它似乎给出了一个奇怪的、偏心的椭圆重叠。

Fiddle

// Hold a global reference to the div#main element.  Initially assign it ... somewhere useful :)
var main = document.getElementById('main');
var circleArray = [];

// Move a circle based on the distance of the approaching mouse
var moveCircle = function(circle, dx, dy) {

};

// Look at all the circle elements, and figure out if any of them have to move.
var checkMove = function() {

};
var setup = function() {
  for (var i = 0; i < 15; i++) {
    //create element, add it to the array, and assign it's coordinates trigonometrically.
    //Then add it to the "main" div
    var circle = document.createElement('div');
    circle.className = 'circle number' + i;
    circleArray.push(circle);
    circleArray[i].posx = Math.round((150 * Math.cos(i * (2 * Math.PI / 15)))) + 'px';
    circleArray[i].posy = Math.round((150 * Math.sin(i * (2 * Math.PI / 15)))) + 'px';
    circleArray[i].style.position = "relative";
    circleArray[i].style.top = circleArray[i].posy;
    circleArray[i].style.left = circleArray[i].posx;
    main.appendChild(circleArray[i]);
  }
};
setup();
window.addEventListener('load', function() {

});
div {
  box-sizing: border-box;
}
div#main {
  position: absolute;
  left: 50%;
  top: 50%;
}
div.circle {
  position: absolute;
  width: 20px;
  height: 20px;
  border: 2px solid black;
  border-radius: 10px;
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
}
&lt;div id="main"&gt;&lt;/div&gt;

关于我可能做错了什么有什么建议吗?

【问题讨论】:

  • 请包含相应的HTML。
  • 完成。 “主”元素仅在主 HTML div 上使用 getElementById 方法找到。
  • circleArray 也没有定义,但无论如何,我想我们错过了一些你正在使用的基本 CSS,你能提供吗? (我猜就是你的代码中的'probmem.css')
  • 如果你也包含你的 CSS 会更好。
  • 已更新以包含 css... 此外,circleArray 在脚本的前面被全局定义为我要推送的空数组。还包括一个指向 JSFiddle 的链接,以防我忘记了一些代码,这样每个人都可以看到问题。提前致谢!

标签: javascript html css


【解决方案1】:

首先,圆上的坐标方程很简单:

(x, y) = (r * cos(θ), r * sin(θ))

其中,r 是圆的半径,θ 是以弧度为单位的角度。


您的代码创建偏心椭圆的原因是,当您分配 .top.left CSS 值时,您并没有考虑到它实际上会将左上角作为其参考。我已经修复了你的代码,现在它创建了一个完美的圆圈。

对您的代码所做的更改:

  1. 添加了一个包含所有角度的数组theta

    var theta = [0, Math.PI / 6, Math.PI / 4, Math.PI / 3, Math.PI / 2, 2 * (Math.PI / 3), 3 * (Math.PI / 4), 5 * (Math.PI / 6), Math.PI, 7 * (Math.PI / 6), 5 * (Math.PI / 4), 4 * (Math.PI / 3), 3 * (Math.PI / 2), 5 * (Math.PI / 3), 7 * (Math.PI / 4), 11 * (Math.PI / 6)];
    

    下图显示了我使用的所有角度。

  2. 添加了一个包含不同颜色的数组colors

    var colors = ['red', 'green', 'purple', 'black', 'orange', 'yellow', 'maroon', 'grey', 'lightblue', 'tomato', 'pink', 'maroon', 'cyan', 'magenta', 'blue', 'chocolate', 'DarkSlateBlue'];
    
  3. 对三角方程进行了更改。

    circleArray[i].posx = Math.round(radius * (Math.cos(theta[i]))) + 'px';
    circleArray[i].posy = Math.round(radius * (Math.sin(theta[i]))) + 'px';
    
  4. 更改了.top.left 的分配方式。

    circleArray[i].style.top = ((mainHeight / 2) - parseInt(circleArray[i].posy.slice(0, -2))) + 'px';
    circleArray[i].style.left = ((mainHeight / 2) + parseInt(circleArray[i].posx.slice(0, -2))) + 'px';
    

    其中mainHeight#main div 的高度。


[1] 16 divs

Fiddle 上的演示

var setup = function() {
  var radius = 150;
  var main = document.getElementById('main');
  var mainHeight = parseInt(window.getComputedStyle(main).height.slice(0, -2));
  var theta = [0, Math.PI / 6, Math.PI / 4, Math.PI / 3, Math.PI / 2, 2 * (Math.PI / 3), 3 * (Math.PI / 4), 5 * (Math.PI / 6), Math.PI, 7 * (Math.PI / 6), 5 * (Math.PI / 4), 4 * (Math.PI / 3), 3 * (Math.PI / 2), 5 * (Math.PI / 3), 7 * (Math.PI / 4), 11 * (Math.PI / 6)];
  var circleArray = [];
  var colors = ['red', 'green', 'purple', 'black', 'orange', 'yellow', 'maroon', 'grey', 'lightblue', 'tomato', 'pink', 'maroon', 'cyan', 'magenta', 'blue', 'chocolate', 'DarkSlateBlue'];
  for (var i = 0; i < 16; i++) {
    var circle = document.createElement('div');
    circle.className = 'circle number' + i;
    circleArray.push(circle);
    circleArray[i].posx = Math.round(radius * (Math.cos(theta[i]))) + 'px';
    circleArray[i].posy = Math.round(radius * (Math.sin(theta[i]))) + 'px';
    circleArray[i].style.position = "absolute";
    circleArray[i].style.backgroundColor = colors[i];
    circleArray[i].style.top = ((mainHeight / 2) - parseInt(circleArray[i].posy.slice(0, -2))) + 'px';
    circleArray[i].style.left = ((mainHeight / 2) + parseInt(circleArray[i].posx.slice(0, -2))) + 'px';
    main.appendChild(circleArray[i]);
  }
};
setup();
div#main {
  height: 300px;
  width: 300px;
  position: absolute;
  margin: 0 auto;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
}
div.circle {
  position: absolute;
  width: 20px;
  height: 20px;
  border: 2px solid black;
  border-radius: 50%;
}
body {
  margin: 0 auto;
  background: papayawhip;
}
&lt;div id="main"&gt;&lt;/div&gt;

[2] 15 divs 均匀定位

Fiddle 上的演示

var setup = function() {
  var radius = 150;
  var main = document.getElementById('main');
  var mainHeight = parseInt(window.getComputedStyle(main).height.slice(0, -2));
  var theta = [0, (2 * (Math.PI / 15)), (4 * (Math.PI / 15)), (2 * (Math.PI / 5)), (8 * (Math.PI / 15)), (2 * (Math.PI / 3)), (4 * (Math.PI / 5)), (14 * (Math.PI / 15)), (16 * (Math.PI / 15)), (6 * (Math.PI / 5)), (4 * (Math.PI / 3)), (22 * (Math.PI / 15)), (8 * (Math.PI / 5)), (26 * (Math.PI / 15)), (28 * (Math.PI / 15))];
  var circleArray = [];
  var colors = ['red', 'green', 'purple', 'black', 'orange', 'yellow', 'maroon', 'grey', 'lightblue', 'tomato', 'pink', 'maroon', 'cyan', 'magenta', 'blue', 'chocolate', 'DarkSlateBlue'];
  for (var i = 0; i < 15; i++) {
    var circle = document.createElement('div');
    circle.className = 'circle number' + i;
    circleArray.push(circle);
    circleArray[i].posx = Math.round(radius * (Math.cos(theta[i]))) + 'px';
    circleArray[i].posy = Math.round(radius * (Math.sin(theta[i]))) + 'px';
    circleArray[i].style.position = "absolute";
    circleArray[i].style.backgroundColor = colors[i];
    circleArray[i].style.top = ((mainHeight / 2) - parseInt(circleArray[i].posy.slice(0, -2))) + 'px';
    circleArray[i].style.left = ((mainHeight / 2) + parseInt(circleArray[i].posx.slice(0, -2))) + 'px';
    main.appendChild(circleArray[i]);
  }
};
setup();
div#main {
  height: 300px;
  width: 300px;
  position: absolute;
  margin: 0 auto;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
}
div.circle {
  position: absolute;
  width: 20px;
  height: 20px;
  border: 2px solid black;
  border-radius: 50%;
}
body {
  margin: 0 auto;
  background: papayawhip;
}
&lt;div id="main"&gt;&lt;/div&gt;

[3] 在椭圆/圆上动态定位任意数量的divs

椭圆上的坐标方程为:

(x, y) = (r<sub>x</sub> * cos(θ), r<sub>y</sub> * sin(θ))

其中,r<sub>x</sub> 是沿 X 轴的半径,r<sub>y</sub> 是沿 Y 轴的半径。


在这种情况下,函数generate(n, rx, ry, id) 有四个参数,其中ndivs 的数量,rxry 分别是沿 X 和 Y 轴的半径,最后是 @ 987654360@ 是div 中的id,您要在其中添加椭圆排列的divs。

Fiddle 上的演示

var theta = [];

var setup = function(n, rx, ry, id) {
  var main = document.getElementById(id);
  var mainHeight = parseInt(window.getComputedStyle(main).height.slice(0, -2));
  var circleArray = [];
  var colors = ['red', 'green', 'purple', 'black', 'orange', 'yellow', 'maroon', 'grey', 'lightblue', 'tomato', 'pink', 'maroon', 'cyan', 'magenta', 'blue', 'chocolate', 'darkslateblue', 'coral', 'blueviolet', 'burlywood', 'cornflowerblue', 'crimson', 'darkgoldenrod', 'olive', 'sienna', 'red', 'green', 'purple', 'black', 'orange', 'yellow', 'maroon', 'grey', 'lightblue', 'tomato', 'pink', 'maroon', 'cyan', 'magenta', 'blue', 'chocolate', 'darkslateblue', 'coral', 'blueviolet', 'burlywood', 'cornflowerblue', 'crimson', 'darkgoldenrod', 'olive', 'sienna'];
  for (var i = 0; i < n; i++) {
    var circle = document.createElement('div');
    circle.className = 'circle number' + i;
    circleArray.push(circle);
    circleArray[i].posx = Math.round(rx * (Math.cos(theta[i]))) + 'px';
    circleArray[i].posy = Math.round(ry * (Math.sin(theta[i]))) + 'px';
    circleArray[i].style.position = "absolute";
    circleArray[i].style.backgroundColor = colors[i];
    circleArray[i].style.top = ((mainHeight / 2) - parseInt(circleArray[i].posy.slice(0, -2))) + 'px';
    circleArray[i].style.left = ((mainHeight / 2) + parseInt(circleArray[i].posx.slice(0, -2))) + 'px';
    main.appendChild(circleArray[i]);
  }
};

var generate = function(n, rx, ry, id) {
  var frags = 360 / n;
  for (var i = 0; i <= n; i++) {
    theta.push((frags / 180) * i * Math.PI);
  }
  setup(n, rx, ry, id)
}
generate(16, 150, 75, 'main');
div#main {
  height: 300px;
  width: 300px;
  position: absolute;
  margin: 0 auto;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
}
div.circle {
  position: absolute;
  width: 20px;
  height: 20px;
  border: 2px solid black;
  border-radius: 50%;
}
body {
  margin: 0 auto;
  background: papayawhip;
}
&lt;div id="main"&gt;&lt;/div&gt;

编辑[2015 年 12 月 9 日]:

Here's 更灵活的版本,具有起始偏移、顺时针和逆时针功能。

/*
Usage: Position.ellipse(n, rx, ry, so, wh, idd, cls, cw);

where n = number of divs,
      rx = radius along X-axis,
      ry = radius along Y-axis,
      so = startOffset,
      wh = width/height of divs,
      idd = id of main div(ellipse),
      cls = className of divs;
      cw = clockwise(true/false)
*/

var Position = {
  ellipse: function(n, rx, ry, so, wh, idd, cls, cw) {
    var m = document.createElement('div'),
      ss = document.styleSheets;
    ss[0].insertRule('#' + idd + ' { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); border-radius: 50%; box-shadow: inset 0 0 ' + wh + 'px ' + wh / 4 + 'px black; background: rgba(0, 0, 0, 0.2); width: ' + String((rx * 2) + wh) + 'px; height: ' + String((ry * 2) + wh) + 'px; }', 1);
    ss[0].insertRule('.' + cls + '{ position: absolute; background: black; color: papayawhip; text-align: center; font-family: "Open Sans Condensed", sans-serif; border-radius: 50%; transition: transform 0.2s ease; width: ' + wh + 'px; height: ' + wh + 'px; line-height: ' + wh + 'px;}', 1);
    ss[0].insertRule('.' + cls + ':hover { transform: scale(1.2); cursor: pointer; background: rgba(0, 0, 0, 0.8); }', 1);
    m.id = idd;
    for (var i = 0; i < n; i++) {
      var c = document.createElement('div');
      c.className = cls;
      c.innerHTML = i + 1;
      c.style.top = String(ry + -ry * Math.cos((360 / n / 180) * (i + so) * Math.PI)) + 'px';
      c.style.left = String(rx + rx * (cw ? Math.sin((360 / n / 180) * (i + so) * Math.PI) : -Math.sin((360 / n / 180) * (i + so) * Math.PI))) + 'px';
      m.appendChild(c);
    }
    document.body.appendChild(m);
  }
}

Position.ellipse(20, 150, 150, 0, 42, 'main', 'circle', true);
@import url(http://fonts.googleapis.com/css?family=Open+Sans+Condensed:300);
 body {
  margin: 0 auto;
  background: rgb(198, 193, 173);
}

【讨论】:

  • 这很完整,谢谢!我很好奇你使用 slice 方法。我想我误解了它的功能是什么(我认为它与字符串更相关?)
  • 这太棒了。此外,为tomato +1:从未意识到这是 w3c 颜色:)
  • @chipChocolate.py 绝对是。我已经纠正了。我觉得你的帖子很棒。很抱歉,我草率地误点击了;)
  • @thomas - 没关系!谢谢! :)
  • 很棒的帖子,内容丰富!带有随机圆数和直径的分叉小提琴 [5] jsfiddle.net/Lq7tkxj3
【解决方案2】:

没有JS的其他方法

chipChocolate.py 的分析器非常完整,但还有其他方法可以实现您的目标。更简单,不需要JS。

重点是考虑“圆”和旋转,而不是依赖[x,y]坐标:

您需要嵌套所有元素并对它们应用旋转。由于它们是嵌套的,n + 1 元素将根据其直接父级的旋转进行旋转。这是一个DEMO

.circle, .circle div {
    width:24px; height:300px;
    position:absolute;
    left:50%; top:50px;
}
.circle:before, .circle div:before {
    content:'';
    display:block;
    width:20px; height:20px;
    border: 2px solid black;
    border-radius: 100%;
}
.circle div {
    top:0; left:0;
    -webkit-transform : rotate(24deg);
    -ms-transform : rotate(24deg);
    transform : rotate(24deg);
}
<div class="circle">
    <div><div><div><div><div><div><div><div><div><div><div><div><div><div><div>
    </div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>
</div>

圆的直径由元素的高度控制(在演示中height:300px),您可以设置一个百分比以使圆响应(见下文)。

必须根据您想要围绕圆圈的元素数量设置旋转。在演示中 15 个元素,所以 rotation = 360 / 15 = 24deg.

如果你有动态数量的元素,你可以使用 JS 来添加它们并计算所需的旋转角度。


响应式示例

DEMO

.circle{
    position:relative;
    width:5%;padding-bottom:50%;
    margin-left:47.5%;
}
.circle div {
    position:absolute;
    top:0; left:0;
    width:100%; height:100%;
    -webkit-transform : rotate(24deg);
    -ms-transform : rotate(24deg);
    transform : rotate(24deg);
}
.circle:before, .circle div:before {
    content:'';
    position:absolute;
    top:0; left:0;
    width:100%; padding-bottom:100%;
    border-radius: 100%;
    border: 2px solid teal;
    background:gold;
}
<div class="circle">
    <div><div><div><div><div><div><div><div><div><div><div><div><div><div><div>
    </div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>
</div>

【讨论】:

  • 我必须在 javascript 中定位它们,因为我要编写代码来根据 mousemove 操作位置,并且需要脚本知道它们的位置。
  • 好的,我会留下这个答案,以防有人在没有 JS 的情况下需要同样的东西。
  • 对我来说也很棒。新的原生 CSS 功能可能会减少使用复杂 javascript 的需要,因此,如果可能,我更喜欢坚持使用原生而不是 javascript。尽管如此,javascript答案中的大量知识。
【解决方案3】:

另一个解决方案,基于我见过的其他解决方案的想法

http://jsfiddle.net/0hr1n7a2/6/

(function() {
  var radians, radius;

  radius = 150;
    
  var totalItems = 48
  var item = 0;
  function positionTarget() 
  {
    var x, y, angle = 0, step = (2*Math.PI) / totalItems;
    var width = $('#container').width()/2;
    var height = $('#container').height()/2;
    var itemW = 20, itemH = 2;
    var deg = 0;    
 while(item <= totalItems)
 {        
  x = Math.round(width + radius * Math.cos(angle) - itemW/2);
  y = Math.round(height + radius * Math.sin(angle) - itemH/2);        
        //console.log(x + "," + y);
     
  $('#container').append('<div id="'+ item +'"/>')
  $('div#'+item).css('position', 'absolute')
        .css('width', itemW+'px').css('height', itemH+'px')      
        .css('left', x+'px').css('top', y+'px')
        .css('background-color', 'blue')
        .css('transform-origin', x+'px' -y+'px')        
        .css('transform', 'rotate('+ deg +'deg)')
        .css('border', 'solid 1px #000');
     
        angle += step;
        ++item;
        deg += 360/totalItems;
     
        //console.log(deg)
    }
  }

  $('#theButton').on('click', function()
  {
        positionTarget();
  })
    
})();
#container { width: 600px; height: 600px; border: 1px solid #000; position: relative; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="button" id="theButton" value="Draw">    
<div id="container">
</div>

【讨论】:

    【解决方案4】:
    1. 将位置设置为“绝对”。这将允许“top”和“left”从 (0, 0) 定位 div。使用“相对”会将 div 定位在它们通常布局的位置。

    2. 将圆的中心点从 (0, 0) 更改为其他值,例如 (250, 250)。

      circleArray[i].posx = 250 + Math.round((150*Math.cos(i*(2*Math.PI/15)))) + 'px';
      circleArray[i].posy = 250 + Math.round((150*Math.sin(i*(2*Math.PI/15)))) + 'px';
      circleArray[i].style.position = "absolute";
      

    【讨论】:

    • 我希望它们相对于它们通常定位的位置(这是页面的中心作为“主”div的子级,所以它们都围绕着中心页面,基本上)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-08
    • 2020-05-06
    • 1970-01-01
    相关资源
    最近更新 更多