气泡图
效果展示
A
100
A+
200
B
300
B+
400
C
600
C+
700
A
100
A+
200
B
300
B+
400
C
600
C+
700
示例代码
vue
<template>
<button class="button" @click="refresh()">刷新</button>
<div class="main" :style="{width: maxWidth +'px', height: maxHeight + 'px'}">
<div class="box" v-for="(item,index) in bubbleItems" :key="index">
<div class="item" :style="itemStyle(item,index)">
<div class="label" :style="labelStyle(item)">
<div class="name">{{ item.name }}</div>
<div class="value">{{ item.value }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
import * as _ from 'lodash-es'
export default{
data(){
return {
maxWidth: 500,
maxHeight: 200,
minValue: 0,
maxValue: 0,
sumValue: 0,
baseRate: 0, // 基础比率,表示 value = 1 时 占多少个像素(px)
bubbleItems: [
{name:'A',value:100, startColor:'#251571',endColor:'#5a41dd', symbolSize: 0},
{name:'A+',value:200, startColor:'#251571',endColor:'#24ac82'},
{name:'B',value:300, startColor:'#251571',endColor:'#0173e4'},
{name:'B+',value:400, startColor:'#251571',endColor:'#926710'},
{name:'C',value:600, startColor:'#251571',endColor:'#5a41dd'},
{name:'C+',value:700, startColor:'#251571',endColor:'#5a41dd'},
{name:'A',value:100, startColor:'#251571',endColor:'#5a41dd', symbolSize: 0},
{name:'A+',value:200, startColor:'#251571',endColor:'#24ac82'},
{name:'B',value:300, startColor:'#251571',endColor:'#0173e4'},
{name:'B+',value:400, startColor:'#251571',endColor:'#926710'},
{name:'C',value:600, startColor:'#251571',endColor:'#5a41dd'},
{name:'C+',value:700, startColor:'#251571',endColor:'#5a41dd'},
]
}
},
mounted() {
this.bubbleItems = _.shuffle(this.bubbleItems);
this.calculateValues();
},
methods:{
calculateValues(){
this.minValue = _.maxBy(this.bubbleItems, 'value').value;
this.maxValue = _.maxBy(this.bubbleItems, 'value').value;
this.sumValue = _.sumBy(this.bubbleItems, 'value');
// 先用x轴计算
this.baseRate = (this.maxWidth - (this.bubbleItems.length + 1) * 5) / this.sumValue;
if (this.baseRate * this.maxValue > this.maxHeight) {
// 说明 最大的圆直径会超过容器的高度,需要用 x 轴来计算
this.baseRate = (this.maxHeight - 10) / this.maxValue;
}
this.bubbleItems.forEach((e,i) => {
e.symbolSize = e.value * this.baseRate;
var diff = this.maxHeight - e.symbolSize;
e.translateY = _.random(-diff, diff) / 2;
e.labelScale = this.getLabelScale(e.symbolSize)
})
console.log(this.bubbleItems, 'this.bubbleItems');
},
refresh(){
this.bubbleItems = _.shuffle(this.bubbleItems);
this.bubbleItems[_.random(0, this.bubbleItems.length)].value = _.random(10, 5000)
this.bubbleItems[_.random(0, this.bubbleItems.length)].value = _.random(10, 5000)
this.calculateValues();
},
itemStyle(item) {
return {
width: item.symbolSize + 'px',
height: item.symbolSize + 'px',
translate: '0 ' + item.translateY + 'px',
'background-image': 'radial-gradient(circle, ' + item.startColor + ', ' + item.endColor + ')',
}
},
labelStyle(item){
return {
scale: item.labelScale
}
},
getLabelScale(width) {
var baseWidth = 70; // 基础宽度:width:70px;
var baseSize = 12; // 基础字体大小:font-size:12px;
var size = 1;
if (width < 40) {
size = 0.7;
}
else if (width < 50) {
size = 0.8;
}
else if (width < 60) {
size = 0.9;
}
else if (width < 70) {
size = 1;
} else if (width < 80) {
size = 1.1;
} else if (width < 90) {
size = 1.2;
} else if (width < 100) {
size = 1.3;
}
else if (width < 110) {
size = 1.4;
}
else {
size = 1.5;
}
return size;
}
}
}
</script>
<style scoped>
.button{
margin: 10px 0;
padding: 10px 20px;
border-radius: 5px;
background-color: #10b981;
color: #fff;
}
.main{
padding: 10px 0;
background-color: #031c4c;
display: flex;
justify-content: center;
align-items: center;
gap: 5px;
translate: 1;
}
.item{
cursor: pointer;
line-height: initial;
color: #fff;
border: 0px solid red;
border-radius: 50%;
font-size: 12px;
/* background-image: radial-gradient(circle, #251571, #5a41dd); */
position: relative;
}
.item:hover{
scale: 1.1;
}
.item .label{
border: 0px solid red;
text-align: center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
/* transform: scale(1.5); */
}
</style>