Vue uses Canvas to generate random sized and non-overlapping circles

Vue uses Canvas to generate random sized and non-overlapping circles

Canvas related documents

  • Canvas API
  • CANVAS Quick Check Table

Effect picture display

The first one is the effect of random colors and random sizes aggregated together

The second one is the random background image with random size dispersion effect (the pictures I used here are all the same so different pictures are not shown)

Case complete code

  • This example is implemented using Vue. Other methods are similar to Vue. You can achieve the effect by changing the corresponding syntax.
  • The case uses Vue parent-child component value transfer

Parent component code

<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 simulation data 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: {
    // Get the width and height of the parent box getWidth() {
      this.parentClientWidth = this.$refs.tags.clientWidth;
      this.parentClientHeight = this.$refs.tags.clientHeight;
      console.log(this.$refs.tags.clientWidth);
    }
  },
};
</script>

Subcomponent code

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

  data() {
    return {
      dataListCopy: this.dataList
    }
  },
  
  created() {
    this.$nextTick(() => {
      // Initialize 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()
        }

        // Random color 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 = cc
          ctx.fillStyle = cc
          // Draw a circle ctx.arc(cx, cy, cr, 0, 2 * Math.PI)

          ctx.stroke()
          ctx.fill()

          // ctx.textAlign = 'center'
          // ctx.textBaseline = 'middle'

          // ctx.fillStyle = 'black'
          // ctx.font = '1rem Microsoft YaHei'
          // ctx.fillText(that.dataListCopy[index].follow, cx, cy - 10) // Text inside the circle let img = new Image()
          img.src = that.dataListCopy[index].image
          ctx.drawImage(img, cx - cr, cy - cr, cr * 2, cr * 2)

          this.circleNumber++
        }

        check(x, y, r) {
          return !(x + r > this.dWidth || x - r < 0 || y + r > this.dHeight || y - r < 0)
        }

        // Get the radius of a new circle, mainly to determine the distance between the radius and the nearest circle getR(x, y) {
          if (this.circleArray.length === 0) return Math.floor(Math.random() * 20 + 20)

          let lenArr = this.circleArray.map((c) => {
            let xSpan = cx - x
            let ySpan = cy - y

            return Math.floor(Math.sqrt(Math.pow(xSpan, 2) + Math.pow(ySpan, 2))) - cr
          })

          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
        }

        // Generate a circle with a randomly generated center.
        // If the radius is not suitable after 200 consecutive generation, terminate the process 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))
        }

        // If generating new circles fails 100 times, terminate the scheme.
        // If none of the 100 generated solutions are suitable, terminate the process.
        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
            }
          }

          // Draw circles from large to small according to the radius.
          this.circleArray
            .sort((a, b) => br - ar)
            .forEach((c, index) => {
              this.drawOneCircle(c, index)
            })
        }
      }
      // console.log(this.circle);

      const p = new RandomCircle({
        id: 'myCanvas',
        total: that.dataListCopy.length //Configuration quantity})

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

Summarize

This is the end of this article about how Vue uses Canvas to generate random-sized, non-overlapping circles. For more information about how Vue uses Canvas to generate random circles, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Vue uses canvas to realize image compression upload
  • How to draw the timeline with vue+canvas
  • VUE+Canvas realizes the whole process of a simple Gobang game
  • VUE+Canvas implements the game of God of Wealth receiving ingots
  • How to use VUE and Canvas to implement a Thunder Fighter typing game
  • VUE+Canvas implements the sample code of the desktop pinball brick-breaking game
  • Vue uses the mouse to draw a rectangle on Canvas
  • Vue uses canvas to implement mobile handwritten signature
  • Vue+canvas realizes puzzle game
  • Vue uses canvas handwriting input to recognize Chinese

<<:  Realize the CSS loading effect after clicking the button

>>:  How to create a table in mysql and add field comments

Recommend

Detailed explanation of the use of nohup /dev/null 2>&1

nohup command: If you are running a process and y...

A brief discussion on Flex layout and scaling calculation

1. Introduction to Flex Layout Flex is the abbrev...

JS asynchronous code unit testing magic Promise

Table of contents Preface Promise chaining MDN Er...

HTML implements a fixed floating semi-transparent search box on mobile

Question. In the mobile shopping mall system, we ...

MySQL optimization: use join instead of subquery

Use JOIN instead of sub-queries MySQL supports SQ...

Steps for Docker to build a private warehouse Harbor

Harbor Harbor is an open source solution for buil...

Angular Dependency Injection Explained

Table of contents Overview 1. Dependency Injectio...

How to fix the four sides of the table to scroll up, down, left and right

question: When I was doing project statistics rec...

A more elegant error handling method in JavaScript async await

Table of contents background Why error handling? ...

Disable autocomplete in html so it doesn't show history

The input box always displays the input history wh...

Detailed explanation of MySQL master-slave replication process

1. What is master-slave replication? The DDL and ...

Several mistakes that JavaScript beginners often make

Table of contents Preface Confusing undefined and...

$nextTick explanation that you can understand at a glance

Table of contents 1. Functional description 2. Pa...