| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- <template>
- <div class="doughnut_charts">
- <div class="operation" v-if="props.showLegend && props.showLegendOperationAll">
- <el-checkbox
- :model-value="showAll"
- :indeterminate="indeterminate"
- @change="(val)=>HandleCheckAllOrNot(val)"
- >
- 显示全部
- </el-checkbox>
- </div>
- <div class="render_doughnut_charts" :style="{height:chartHeight}" ref="chartsRef">
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import {ref,onMounted, watch,computed} from 'vue'
- import * as echarts from 'echarts';
- import type { PropType } from 'vue'
- interface PieItm {
- name:String,
- value:String
- }
- interface SeiresLabelFormatter {
- formatter:Function | String,
- rich:Object
- }
- const props = defineProps({
- chartHeight:{
- type:String,
- default:'270px'
- },
- //饼图数据
- chartData:{
- required:true,
- type:Array<PieItm>
- },
- // 饼图扇形弧度
- rotateAngle:{
- type:[Number,null],
- default:360
- },
- // 是否显示图例
- showLegend:{
- type:Boolean,
- default:true
- },
- // 图例的位置
- legendTop:{
- type:[Number,String],
- default:'auto'
- },
- legendBottom:{
- type:[Number,String],
- default:'auto'
- },
- legendLeft:{
- type:[Number,String],
- default:'auto'
- },
- legendRight:{
- type:[Number,String],
- default:'auto'
- },
- // 图例布局朝向
- legendOrient:{
- type:String,
- default:'vertical'
- },
- // 是否一键隐藏图例或展示图例
- showLegendOperationAll:{
- type:Boolean,
- default:false
- },
- // 图例展示文本
- legendFormatter:{
- type:Function
- },
- // 扇形图位置
- pieTop:{
- type:[Number,String],
- default:0
- },
- pieLeft:{
- type:[Number,String],
- default:0
- },
- pieBottom:{
- type:[Number,String],
- default:0
- },
- pieRight:{
- type:[Number,String],
- default:0
- },
- pieRadius:{
- type:Array,
- required:true
- },
-
- //展示扇区信息
- showSeriesLabel:{
- type:Boolean,
- default:true
- },
- // 扇形的信息展示位置
- seriesLabelPosition:{
- type:String,
- },
- // 扇区信息的格式
- seiresLabelFormatter: {
- type:Object as PropType<SeiresLabelFormatter>
- },
-
- // 展示鼠标悬浮提示
- showTooltip:{
- type:Boolean,
- default:true,
- },
- // 鼠标悬浮提示 展示的位置
- tooltipPosition:{
- type:[Array,Function],
- default:()=>{
- return function (point, params, dom, rect, size) {
- // 固定在鼠标右侧
- return [point[0], point[1]];
- }
- }
- },
- // 图表鼠标悬浮提示信息
- tooltipFormatter:{
- type:[Function,String]
- },
- //页面动态变化的标识
- randomIndex:{
- type:Number,
- required:true
- },
-
- })
- const chartsRef = ref(null)
- const myChart = ref()
- /**
- * 图例全选/取消全选
- */
- const showAll = ref(true)
- const indeterminate = ref(false)
- const selectedLegendList = ref([])
- const HandleCheckAllOrNot = (val)=>{
- console.log('当前的变更值',val)
- showAll.value = val
- indeterminate.value = false
- if(val){
- myChart.value.dispatchAction({
- type: 'legendAllSelect',
- });
- }else{
- // 第一次点击没有图例值 需要调用反选
- if(selectedLegendList.value?.length > 0){
- selectedLegendList.value.map(item=>{
- myChart.value.dispatchAction({
- type: 'legendUnSelect',
- name:item
- })
- })
- }else{
- // 反选
- myChart.value.dispatchAction({
- type: 'legendInverseSelect',
- })
- }
- }
- }
- // 基础配置
- const getBaseOption = () => ({
- tooltip: {
- trigger: 'item',
- borderWidth:0,
- textStyle:{
- color:'#666'
- },
- },
- legend: {
- itemGap:15,
- itemWidth:20,
- padding:1,
- itemHeight:10,
- textStyle:{
- fontSize:12,
- },
- },
- color:['#5470C6','#3BA272','#FAC858','#995FB3','#EE6666','#72C0DD','#90CB75','#EA7ACB','#FC8451','#65789B',
- '#178BD3','#26A616','#A6129E','#D3A141','#234098','#047640','#B43535','#848BDC','#D6AF83','#84313D'],
- series: [
- {
- name: '',
- type: 'pie',
- startAngle:90,
- avoidLabelOverlap: false,
- labelLine: {
- length:15,
- length2:10,
- },
- emphasis: {
- scale:false,
- },
- data: [],
- },
- {
- name: '',
- type: 'pie',
- startAngle:90,
- endAngle:'auto',
- avoidLabelOverlap: false,
- label: {
- show: false,
- },
- labelLine: {
- show: false,
- },
- emphasis: {
- scale:false,
- label: {
- show: false,
- }
- },
- data:[],
- emptyCircleStyle:{
- color:'#F4F5F8',
- opacity:1
- },
- }
- ]
- });
- // 动态配置
- const getDynamicOption = ()=>({
- tooltip: {
- showContent:props.showTooltip,
- formatter: props.tooltipFormatter,
- position:props.tooltipPosition
- },
- legend: {
- show: props.showLegend,
- top: props.legendTop,
- right:props.legendRight,
- left:props.legendLeft,
- bottom:props.legendBottom,
- orient:props.legendOrient,
- // 自定义图例展示内容:名称:占比xx%
- formatter: props.legendFormatter,
- },
- series: [
- {
- name: '',
- radius: props.pieRadius,
- endAngle:endAngle.value,
- top:props.pieTop,
- left:props.pieLeft,
- right:props.pieRight,
- bottom:props.pieBottom,
- label: {
- show: props.showSeriesLabel,
- position:props.seriesLabelPosition,
- ...props.seiresLabelFormatter,
- },
- labelLine: {
- show: props.showSeriesLabel,
- },
- emphasis: {
- disabled: !props.showTooltip,
- label: {
- show: props.showSeriesLabel,
- }
- },
- data: props?.chartData || [],
- },
- {
- name: '',
- radius: props.pieRadius,
- top:props.pieTop,
- left:props.pieLeft,
- right:props.pieRight,
- bottom:props.pieBottom,
- }
- ]
- })
- // 饼图的扇区结束位置
- const endAngle = computed(()=>{
- console.log('旋转角度',props.rotateAngle)
- if(props.rotateAngle && props.rotateAngle !== 360){
- if(props.rotateAngle <= 90){
- return ( 90 - props.rotateAngle)
- }else{
- return ( 90 - props.rotateAngle + 360)
- }
- }else{
- return 'auto'
- }
- })
- const UpdateChart = () =>{
- if(!myChart.value) return
- console.log('labelformater值',props.seiresLabelFormatter)
- myChart.value.setOption(getBaseOption());
- myChart.value.setOption(getDynamicOption());
- }
- const HandleInitChart = ()=>{
- console.log('准备初始化了--')
- if(myChart.value){
- myChart.value?.dispose();
- myChart.value = null
- }
- // 基于准备好的dom,初始化echarts实例
- myChart.value = echarts.init(chartsRef.value);
- UpdateChart()
- myChart.value.on('legendselectchanged', function (params) {
- console.log('图例状态切换了',params);
- selectedLegendList.value = Object.entries(params.selected).map(itm=>itm[0])
- let selectedStatus = Object.values(params.selected)
- let length = selectedStatus.length
- let selectedLegendStatus = selectedStatus.filter(item=>item === true)
- let unSelectedLegend = selectedStatus.filter(item=>item === false)
- if(selectedLegendStatus.length === length || unSelectedLegend.length === length){
- indeterminate.value = false
- if(selectedLegendStatus.length === length){
- showAll.value = true
- }else{
- showAll.value = false
- }
- }else{
- indeterminate.value = true
- }
- });
- }
- watch([()=>props.randomIndex,()=>props.rotateAngle],([newRandom,newRotate],[oldRandom,oldRotate])=>{
- if(!myChart.value) return
- // rotateAngle 实际发生变化时需要重建以应用 endAngle 变更
- if(newRotate !== oldRotate){
- HandleInitChart()
- return
- }
- console.log('执行到了--')
- // 仅容器尺寸/布局变化时调整大小
- try{ myChart.value.resize() }catch(e){}
- })
- watch(()=>props.chartData,(newVal)=>{
- // 数据变换后只更新 series.data
- if(!myChart.value) return
- try{
- // 同步更新 series 数据并刷新 legend 和 label 的展示(使百分比同步)
- myChart.value.setOption(getDynamicOption())
- }catch(e){
- HandleInitChart()
- }
- },{deep:true})
- onMounted(()=>{
- HandleInitChart()
- })
- </script>
- <style lang="scss" scoped>
- .render_doughnut_charts{
- position: relative;
- width: 100%;
- }
- .operation{
- position: absolute;
- :deep(.el-checkbox){
- display: flex;
- align-items: center;
- height: auto !important;
- .el-checkbox__label{
- font-size: 12px !important;
- }
- color:#333333;
- }
- }
- </style>
|