Javascript 实现在给定区域随机生成圆形

2021/07/29 Javascript Html 共 3090 字,约 9 分钟
北城北小北

描述

在给定区域实现随机生成给定数量的圆,每个圆的半径不固定,要动态计算圆的半径和距离。可以使用canvas或者div 去生成DOM 效果如下图所示

image

代码

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);
    console.log('ccc', this.c)
    this.dWidth = this.c.width || this.c.offsetWidth; // 宽
    this.dHeight = this.c.height || this.c.offsetHeight; // 高
    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
    this.colorList = obj.colorList || ['#FFC144', '#3A85FF', '#692EFF', '#19C48A', '#BDB2FF', '#FFB9B2', '#FF846D', '#C9DEFF', '#A8DADC', '#FFE8A9']
    this.data = obj.data || []
    this.circleClassName = obj.data.className || 'travel_circle_item'
  }

  // dom版本
  drawOneCircle(c, i) {
    const childrenDiv = document.createElement('div')
    const numDiv = document.createElement('div')
    const nameDiv = document.createElement('div')
    numDiv.innerText = this.data[i].rate ? format_rate(this.data[i].rate) + '%' : '-'
    nameDiv.innerText = this.data[i].name
    childrenDiv.setAttribute('class', `${this.circleClassName} dmp_tooltip`)
    childrenDiv.setAttribute('data-msg', `${this.data[i].name}  ${format_number(this.data[i].value)}`)
    childrenDiv.appendChild(numDiv)
    childrenDiv.appendChild(nameDiv)
    childrenDiv.style.cssText =
      `position:absolute;left:${c.x - c.r}px;top:${c.y - c.r}px;width:${c.r * 2}px;height:${c.r * 2}px;border: 1px solid ${this.colorList[i]};border-radius:50%;background-color:${this.colorList[i]};font-size:${c.r / 4}px`
    this.c.appendChild(childrenDiv)
    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() {
    console.log(222)
    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, i) => {
      this.drawOneCircle(c, i)
    })
  }
}

export default RandomCircle

文档信息

Search

    Table of Contents