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 相关文章推荐
HTML IMG标签 onload 内存溢出导致浏览器CPU占用过高
Mar 09 Javascript
兼容多浏览器的iframe自适应高度(ie8 、谷歌浏览器4.0和 firefox3.5.3)
Nov 04 Javascript
JavaScript 字符串与数组转换函数[不用split与join]
Dec 13 Javascript
javascript下对于事件、事件流、事件触发的顺序随便说说
Jul 17 Javascript
JavaScript获取客户端计算机硬件及系统等信息的方法
Jan 02 Javascript
jQuery获取样式中颜色值的方法
Jan 29 Javascript
js获取微信版本号的方法
May 12 Javascript
购物车前端开发(jQuery和bootstrap3)
Aug 27 Javascript
Vue.2.0.5过渡效果使用技巧
Mar 16 Javascript
JavaScript实现删除数组重复元素的5种常用高效算法总结
Jan 18 Javascript
Vue开发中遇到的跨域问题及解决方法
Feb 11 Javascript
webpack+vue.js构建前端工程化的详细教程
May 10 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 网络开发详解之远程文件包含漏洞
2010/04/25 PHP
深入学习微信网址链接解封的防封原理visit_type
2019/08/15 PHP
Yii使用DbTarget实现日志功能的示例代码
2020/07/21 PHP
JS 时间显示效果代码
2009/08/23 Javascript
基于JQuery的访问WebService的代码(可访问Java[Xfire])
2010/11/19 Javascript
JavaScript中常用的运算符小结
2012/01/18 Javascript
jquery实现兼容浏览器的图片上传本地预览功能
2013/10/14 Javascript
表单提交前触发函数返回true表单才会提交
2014/03/11 Javascript
使用Node.js处理前端代码文件的编码问题
2016/02/16 Javascript
使用CSS+JavaScript或纯js实现半透明遮罩效果的实例分享
2016/05/09 Javascript
原生js实现无缝轮播图效果
2017/01/11 Javascript
利用transition实现文字上下抖动的效果
2017/01/21 Javascript
jQuery获取Table某列的值(推荐)
2017/03/03 Javascript
jQuery 防止相同的事件快速重复触发方法
2018/02/08 jQuery
QRCode.js二维码生成并能长按识别
2018/10/16 Javascript
elementUI Tree 树形控件的官方使用文档
2019/04/25 Javascript
jQuery实现的鼠标拖动画矩形框示例【可兼容IE8】
2019/05/17 jQuery
微信小程序引入模块中wxml、wxss、js的方法示例
2019/08/09 Javascript
微信自定义分享链接信息(标题,图片和内容)实现过程详解
2019/09/04 Javascript
JS判断数组是否包含某元素实现方法汇总
2020/06/24 Javascript
python实现通过代理服务器访问远程url的方法
2015/04/29 Python
深入浅析python变量加逗号,的含义
2020/02/22 Python
Django接收照片储存文件的实例代码
2020/03/07 Python
利用Pycharm + Django搭建一个简单Python Web项目的步骤
2020/10/22 Python
使用CSS3在触屏上为按钮实现激活效果
2013/09/27 HTML / CSS
StudentUniverse英国:学生航班、酒店和旅游
2019/08/25 全球购物
英国百年闻名的优质健康产品连锁店:Holland & Barrett
2019/12/19 全球购物
JD Sports西班牙:英国领先的运动服装公司
2020/01/06 全球购物
希腊品牌鞋类销售网站:epapoutsia.gr
2020/03/18 全球购物
《黄河颂》教学反思
2014/02/07 职场文书
办公室秘书岗位职责范本
2014/02/11 职场文书
蓬莱阁导游词
2015/02/04 职场文书
幼师辞职信怎么写
2015/02/27 职场文书
2016幼儿园中班开学寄语
2015/12/03 职场文书
JavaScript中关于预编译、作用域链和闭包的理解
2021/03/31 Javascript
Python实现Telnet自动连接检测密码的示例
2021/04/16 Python