js实现固定区域内的不重叠随机圆


Posted in Javascript onOctober 24, 2019

本文实例为大家分享了js实现固定区域内的不重叠随机圆,供大家参考,具体内容如下

关键词:js、固定区域、不重叠、随机圆,半径固定、半径随机

最近公司有一个需求就是在一个固定的区域(500X500)内显示10个圆,且半径固定,而且不重叠

因为圆的个数固定,而且半径固定,那么就有可能会没有解决方案。

不过其实也没有很难,处理好半径的最大值就好了。

效果图:

js实现固定区域内的不重叠随机圆

思路:

(固定半径)

step1:先在区域内生成一个随机的圆心坐标,
step2:然后拿一个固定半径(从大到小拿固定半径)
step3:判断圆心和半径是否合法(是否超边距,或者两个圆相交)
step4:如果不合法,重新执行step2和step3
step5:如果合法,记为一个新圆
step6:重复step1~5,直到生成10个圆

(随机半径)

step1:先在区域内生成一个随机的圆心坐标,
step2:根据圆心坐标,与其他圆比较,获取最短的圆心距减去比较圆的半径(圆心距-R n  RnR_n)的值,作为新圆的半径(这样就会生成一个相切的圆)
step3:判断圆心和半径是否合法(是否超边距)
step4:如果不合法,重新执行step2和step3
step5:如果合法,记为一个新圆
step6:重复step1~5,直到生成10个圆

代码:

// 参数
let obj = {
  id: string, // canvas 的id
  fix:boolean, // 是否固定半径,默认为false
  minMargin: Number, // 两个圆的最短距离,默认为10
  minRadius: Number, 最小的圆半径,默认为30
  radiuArr: Array, 圆的半径的数组,当fix为true时该值必须填
  total: Number ,圆的个数,默认为10
}
<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="500" height="500" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>

<script>
class Circle {
  constructor(x, y, r, color){
    this.x = x
    this.y = y
    this.r = r,
    this.c = color ? color : this.getRandomColor()
  }
  getRandomColor(){ 
    let r = Math.floor(Math.random()*100) + 155
    let g = Math.floor(Math.random()*100) + 155
    let b = Math.floor(Math.random()*100) + 155
    return `rgb(${r},${g},${b})` 
  } 
}

class RandomCircle {

  constructor(obj) {
    this.c      = document.getElementById(obj.id);
    this.ctx     = this.c.getContext("2d");
    this.dWidth   = this.c.width;
    this.dHeight   = this.c.height

    this.fix     = obj.fix || false;
    this.minMargin  = obj.minMargin || 10 
    this.minRadius  = obj.minRadius || 30
    this.radiuArr  = obj.radiuArr || [80,70,60,50,45,40,40,35,35,30]
    this.total = obj.total || 10
    this.circleArray = []
    this.circleNumber = 1
  }


  drawOneCircle(c) {
    let ctx = this.ctx;
    ctx.beginPath();
    ctx.strokeStyle = c.c;
    ctx.fillStyle=c.c;
    ctx.arc(c.x, c.y, c.r, 0, 2*Math.PI);
    ctx.stroke();
    ctx.fill();

    ctx.fillStyle='black';
    ctx.fillText('No:'+this.circleNumber, c.x-10, c.y-5);
    ctx.fillText('R:'+c.r, c.x-10, c.y+5);
    this.circleNumber ++ 
  }

  check(x,y,r) {
    return !(x+r > this.dWidth || x-r < 0 || y + r > this.dHeight || y-r < 0)
  }

  // 获取一个新圆的半径,主要判断半径与最近的一个圆的距离
  getR(x,y) {
    if (this.circleArray.length === 0) return Math.floor(Math.random()*20 + 80)
    let lenArr = this.circleArray.map(c => {
      let xSpan = c.x-x
      let ySpan = c.y-y
      return Math.floor(Math.sqrt(Math.pow(xSpan,2) + Math.pow(ySpan,2))) - c.r
    })
    let minCircleLen = Math.min(...lenArr)
    let minC = this.circleArray[lenArr.indexOf(minCircleLen)]
    let tempR = this.fix ? this.radiuArr[this.circleArray.length] : minCircleLen - this.minMargin
    let bool = this.fix ? (tempR <= minCircleLen - minC.r) : (tempR >= this.minRadius)
    return bool ? tempR : false
  }

  // 生成一个圆,随机生成圆心。
  // 如果连续生成200次半径都没有合适的话,终止进程
  createOneCircle(){
    let x,y,r;
    let createCircleTimes = 0
    while(true) {
      createCircleTimes ++ 
      x = Math.floor(Math.random()*this.dWidth)
      y = Math.floor(Math.random()*this.dHeight)
      let TR = this.getR(x,y)
      if (!TR) {
        continue;
      } else {
        r = TR
      }
      if (this.check(x,y,r) || createCircleTimes > 200) {
        break
      }

    }
    this.check(x,y,r) && this.circleArray.push(new Circle(x, y, r))

  }

  // 如果生成100次新圆都失败的话,终止方案。
  // 如果生成100种方案都没有合适可用的话,终止进程。
  init() {
    let n = 0
    while(this.circleArray.length < this.total) {
      this.circleArray = []
      let i = 0;
      while (this.circleArray.length < this.total) {
        this.createOneCircle()
        i ++ 
        if (i >= 100) {
          break;
        }
      }
      n ++ 
      if (n > 100) {
        break;
      }
    }
    // 根据半径从大到小画圆。
    this.circleArray.sort( (a,b) => b.r-a.r).forEach(c => {
      this.drawOneCircle(c)
    })
  }
}


let p = new RandomCircle({id: 'myCanvas', total: 20})
p.init()

console.log(p.circleArray)

</script> 
</body>
</html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
用JavaScript编写COM组件的步骤
Mar 17 Javascript
js操作select控件的几种方法
Jun 02 Javascript
jQuery 联动日历实现代码
May 31 Javascript
jquery简单的弹出层浮动层代码
Apr 27 Javascript
简介JavaScript中的setHours()方法的使用
Jun 11 Javascript
原生javascript实现解析XML文档与字符串
Mar 01 Javascript
JS控制文本域只读或可写属性的方法
Jun 24 Javascript
AngularJS实现用户登录状态判断的方法(Model添加拦截过滤器,路由增加限制)
Dec 12 Javascript
vue单页应用加百度统计代码(亲测有效)
Jan 31 Javascript
微信自定义分享链接信息(标题,图片和内容)实现过程详解
Sep 04 Javascript
jquery将信息遍历到界面上实例代码
Jan 21 jQuery
JavaScript小技巧带你提升你的代码技能
Sep 15 Javascript
js实现随机div颜色位置 类似满天星效果
Oct 24 #Javascript
windows实现npm和cnpm安装步骤
Oct 24 #Javascript
JS实现简单随机3D骰子
Oct 24 #Javascript
JS合并两个数组的3种方法详解
Oct 24 #Javascript
js实现简单掷骰子小游戏
Oct 24 #Javascript
js实现GIF图片的分解和合成
Oct 24 #Javascript
js实现掷骰子小游戏
Oct 24 #Javascript
You might like
详细介绍PHP应用提速面面观
2006/10/09 PHP
PHP 上传文件的方法(类)
2009/07/30 PHP
php 数组排序 array_multisort与uasort的区别
2011/03/24 PHP
Symfony核心类概述
2016/03/17 PHP
php使用include 和require引入文件的区别
2017/02/16 PHP
lyhucSelect基于Jquery的Select数据联动插件
2011/03/29 Javascript
jQuery 的全选(全非选)即取得被选中的值使用介绍
2013/11/12 Javascript
使用AngularJS对路由进行安全性处理的方法
2015/06/18 Javascript
javascript实现textarea中tab键的缩排处理方法
2015/06/26 Javascript
jQuery在线选座位插件seat-charts特效代码分享
2015/08/27 Javascript
JS实现横向与竖向两个选项卡Tab联动的方法
2015/09/27 Javascript
jQuery实现的精美平滑二级下拉菜单效果代码
2016/03/28 Javascript
JavaScript实现刷新不重记的倒计时
2016/08/10 Javascript
javascript数字验证的实例代码(推荐)
2016/08/20 Javascript
angular-tree-component的使用详解
2018/07/30 Javascript
element-ui 本地化使用教程详解
2019/10/28 Javascript
[04:52]第二届DOTA2亚洲邀请赛主赛事第一天比赛集锦:OG娜迦海妖放大配合谜团大中3人
2017/04/02 DOTA
[01:01]青春无憾,一战成名——DOTA2全国高校联赛开启
2018/02/25 DOTA
Python的净值数据接口调用示例分享
2016/03/15 Python
python 缺失值处理的方法(Imputation)
2019/07/02 Python
使用Django搭建一个基金模拟交易系统教程
2019/11/18 Python
Python 实现Image和Ndarray互相转换
2020/02/19 Python
基于Python 的语音重采样函数解析
2020/07/06 Python
使用python编写一个语音朗读闹钟功能的示例代码
2020/07/14 Python
Python+Kepler.gl实现时间轮播地图过程解析
2020/07/20 Python
基于Python实现全自动下载抖音视频
2020/11/06 Python
详解CSS3 弹性布局快速入门
2019/06/06 HTML / CSS
LEGO玩具英国官方商店:LEGO Shop GB
2018/03/27 全球购物
技术人员面试提纲
2013/11/28 职场文书
求职信需要的五点内容
2014/02/01 职场文书
优秀毕业生推荐信范文
2014/03/07 职场文书
《毛主席在花山》教学反思
2014/04/20 职场文书
让生命充满爱演讲稿
2014/05/10 职场文书
乡镇领导干部个人对照检查材料思想汇报
2014/09/23 职场文书
《比尾巴》教学反思
2016/02/24 职场文书
JPA 通过Specification如何实现复杂查询
2021/11/23 Java/Android