BaseDashboard.vue 2.38 KB
<script lang="ts" setup>
  import type { ECharts, EChartsOption } from 'echarts';
  import type { PropType } from 'vue';
  import { nextTick, onMounted, onUnmounted, ref, unref } from 'vue';
  import { init } from 'echarts';

  interface DataSource {
    id: string | number;
  }

  const props = defineProps({
    dataSource: {
      type: Object as PropType<DataSource>,
      required: true,
    },
    chartOption: {
      type: Object as PropType<EChartsOption>,
      // required: true,
    },
    add: {
      type: Function,
      required: true,
    },
  });

  const getControlsWidgetId = () => `widget-chart-${props.dataSource.id}`;

  const chartRef = ref<Nullable<ECharts>>(null);

  function initChart() {
    const chartDom = document.getElementById(getControlsWidgetId())!;
    chartRef.value = init(chartDom);
    const option: EChartsOption = props.chartOption || {
      tooltip: {
        trigger: 'item',
        // confine: true,
        extraCssText: 'position: fixed;',
        position: (point, params, dom, rect, size) => {
          const parentEl = (dom as HTMLDivElement).parentElement!;

          const { top = 0, left = 0 } = parentEl.getBoundingClientRect()!;
          return [left, top];
        },
      },
      series: [
        {
          name: 'Access From',
          type: 'pie',
          radius: '50%',
          data: [
            { value: 1048, name: 'Search Engine' },
            { value: 735, name: 'Direct' },
            { value: 580, name: 'Email' },
            { value: 484, name: 'Union Ads' },
            { value: 300, name: 'Video Ads' },
          ],
          emphasis: {
            itemStyle: {
              shadowBlur: 10,
              shadowOffsetX: 0,
              shadowColor: 'rgba(0, 0, 0, 0.5)',
            },
          },
        },
      ],
    };

    nextTick(() => {
      option && unref(chartRef)?.setOption(option);
    });
  }

  function update() {
    unref(chartRef)?.resize();
  }

  onMounted(() => {
    initChart();
    props.add(props.dataSource.id, update);
  });

  onUnmounted(() => {
    unref(chartRef)?.clear();
  });

  defineExpose({ update });
</script>

<template>
  <div :id="getControlsWidgetId()" class="widget-charts"></div>
</template>

<style scoped>
  .widget-charts {
    min-width: 10px;
    min-height: 10px;
    width: 100%;
    height: 100%;
  }

  .widget-charts > div {
    width: 100%;
    height: 100%;
  }
</style>