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 Linux copy and paste in VMware virtual machine

1. Linux under VMware Workstation: 1. Update sour...

Detailed explanation of system input and output management in Linux

Management of input and output in the system 1. U...

Vue realizes simple effect of running light

This article shares the specific code of Vue to a...

Summary of methods to clear cache in Linux system

1) Introduction to cache mechanism In the Linux s...

Using react-virtualized to implement a long list of images with dynamic height

Table of contents Problems encountered during dev...

Mysql master-slave synchronization Last_IO_Errno:1236 error solution

What is the reason for the Last_IO_Errno:1236 err...

Simple use of Vue vee-validate plug-in

Table of contents 1. Installation 2. Import 3. De...

How to use Nginx to proxy multiple application sites in Docker

Preface What is the role of an agent? - Multiple ...

iview implements dynamic form and custom verification time period overlap

Dynamically adding form items iview's dynamic...

Solve the 1251 error when establishing a connection between mysql and navicat

I reinstalled the computer and installed the late...

A brief explanation of the reasonable application of table and div in page design

At the beginning of this article, I would like to ...

Linux's fastest text search tool ripgrep (the best alternative to grep)

Preface Speaking of text search tools, everyone m...

The One-Hand Rule of WEB2.0

<br />My previous article about CSS was not ...