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 相关文章推荐
学习ExtJS Panel常用方法
Oct 07 Javascript
基于jQuery的弹出警告对话框美化插件(警告,确认和提示)
Jun 10 Javascript
使用javascript获取页面名称
Dec 23 Javascript
jquery仿QQ登录账号选择下拉框效果
Mar 22 Javascript
设计模式中的组合模式在JavaScript程序构建中的使用
May 18 Javascript
Javascript小技能总结(推荐)
Jun 02 Javascript
JS实现图片局部放大或缩小的方法
Aug 20 Javascript
jQuery实现邮箱下拉列表自动补全功能
Sep 08 Javascript
jQuery EasyUI tree 使用拖拽时遇到的错误小结
Oct 10 Javascript
基于hover的用法实例(推荐)
Jul 04 Javascript
Vue前端开发规范整理(推荐)
Apr 23 Javascript
深入解析Vue源码实例挂载与编译流程实现思路详解
May 05 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/06/25 PHP
Yii2增删改查之查询 where参数详细介绍
2016/08/08 PHP
PHP从数组中删除元素的四种方法实例
2017/05/12 PHP
实现超用户体验 table排序javascript实现代码
2009/06/22 Javascript
封装html的select标签的js操作实例
2013/07/02 Javascript
html5 canvas js(数字时钟)实例代码
2013/12/23 Javascript
跟我学习javascript的定时器
2015/11/19 Javascript
实例详解jQuery的无new构建
2016/08/02 Javascript
微信小程序 wxapp画布 canvas详细介绍
2016/10/31 Javascript
javascript实现简单的可随机变色网页计算器示例
2016/12/30 Javascript
js时间戳与日期格式之间相互转换
2017/12/11 Javascript
vue中实现移动端的scroll滚动方法
2018/03/03 Javascript
8个有意思的JavaScript面试题
2019/07/30 Javascript
微信小程序左滑删除实现代码实例
2019/09/16 Javascript
怎么理解wx.navigateTo的events参数使用详情
2020/05/18 Javascript
Node.js 中判断一个文件是否存在
2020/08/24 Javascript
浅谈Python2.6和Python3.0中八进制数字表示的区别
2017/04/28 Python
火车票抢票python代码公开揭秘!
2018/03/08 Python
python list是否包含另一个list所有元素的实例
2018/05/04 Python
一篇文章了解Python中常见的序列化操作
2019/06/20 Python
用python实现学生管理系统
2020/07/24 Python
python实现人性化显示金额数字实例详解
2020/09/25 Python
Python根据字典的值查询出对应的键的方法
2020/09/30 Python
用css3实现转换过渡和动画效果
2020/03/13 HTML / CSS
美国最大的香水连锁店官网:Perfumania
2016/08/15 全球购物
阿迪达斯荷兰官方网站:adidas荷兰
2018/03/16 全球购物
英国最大的在线时尚眼镜店:Eyewearbrands
2019/03/12 全球购物
白俄罗斯女装和针织品网上商店:Presli.by
2019/10/13 全球购物
国家领导干部党的群众路线教育实践活动批评与自我批评材料
2014/09/23 职场文书
渠道运营商合作协议书范本
2014/10/06 职场文书
2014年银行客户经理工作总结
2014/11/12 职场文书
2014年班干部工作总结
2014/11/25 职场文书
2014年残疾人工作总结
2014/12/06 职场文书
无房证明样本
2015/06/17 职场文书
mysql的MVCC多版本并发控制的实现
2021/04/14 MySQL
MySQL之PXC集群搭建的方法步骤
2021/05/25 MySQL