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