因为要实现的饼图效果较复杂,所以,需要重新写列表。
点击右侧列表的圆点,实现隐藏左侧饼图相应环状。
<template>
<div class="index_div">
<a-spin :spinning="aLoading">
<scalescreen
:width="1920"
:height="1080"
:selfAdaption="true"
class="scale-wrap"
>
<div class="pieMulBox">
<div class="pieMulChart">
<div class="pie_mul_box">
<div class="innPieBg">
<div class="number">{
{curStorageRate}}</div>
</div>
<div class="pieChart">
<pie_mul ref="pie_mul" />
</div>
</div>
<p style="margin-top: 17px;">当前系统访问率</p>
</div>
<div class="pieMulMsg">
<ul>
<li v-for="(item,index) in pieMulData" :key="index" @click="clickPiechart(item, index)">
<span>{
{item.label}}</span><strong>{
{item.value}}</strong>
</li>
</ul>
</div>
</div>
</scalescreen>
</a-spin>
</div>
</template>
<script>
import { deepClone } from '@/utils/util'
import pie_mul from './Analysis/pie_mul'
import scalescreen from './Analysis/scale-screen.vue'
import { energyStateAnalysis } from '@/api/analysis/index'
export default {
name: "Analysis",
components: {
pie_mul,
scalescreen
},
data() {
return {
aLoading: true,
pieMulData: [],
hidePieData: [], // 点击隐藏的值
showPieData: [] // 点击显示的值
}
},
created() {
this.getEnergyStateAnalysis()
setTimeout(()=>{
this.aLoading = false
}, 3000)
},
methods: {
getEnergyStateAnalysis() {
energyStateAnalysis().then((res) => {
// console.log('energyStateAnalysis', res)
if (res.success) {
let data = res.result
this.curStorageRate = data.curStorageRate
// let dataList = [
// { value: 62.2, label: "小1" },
// { value: 17.3, label: "基1" },
// { value: 6.2, label: "移1" },
// { value: 9.1, label: "农1" },
// { value: 3.2, label: "三1" },
// ];
// this.pieMulData = dataList
// this.$refs.pie_mul.draw(dataList);
if(data.list && data.list.length > 0) {
let dataList = []
this.$nextTick(() => {
data.list.map(v=>{
dataList.push({ value: v.cnt, label: v.itemName })
});
this.pieMulData = dataList
this.showPieData = deepClone(dataList)
this.$refs.pie_mul.draw(dataList);
})
}
}
})
},
// 点击饼图旁边的列表,显示和隐藏饼图数据。
clickPiechart(item, idx) {
const index = this.hidePieData.indexOf(item.label);
if (index > -1) {
this.hidePieData.splice(index, 1);
this.showPieData[idx] = item
} else {
this.hidePieData.push(item.label);
this.showPieData[idx] = {}
}
this.$refs.pie_mul.draw(this.showPieData);
},
}
}
</script>
<style scoped lang="less">
.index_div {
margin: -12px -12px 0;
padding: 12px 12px 0;
background: #01091D;
}
ul, li {
list-style: none none outside;
padding: 0;
margin-bottom: 0;
}
.pieMulBox {
display: flex;
flex-direction: row;
padding-left: 12px;
.pieMulChart {
text-align: center;
.pie_mul_box {
position: relative;
width: 150px;
height: 150px;
border: 3px solid rgba(14, 98, 121, 0.3);
border-radius: 1000px;
display: flex;
align-items: center;
justify-content: center;
&::before {
content: '';
display: block;
width: 7px;
height: 7px;
background: #3AB9FC;
border-radius: 1000px;
position: absolute;
top: -4px;
left: 68px;
}
&::after {
content: '';
display: block;
width: 7px;
height: 7px;
background: #3AB9FC;
border-radius: 1000px;
position: absolute;
bottom: -4px;
left: 68px;
}
.pieChart {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
}
.innPieBg {
width: 93px;
height: 93px;
border: 6px solid rgba(14, 98, 121, 0.1);
border-radius: 1000px;
position: relative;
.number {
font-family: Alibaba-PuHuiTi, Alibaba-PuHuiTi;
font-weight: normal;
font-size: 26px;
color: #FFFFFF;
line-height: 35px;
text-align: center;
font-style: normal;
position: absolute;
left: 0;
top: 21px;
right: 0;
bottom: 0;
z-index: 9;
}
}
}
p {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 18px;
color: #F0F0F0;
line-height: 25px;
}
}
.pieMulMsg {
margin-left: 68px;
padding-top: 19px;
ul {
li {
position: relative;
padding-left: 23px;
padding-bottom: 6px;
margin-bottom: 12px;
&::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
border-radius: 1000px;
position: absolute;
left: 0;
top: 6px;
}
&::after {
content: '';
display: inline-block;
width: 118px;
height: 1px;
background: linear-gradient( 90deg, #0E7FC8 0%, rgba(9,159,216,0.16) 100%);
box-shadow: 0px 20px 11px 11px rgba(0,21,38,0.01);
opacity: 0.5;
position: absolute;
left: 20px;
bottom: 0;
}
&:nth-child(1)::before { background: linear-gradient( 180deg, #469C94 0%, #6AE6C8 100%) }
&:nth-child(2)::before { background: linear-gradient( 180deg, #21C5F5 0%, #043748 100%) }
&:nth-child(3)::before { background: linear-gradient( 180deg, #23A9FF 0%, #0321BD 100%) }
&:nth-child(4)::before { background: linear-gradient( 180deg, #FF7500 0%, #FF7500 100%) }
&:nth-child(5)::before { background: linear-gradient( 180deg, #a72a21 0%, #803d37 100%) }
&:nth-child(6)::before { background: linear-gradient( 180deg, #7b0488 0%, #3c1e69 100%) }
&:nth-child(7)::before { background: linear-gradient( 180deg, #ff00bf 0%, #651754 100%) }
span {
display: inline-block;
width: 110px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: rgba(255,255,255,0.8);
line-height: 22px;
}
strong {
font-weight: normal;
font-size: 18px;
color: #FFFFFF;
line-height: 19px;
}
}
}
}
}
</style>
echarts的饼图组件:pie_mul.vue
<template>
<div class="bg">
<div id="mulPieChart" style="width: 150px;height:150px;"></div>
</div>
</template>
<script>
// import * as echarts from 'echarts';
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core';
// 引入图表,图表后缀都为 Chart
// import { LineChart } from 'echarts/charts';
// import { BarChart } from 'echarts/charts';
// import { CustomChart } from 'echarts/charts';
import { PieChart } from 'echarts/charts';
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
// TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
// MarkLineComponent,
// MarkAreaComponent,
// MarkPointComponent
} from 'echarts/components';
// 标签自动布局、全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features';
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers';
// 注册必须的组件
echarts.use([
// TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
// MarkLineComponent,
// MarkAreaComponent,
// MarkPointComponent,
// LineChart,
// BarChart,
// CustomChart,
PieChart,
LabelLayout,
UniversalTransition,
CanvasRenderer
]);
export default {
data() {
return {
status: 'loading',
loading: true,
chart: null
}
},
created() {
},
mounted() {
},
beforeDestroy() {
},
methods: {
draw(sourceData) {
// console.log(sourceData)
// 基于准备好的dom,初始化echarts实例
if (!this.chart) {
this.chart = echarts.init(document.getElementById('mulPieChart'));
}
// 指定图表的配置项和数据
let option = {
tooltip: {
trigger: 'item'
},
series: [
{
type: 'pie',
name: '',
radius: [55, 62],
legendHoverLink: false,
avoidLabelOverlap: false,
selectedOffset: 0,
padAngle: 2,
itemStyle: {
borderRadius: 2
},
label: {
show: true,
position: 'center'
},
emphasis: {
label: {
show: false,
fontSize: 40,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: sourceData,
itemStyle: {
normal: {
color: function (params) {
var colorList = [
['#469C94', '#6AE6C8'],
['#21C5F5', '#043748'],
['#23A9FF', '#0321BD'],
['#FF7500', '#FF7500'],
['#a72a21', '#803d37'],
['#7b0488', '#3c1e69'],
['#ff00bf', '#651754'],
];
var index = params.dataIndex;
return new echarts.graphic.LinearGradient(0, 0, 1, 1, [
{
offset: 0,
color: colorList[index][0]
},
{
offset: 1,
color: colorList[index][1]
}
]);
}
}
}
}
]
}
this.chart.setOption(option)
}
}
}
</script>
<style lang="scss" scoped>
</style>
scale-screen.vue
<template>
<div class="screen-wrapper" :class="{'opacity': opacity}" ref="screenWrapper" :style="wrapperStyle">
<slot></slot>
</div>
</template>
<script>
/**
* 防抖函数
* @param {T} fn
* @param {number} delay
* @return
*/
function debounce(fn, delay) {
let timer = null;
return function (...args) {
timer = setTimeout(
() => {
typeof fn === "function" && fn.apply(null, args);
clearTimeout(timer);
},
delay > 0 ? delay : 100
);
};
}
export default {
name: "VScaleScreen",
props: {
width: {
type: [String, Number],
default: 1920,
},
height: {
type: [String, Number],
default: 1080,
},
fullScreen: {
type: Boolean,
default: false,
},
autoScale: {
type: [Object, Boolean],
default: true,
},
selfAdaption: {
type: Boolean,
default: true,
},
delay: {
type: Number,
default: 500,
},
boxStyle: {
type: Object,
default: () => ({}),
},
wrapperStyle: {
type: Object,
default: () => ({}),
},
},
data() {
return {
currentWidth: 0,
currentHeight: 0,
originalWidth: 0,
originalHeight: 0,
onResize: null,
observer: null,
opacity: false
};
},
watch: {
selfAdaption(val) {
if (val) {
this.resize();
this.addListener();
} else {
this.clearListener();
this.clearStyle();
}
},
},
computed: {
screenWrapper() {
return this.$refs["screenWrapper"];
},
},
methods: {
initSize() {
return new Promise((resolve, reject) => {
// console.log("初始化样式");
//给父元素设置 overflow:hidden
this.screenWrapper.parentNode.style.overflow = "hidden";
this.screenWrapper.parentNode.scrollLeft = 0;
this.screenWrapper.parentNode.scrollTop = 0;
this.$nextTick(() => {
// region 获取大屏真实尺寸
if (this.width && this.height) {
this.currentWidth = this.width;
this.currentHeight = this.height;
} else {
this.currentWidth = this.screenWrapper.clientWidth;
this.currentHeight = this.screenWrapper.clientHeight;
}
// endregion
// region 获取画布尺寸
if (!this.originalHeight || !this.originalWidth) {
this.originalWidth = window.screen.width;
this.originalHeight = window.screen.height;
}
// endregion
resolve();
});
});
},
updateSize() {
if (this.currentWidth && this.currentHeight) {
this.screenWrapper.style.width = `${this.currentWidth}px`;
this.screenWrapper.style.height = `${this.currentHeight}px`;
} else {
this.screenWrapper.style.width = `${this.originalWidth}px`;
this.screenWrapper.style.height = `${this.originalHeight}px`;
}
},
handleAutoScale(scale) {
if (!this.autoScale) return;
const screenWrapper = this.screenWrapper;
const domWidth = screenWrapper.clientWidth;
const domHeight = screenWrapper.clientHeight;
const currentWidth = document.body.clientWidth - 232;
const currentHeight = document.body.clientHeight - 111;
screenWrapper.style.transform = `scale(${scale},${scale}) `;
let mx = Math.max((currentWidth - domWidth * scale) / 2, 0);
let my = Math.max((currentHeight - domHeight * scale) / 2, 0);
if (typeof this.autoScale === "object") {
// @ts-ignore
!this.autoScale.x && (mx = 0);
// @ts-ignore
!this.autoScale.y && (my = 0);
}
this.screenWrapper.parentNode.style.height = (this.height * scale) + 'px'
setTimeout(() => {
this.opacity = true
}, 500)
},
updateScale() {
const screenWrapper = this.screenWrapper;
// 获取真实视口尺寸
const currentWidth = document.body.clientWidth - 232;
const currentHeight = document.body.clientHeight - 111;
// 获取大屏最终的宽高onResize
const realWidth = this.currentWidth || this.originalWidth;
const realHeight = this.currentHeight || this.originalHeight;
// 计算缩放比例
const widthScale = currentWidth / realWidth;
const heightScale = currentHeight / realHeight;
// console.log({currentWidth, currentHeight,realWidth,realHeight});
// 若要铺满全屏,则按照各自比例缩放
if (this.fullScreen) {
screenWrapper.style.transform = `scale(${widthScale},${heightScale})`;
return false;
}
// 按照宽高最小比例进行缩放
const scale = Math.max(widthScale, heightScale);
this.handleAutoScale(scale);
},
initMutationObserver() {
const screenWrapper = this.screenWrapper;
const observer = (this.observer = new MutationObserver(() => {
this.onResize();
}));
observer.observe(screenWrapper, {
attributes: true,
attributeFilter: ["style"],
attributeOldValue: true,
});
},
clearListener() {
window.removeEventListener("resize", this.onResize);
},
addListener() {
window.addEventListener("resize", this.onResize);
},
clearStyle() {
const screenWrapper = this.screenWrapper;
screenWrapper.parentNode.style.overflow = "auto";
screenWrapper.style = "";
},
async resize() {
if (!this.selfAdaption) {
return;
}
await this.initSize();
this.updateSize();
this.updateScale();
},
},
mounted() {
this.onResize = debounce(() => {
this.resize();
}, this.delay);
this.$nextTick(() => {
if (this.selfAdaption) {
this.resize();
this.addListener();
}
});
},
beforeDestroy() {
this.clearListener();
},
};
</script>
<style scoped>
.screen-box {
overflow: hidden;
background-size: 100% 100%;
background: #000;
width: 100vw;
height: 100vh;
}
.screen-wrapper {
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 500ms;
position: relative;
overflow: hidden;
z-index: 100;
transform-origin: left top;
opacity: 0;
}
.opacity {
opacity: 1;
}
</style>