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 相关文章推荐
js中widow.open()方法使用详解
Jul 30 Javascript
js兼容的placeholder属性详解
Aug 18 Javascript
jQuery异步验证用户名是否存在示例代码
May 21 Javascript
jquery+css3打造一款ajax分页插件(自写)
Jun 18 Javascript
JavaScript里实用的原生API汇总
May 14 Javascript
原生JS实现左右箭头选择日期实例代码
Mar 14 Javascript
jQuery除指定区域外点击任何地方隐藏DIV功能
Nov 13 jQuery
解决angularjs中同步执行http请求的方法
Aug 13 Javascript
Vue之mixin全局的用法详解
Aug 22 Javascript
JavaScript数据结构与算法之基本排序算法定义与效率比较【冒泡、选择、插入排序】
Feb 21 Javascript
JavaScript this使用方法图解
Feb 04 Javascript
JS简易计算器实例讲解
Jun 30 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
在PHP3中实现SESSION的功能(一)
2006/10/09 PHP
MayFish PHP的MVC架构的开发框架
2009/08/13 PHP
PHP 创建文件(文件夹)以及目录操作代码
2010/03/04 PHP
php学习之数据类型之间的转换代码
2011/05/29 PHP
简单实现限定phpmyadmin访问ip的方法
2013/03/05 PHP
PHP中把对象转换为关联数组代码分享
2015/04/09 PHP
PHP中strpos、strstr和stripos、stristr函数分析
2016/06/11 PHP
php intval函数用法总结
2019/04/14 PHP
jquery中dom操作和事件的实例学习 下拉框应用
2011/12/01 Javascript
使用JavaScript和C#中获得referer
2014/11/14 Javascript
JQuery ZTree使用方法详解
2017/01/07 Javascript
vuejs使用axios异步访问时用get和post的实例讲解
2018/08/09 Javascript
vue-cli项目代理proxyTable配置exclude的方法
2018/09/20 Javascript
Vue.js实现大转盘抽奖总结及实现思路
2019/10/09 Javascript
bootstrap+spring boot实现面包屑导航功能(前端代码)
2019/10/09 Javascript
原生JS封装拖动验证滑块的实现代码示例
2020/06/01 Javascript
Python开发常用的一些开源Package分享
2015/02/14 Python
Python脚本获取操作系统版本信息
2016/12/17 Python
浅谈Django的缓存机制
2018/08/23 Python
python调用百度语音识别实现大音频文件语音识别功能
2018/08/30 Python
python使用xlrd模块读取xlsx文件中的ip方法
2019/01/11 Python
python 调试冷知识(小结)
2019/11/11 Python
详解字符串在Python内部是如何省内存的
2020/02/03 Python
Python编程快速上手——疯狂填词程序实现方法分析
2020/02/29 Python
python with语句的原理与用法详解
2020/03/30 Python
Python基于QQ邮箱实现SSL发送
2020/04/26 Python
Jupyter Notebook 安装配置与使用详解
2021/01/06 Python
IE下实现类似CSS3 text-shadow文字阴影的几种方法
2011/05/11 HTML / CSS
巴西婴儿用品商店:Bebe Store
2017/11/23 全球购物
HolidayLettings英国:预订最好的度假公寓、别墅和自助式住宿
2019/08/27 全球购物
外贸实习生自荐信范文
2013/11/24 职场文书
2014年党员教师自我剖析材料
2014/09/30 职场文书
个人培训总结
2015/03/05 职场文书
2015年学校食堂工作总结
2015/04/22 职场文书
开学典礼致辞
2015/07/29 职场文书
mysql字段为NULL索引是否会失效实例详解
2022/05/30 MySQL