Vue使用Canvas生成隨機大小且不重疊圓
canvas 相關(guān)文檔
效果圖展示
第一張是 隨機顏色隨機大小聚合 在一起效果
第二張是 隨機背景圖片隨機大小分散 效果(這里我使用的圖片都一樣所以沒展現(xiàn)出不同圖片)
案例完整代碼
- 本實例是用 vue 來實現(xiàn)的,其他方法和 vue 類似,改為對應(yīng)的語法即可實現(xiàn)效果。
- 案例用到了 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 模擬數(shù)據(jù) 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 { // 接收數(shù)據(jù) 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},$)` } } 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) //圓內(nèi)文字 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 } // 生成一個圓,隨機生成圓心。 // 如果連續(xù)生成200次半徑都沒有合適的話,終止進(jìn)程 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種方案都沒有合適可用的話,終止進(jìn)程。 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 } } // 根據(jù)半徑從大到小畫圓。 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 // 配置數(shù)量 }) p.init() console.log(p) console.log(p.circleArray) } } } </script>
總結(jié)
到此這篇關(guān)于Vue使用Canvas生成隨機大小且不重疊圓的文章就介紹到這了,更多相關(guān)Vue用Canvas生成隨機圓內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue項目如何實現(xiàn)前端預(yù)覽word與pdf格式文件
最近項目中需要在線預(yù)覽WORD文檔,所以給大家總結(jié)下,這篇文章主要給大家介紹了關(guān)于vue項目如何實現(xiàn)前端預(yù)覽word與pdf格式文件的相關(guān)資料,需要的朋友可以參考下2023-03-03Vue實現(xiàn)省市區(qū)級聯(lián)下拉選擇框
這篇文章主要為大家詳細(xì)介紹了Vue實現(xiàn)省市區(qū)級聯(lián)下拉選擇框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03詳解vue項目優(yōu)化之按需加載組件-使用webpack require.ensure
本篇文章主要介紹了詳解vue項目優(yōu)化之按需加載組件-使用webpack require.ensure,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06使用vue-router與v-if實現(xiàn)tab切換遇到的問題及解決方法
這篇文章主要介紹了vue-router與v-if實現(xiàn)tab切換的思考,需要的朋友可以參考下2018-09-09Vuex如何獲取getter對象中的值(包括module中的getter)
這篇文章主要介紹了Vuex如何獲取getter對象中的值(包括module中的getter),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08淺談ElementUI el-select 數(shù)據(jù)過多解決辦法
下拉框的選項很多,上萬個選項甚至更多,這個時候如果全部把數(shù)據(jù)放到下拉框中渲染出來,瀏覽器會卡死,體驗會特別不好,本文主要介紹了ElementUI el-select 數(shù)據(jù)過多解決辦法,感興趣的可以了解一下2021-09-09淺談vuejs實現(xiàn)數(shù)據(jù)驅(qū)動視圖原理
這篇文章主要介紹了淺談vuejs實現(xiàn)數(shù)據(jù)驅(qū)動視圖原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02