<template>
<div class="base-chart-warp">
<!-- 暂无数据 begin -->
<div
v-if="isNoData"
class="noData"
>
<div class="noData-img"></div>
<p class="noData-txt">
{{ noDataTxt }}
</p>
</div>
<!-- 暂无数据 end -->
<!-- 图表展示 begin -->
<div class="base-echart">
<div
ref="echartDivRef"
:style="{width, height}"
></div>
</div>
<!-- 图表展示 end -->
</div>
</template>
<script lang="ts">
import {
defineComponent,
PropType,
toRefs,
onMounted,
// onUnmounted,
watchEffect,
ref
} from "vue"
import * as echarts from "echarts"
import useEchart from "../hooks/useEchart"
export default defineComponent({
props: {
isNoData: { type: Boolean, default: false },
noDataTxt: { type: String, default: "" },
width: { type: String, default: "100%" },
height: { type: String, default: "360px" },
options: {
type: Object as PropType<echarts.EChartsOption>
}
},
setup(props) {
const echartDivRef = ref<HTMLElement | undefined>()
onMounted(() => {
const { setOptions } = useEchart(echartDivRef.value as HTMLElement)
watchEffect(() => {
const { options } = toRefs(props)
setOptions(options.value as echarts.EChartsOption)
})
})
// onUnmounted(() => {
// echart.dispose
// })
return { echartDivRef }
}
})
</script>
<style lang="scss" scoped>
// 暂无数据
.noData {
width: 100%;
height: 100%;
position: absolute;
left: 0;
right: 0;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.noData-img {
width: 184px;
height: 151px;
// background: url('../../../assets/images/no-data.png') no-repeat center center;
background-size: 100% auto;
}
.noData-txt {
font-size: 14px;
color: #7b8795;
margin-top: 30px;
}
}
</style>
// useEchart.ts
//hooks
/****************************************************/
import * as echarts from "echarts"
export default function (el: HTMLElement) {
const echartInstance = echarts.init(el)
const setOptions = (options: echarts.EChartsOption) => {
echartInstance.setOption(options)
}
const updateSize = () => {
echartInstance.resize()
}
window.addEventListener("resize", () => {
echartInstance.resize()
})
return {
echartInstance,
setOptions,
updateSize
}
}
/****************************************************/
// 每段渐变的圆环
const originData = [
{ value: 1048, name: 'Search Engine', color: ['rgba(0,0,0,1)','rgba(0,0,0,0)'] },
{ value: 735, name: 'Direct', color: ['rgba(0,0,255,1)','rgba(0,0,255,0)'] },
{ value: 580, name: 'Email', color: ['rgba(0,255,0,1)','rgba(0,255,0,0)'] },
{ value: 484, name: 'Union Ads', color: ['rgba(255,0,0,1)','rgba(255,0,0,0)'] },
];
const total = originData.reduce((sum, it) => sum + Number(it.value || 0), 0);
let startAngle = -Math.PI / 2;
// 动态生成带有渐变方向的数据项
const data = originData.map((dItem) => {
const angleSpan = total ? (dItem.value / total) * Math.PI * 2 : 0;
// 计算扇区中心角度
const midAngle = startAngle + angleSpan / 2;
// 更新下一个扇区的起始角度
startAngle += angleSpan;
// 计算顺时针切线方向(midAngle + π/2)
const tangentDir = midAngle + Math.PI / 2;
// 渐变方向向量
const dx = Math.cos(tangentDir);
const dy = Math.sin(tangentDir);
return {
...dItem,
itemStyle: {
color: Array.isArray(dItem.color)
? new echarts.graphic.LinearGradient(0.5 - dx * 0.5, 0.5 - dy * 0.5, 0.5 + dx * 0.5, 0.5 + dy * 0.5, [
{ offset: 0, color: dItem.color[0] },
{ offset: 1, color: dItem.color[1] },
])
: dItem.color,
},
};
});
/****************************************************/
console