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 相关文章推荐
jquery 分页控件实现代码
Nov 30 Javascript
$.format,jquery.format 使用说明
Jul 13 Javascript
通过js来制作复选框的全选和不选效果
May 22 Javascript
js 中将多个逗号替换为一个逗号的代码
Jun 07 Javascript
jquery中val()方法是从最后一个选项往前读取的
Sep 06 Javascript
Jquery轮播效果实现过程解析
Mar 30 Javascript
全面理解JavaScript中的闭包
May 12 Javascript
谈谈JS中常遇到的浏览器兼容问题和解决方法
Dec 17 Javascript
ES6学习教程之对象字面量详解
Oct 09 Javascript
实例解析ES6 Proxy使用场景介绍
Jan 08 Javascript
webstorm中vue语法的支持详解
May 09 Javascript
vue自定义标签和单页面多路由的实现代码
May 03 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小偷的核心程序
2007/04/09 PHP
实用函数10
2007/11/08 PHP
深入理解PHP JSON数组与对象
2016/07/19 PHP
php实现基于pdo的事务处理方法示例
2017/07/21 PHP
PHP实现打包zip并下载功能
2018/06/12 PHP
JavaScript 图像动画的小demo
2012/05/23 Javascript
js showModalDialog 弹出对话框的简单实例(子窗体)
2014/01/07 Javascript
jQuery实现在下拉列表选择时获取json数据的方法
2015/04/16 Javascript
Javascript aop(面向切面编程)之around(环绕)分析
2015/05/01 Javascript
jquery表单对象属性过滤选择器实例分析
2015/05/18 Javascript
jQuery的deferred对象使用详解
2016/09/25 Javascript
Bootstrap基本组件学习笔记之面板(14)
2016/12/08 Javascript
js中作用域的实例解析
2017/03/16 Javascript
JavaScript之Map和Set_动力节点Java学院整理
2017/06/29 Javascript
解决Jstree 选中父节点时被禁用的子节点也会选中的问题
2017/12/27 Javascript
JS实现简单省市二级联动
2019/11/27 Javascript
Python Request爬取seo.chinaz.com百度权重网站的查询结果过程解析
2019/08/13 Python
关于tf.TFRecordReader()函数的用法解析
2020/02/17 Python
keras读取h5文件load_weights、load代码操作
2020/06/12 Python
Python unittest生成测试报告过程解析
2020/09/08 Python
html5 实现客户端验证上传文件的大小(简单实例)
2016/05/15 HTML / CSS
小狗电器官方商城:中国高端吸尘器品牌
2017/03/29 全球购物
巴西购物网站:Estrela10
2018/12/13 全球购物
Club Monaco加拿大官网:设计师男女服装
2019/09/29 全球购物
超市七夕促销活动方案
2014/08/28 职场文书
质量保证书
2015/01/17 职场文书
蓬莱阁导游词
2015/02/04 职场文书
色戒观后感
2015/06/12 职场文书
化验室安全管理制度
2015/08/06 职场文书
全家福照片寄语怎么写?
2019/04/02 职场文书
CSS3实现的侧滑菜单
2021/04/27 HTML / CSS
微信小程序基础教程之echart的使用
2021/06/01 Javascript
MySQL系列之开篇 MySQL关系型数据库基础概念
2021/07/02 MySQL
一级电子管军用接收机测评
2022/04/05 无线电
openEuler 搭建java开发环境的详细过程
2022/06/10 Servers
JavaScript实现九宫格拖拽效果
2022/06/28 Javascript