Vue使用Canvas生成随机大小且不重叠圆

 更新时间:2021年11月03日 15:56:15   作者:阿怪没有脑袋  
Canvas是HTML5中新增的元素,专门用来绘制图形,下面这篇文章主要给大家介绍了关于Vue使用Canvas生成随机大小且不重叠圆的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

canvas 相关文档

效果图展示

第一张是 随机颜色随机大小聚合 在一起效果

第二张是 随机背景图片随机大小分散 效果(这里我使用的图片都一样所以没展现出不同图片)

案例完整代码

  • 本实例是用 vue 来实现的,其他方法和 vue 类似,改为对应的语法即可实现效果。
  • 案例用到了 vue 父子组件传值

父组件代码

<template>
  <div id="home">
      <div class="tags" ref="tags">
        <circle-box :parentClientWidth="parentClientWidth" :parentClientHeight="parentClientHeight" :dataList="dataList"></circle-box>
      </div>
  </div>
</template>
<script>
import CircleBox from '@/components/content/circle/Circle.vue'
export default {
  components: { CircleBox },
  data() {
    return {
      parentClientWidth: 0,
      parentClientHeight: 0,
      // canvas 模拟数据
      dataList: [
       {
          follow: 1,
          image: 'http://39.99.139.115/demo/RB5.png'
        },
        {
          follow: 2,
          image: 'http://39.99.139.115/demo/RB5.png'
        },
        {
          follow: 3,
          image: 'http://39.99.139.115/demo/RB5.png'
        },
        {
          follow: 4,
          image: 'http://39.99.139.115/demo/RB5.png'
        },
        {
          follow: 5,
          image: 'http://39.99.139.115/demo/RB5.png'
        },
        {
          follow: 6,
          image: 'http://39.99.139.115/demo/RB5.png'
        },
        {
          follow: 7,
          image: 'http://39.99.139.115/demo/RB5.png'
        },
        {
          follow: 8,
          image: 'http://39.99.139.115/demo/RB5.png'
        },
        {
          follow: 9,
          image: 'http://39.99.139.115/demo/RB5.png'
        },
        {
          follow: 10,
          image: 'http://39.99.139.115/demo/RB5.png'
        }
      ],
    };
  },
  
  created() {},
  
  mounted() {
    this.getWidth();
  },
  
  methods: {
    // 获取父盒子的宽度和高度
    getWidth() {
      this.parentClientWidth = this.$refs.tags.clientWidth;
      this.parentClientHeight = this.$refs.tags.clientHeight;
      console.log(this.$refs.tags.clientWidth);
    }
  },
};
</script>

子组件代码

<template>
  <div>
    <canvas id="myCanvas" :width="parentClientWidth + 'px'" :height="parentClientHeight + 'px'"></canvas>
  </div>
</template>
<script>
export default {
  // 接收数据
  props: ['parentClientWidth', 'parentClientHeight', 'dataList'],

  data() {
    return {
      dataListCopy: this.dataList
    }
  },
  
  created() {
    this.$nextTick(() => {
      // 初始化
      this.circleInfo()
    })
  },
  
  mounted() {},
  
  methods: {
    circleInfo() {
      let that = this
      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(this.c)

          this.ctx = this.c.getContext('2d')
          this.dWidth = this.c.width
          this.dHeight = this.c.height
          this.fix = obj.fix || true

          this.minMargin = obj.minMargin || 20
          this.minRadius = obj.minRadius || 30
          this.radiuArr = obj.radiuArr || [30, 30, 30, 30, 30, 30, 30, 30, 30, 30]

          this.total = obj.total || 10

          this.circleArray = []
          this.circleNumber = 1
        }

        drawOneCircle(c, index) {
          // console.log(c, index)
          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.textAlign = 'center'
          // ctx.textBaseline = 'middle'

          // ctx.fillStyle = 'black'
          // ctx.font = '1rem 微软雅黑'
          // ctx.fillText(that.dataListCopy[index].follow, c.x, c.y - 10) //圆内文字

          let img = new Image()
          img.src = that.dataListCopy[index].image
          ctx.drawImage(img, c.x - c.r, c.y - c.r, c.r * 2, c.r * 2)

          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 + 20)

          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, index) => {
              this.drawOneCircle(c, index)
            })
        }
      }
      // console.log(this.circle);

      const p = new RandomCircle({
        id: 'myCanvas',
        total: that.dataListCopy.length // 配置数量
      })

      p.init()
      console.log(p)
      console.log(p.circleArray)
    }
  }
}
</script>

总结

到此这篇关于Vue使用Canvas生成随机大小且不重叠圆的文章就介绍到这了,更多相关Vue用Canvas生成随机圆内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue表单校验validate和validateField的使用及区别详解

    Vue表单校验validate和validateField的使用及区别详解

    validateField 和 validate 都可以用于表单验证,但是它们的作用有所不同,下面这篇文章主要给大家介绍了关于Vue表单校验validate和validateField的使用及区别的相关资料,需要的朋友可以参考下
    2024-04-04
  • vue绑定的点击事件阻止冒泡的实例

    vue绑定的点击事件阻止冒泡的实例

    下面小编就为大家分享一篇vue绑定的点击事件阻止冒泡的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-02-02
  • 基于node+vue实现简单的WebSocket聊天功能

    基于node+vue实现简单的WebSocket聊天功能

    最近学习了一下websocket的即时通信,感觉非常的强大,这里我用node启动了一个服务进行websocket链接,然后再vue的view里面进行了链接,进行通信,废话不多说,直接上代码吧
    2020-02-02
  • ElementUI 修改默认样式的几种办法(小结)

    ElementUI 修改默认样式的几种办法(小结)

    这篇文章主要介绍了ElementUI 修改默认样式的几种办法(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • vue封装一个图案手势锁组件

    vue封装一个图案手势锁组件

    手势锁是常见的一种手机解锁方式,本文主要介绍了vue封装一个图案手势锁组件,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 对vue.js中this.$emit的深入理解

    对vue.js中this.$emit的深入理解

    下面小编就为大家分享一篇对vue.js中this.$emit的深入理解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-02-02
  • 如何在Vue 3中扩展Vue Router链接详解

    如何在Vue 3中扩展Vue Router链接详解

    vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用,这篇文章主要给大家介绍了关于如何在Vue 3中扩展Vue Router链接的相关资料,需要的朋友可以参考下
    2021-06-06
  • vue使用脚手架vue-cli创建并引入自定义组件

    vue使用脚手架vue-cli创建并引入自定义组件

    这篇文章介绍了vue使用脚手架vue-cli创建并引入自定义组件的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • Vue.js中extend选项和delimiters选项的比较

    Vue.js中extend选项和delimiters选项的比较

    这篇文章主要介绍了Vue.js中extend选项和delimiters选项的比较的相关资料,需要的朋友可以参考下
    2017-07-07
  • 解决vue中对象属性改变视图不更新的问题

    解决vue中对象属性改变视图不更新的问题

    下面小编就为大家分享一篇解决vue中对象属性改变视图不更新的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-02-02

最新评论