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 变量基础知识
Nov 07 Javascript
jquery 输入框数字限制插件
Nov 10 Javascript
Js 冒泡事件阻止实现代码
Jan 27 Javascript
JavaScript中提前声明变量或函数例子
Nov 12 Javascript
Mongoose学习全面理解(推荐)
Jan 21 Javascript
layer插件select选中默认值的方法
Aug 14 Javascript
node.js监听文件变化的实现方法
Apr 17 Javascript
微信小程序前端自定义分享的实现方法
Jun 13 Javascript
vue3实现v-model原理详解
Oct 09 Javascript
解决vue的过渡动画无法正常实现问题
Oct 31 Javascript
JS控制只能输入数字并且最多允许小数点两位
Nov 24 Javascript
解决vue-router 切换tab标签关闭时缓存问题
Jul 22 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 类相关函数的使用详解
2013/05/10 PHP
php命令行(cli)模式下报require 加载路径错误的解决方法
2015/11/23 PHP
php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
2018/09/28 PHP
jQuery插件原来如此简单 jQuery插件的机制及实战
2012/02/07 Javascript
Javascript限制网页只能在微信内置浏览器中访问
2014/11/09 Javascript
JS显示下拉列表框内全部元素的方法
2015/03/31 Javascript
jquery实现两个图片渐变切换效果的方法
2015/06/25 Javascript
JavaScript实现下拉列表框数据增加、删除、上下排序的方法
2015/08/11 Javascript
jquery中ajax跨域方法实例分析
2015/12/18 Javascript
JavaScript中子对象访问父对象的方式详解
2016/09/01 Javascript
Angular学习笔记之angular的$filter服务浅析
2016/11/12 Javascript
浅谈struts1 &amp; jquery form 文件异步上传
2017/05/25 jQuery
Vue在页面右上角实现可悬浮/隐藏的系统菜单
2018/05/04 Javascript
vue移动端微信授权登录插件封装的实例
2018/08/28 Javascript
解决vue单页路由跳转后scrollTop的问题
2018/09/03 Javascript
使用JS判断页面是首次被加载还是刷新
2019/05/26 Javascript
pycharm 使用心得(九)解决No Python interpreter selected的问题
2014/06/06 Python
整理Python最基本的操作字典的方法
2015/04/24 Python
python人民币小写转大写辅助工具
2018/06/20 Python
python实现自主查询实时天气
2018/06/22 Python
详解使用python3.7配置开发钉钉群自定义机器人(2020年新版攻略)
2020/04/01 Python
澳大利亚在线百货商店:Real Smart
2017/08/13 全球购物
Manduka官网:瑜伽垫、瑜伽毛巾和服装
2018/07/02 全球购物
MVC的各个部分都有那些技术来实现?如何实现?
2016/04/21 面试题
如何执行一个shell程序
2012/11/23 面试题
通息工程毕业生自荐信
2013/10/16 职场文书
企业管理标语
2014/06/10 职场文书
大一新生期末自我评价
2014/09/12 职场文书
2014年妇产科工作总结
2014/12/08 职场文书
班主任自我评价范文
2015/03/11 职场文书
2015年设计师个人工作总结
2015/04/25 职场文书
医院感染管理制度
2015/08/05 职场文书
2016中学教师读书心得体会
2016/01/13 职场文书
使用pycharm运行flask应用程序的详细教程
2021/06/07 Python
Python图片验证码降噪和8邻域降噪
2021/08/30 Python
Netty分布式客户端处理接入事件handle源码解析
2022/03/25 Java/Android