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最简单的拖拽效果实现代码
Sep 24 Javascript
封装的原生javascript弹出层代码
Sep 24 Javascript
游览器中javascript的执行过程(图文)
May 20 Javascript
Javascript拓展String方法小结
Jul 08 Javascript
javascript实现存储hmtl字符串示例
Apr 25 Javascript
浅谈如何实现easyui的datebox格式化
Jun 12 Javascript
JS中的进制转换以及作用
Jun 26 Javascript
JS实现继承的几种常用方式示例
Jun 22 Javascript
微信小程序使用 vant Dialog组件的正确方式
Feb 21 Javascript
vue-路由精讲 二级路由和三级路由的作用
Aug 06 Javascript
vue-cli打包后本地运行dist文件中的index.html操作
Aug 12 Javascript
vue的项目如何打包上线
Apr 13 Vue.js
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
第十节--抽象方法和抽象类
2006/11/16 PHP
浅析php中如何在有限的内存中读取大文件
2013/07/02 PHP
PHP实现定时执行任务的方法
2014/10/05 PHP
thinkPHP简单遍历数组方法分析
2016/05/16 PHP
Thinkphp批量更新数据的方法汇总
2016/06/29 PHP
PHP实现数组向任意位置插入,删除,替换数据操作示例
2019/04/05 PHP
php中关于换行的实例写法
2019/09/26 PHP
js中访问html中iframe的文档对象的代码[IE6,IE7,IE8,FF]
2011/01/08 Javascript
使用原生javascript创建通用表单验证——更锋利的使用dom对象
2011/09/13 Javascript
sliderToggle在写jquery的计时器setTimeouter中不生效
2014/05/26 Javascript
JavaScript中的原型链prototype介绍
2014/12/30 Javascript
easyui Draggable组件实现拖动效果
2015/08/19 Javascript
jquery实现左右无缝轮播图
2020/07/31 Javascript
Javascript实现跨域后台设置拦截的方法详解
2017/08/04 Javascript
jQuery 改变P标签文本值方法
2018/02/24 jQuery
axios全局请求参数设置,请求及返回拦截器的方法
2018/03/05 Javascript
小程序日历控件使用方法详解
2018/12/29 Javascript
vue axios重复点击取消上一次请求封装的方法
2019/06/19 Javascript
layui点击左侧导航栏,实现不刷新整个页面,只刷新局部的方法
2019/09/25 Javascript
[00:10]DOTA2全国高校联赛 以DOTA2会友
2018/05/30 DOTA
Python采集腾讯新闻实例
2014/07/10 Python
Python简单实现Base64编码和解码的方法
2017/04/29 Python
Python实现字符串反转的常用方法分析【4种方法】
2017/09/30 Python
django之使用celery-把耗时程序放到celery里面执行的方法
2019/07/12 Python
Python程序控制语句用法实例分析
2020/01/14 Python
python实现处理mysql结果输出方式
2020/04/09 Python
印尼最大的网上书店:Gramedia.com
2018/09/13 全球购物
捷克鲜花配送:Florea.cz
2018/10/29 全球购物
生产部厂长助理职位说明书
2014/03/03 职场文书
留学推荐信范文
2014/05/10 职场文书
爱心捐款倡议书范文
2014/05/12 职场文书
环保项目建议书
2014/08/26 职场文书
高中语文教学反思范文
2016/02/16 职场文书
Matplotlib可视化之添加让统计图变得简单易懂的注释
2021/06/11 Python
Python制作表白爱心合集
2022/01/22 Python
MySQL视图概念以及相关应用
2022/04/19 MySQL