PhysiqueChart.vue 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. <script setup lang="ts">
  2. import { provide, ref } from 'vue';
  3. import VChart, { type EChartsOption, theme } from './echart';
  4. const { dataset = [] } = defineProps<{ dataset?: any[][] }>();
  5. const snapshot = defineModel('snapshot', { default: '' });
  6. provide(...theme);
  7. const option = ref<EChartsOption>({
  8. backgroundColor: 'transparent',
  9. legend: { top: 10, right: 10, },
  10. grid: {
  11. containLabel: true,
  12. top: 50,
  13. bottom: 10,
  14. left: 10,
  15. right: 10,
  16. },
  17. xAxis: {
  18. type: 'category',
  19. splitLine: { show: false },
  20. axisTick: { show: false },
  21. },
  22. yAxis: {
  23. type: 'value', min: 0, max: 100, splitNumber: 5,
  24. axisLine: { show: false },
  25. axisLabel: { show: false },
  26. },
  27. series: [],
  28. });
  29. const defaultSetting = [
  30. { label: '平和体质(正常体质)', color: '#38ff6e' },
  31. { label: '所属体质', color: '#ff8917' },
  32. { label: '倾向体质', color: '#ffbc5b' },
  33. { label: '推断体质', color: '#34a76b' },
  34. { label: '体质', color: '#b2b4ab' },
  35. ];
  36. watchEffect(() => {
  37. const ref = new Set<number>(dataset.map((item) => item[2]));
  38. const legend: EChartsOption['legend'] & {} = { data: [] };
  39. const series: EChartsOption['series'][] = [];
  40. for (const key of ref) {
  41. const { label: name, color } = defaultSetting[key] ?? {};
  42. series.push({
  43. name, type: 'bar',
  44. barMaxWidth: 30, barGap: '-100%',
  45. data: dataset.filter((item) => item[2] === key), itemStyle: { color },
  46. });
  47. if (name !== '体质') legend.data?.push({ name, itemStyle: { color } });
  48. }
  49. option.value.legend = { ...option.value.legend, ...legend };
  50. option.value.series = series as any;
  51. });
  52. const chart = useTemplateRef<InstanceType<typeof VChart>>('chart');
  53. let loaded = false;
  54. function onFinished() {
  55. if (loaded || snapshot.value && snapshot.value.startsWith(`data:image/`)) return;
  56. snapshot.value = chart.value?.getDataURL() ?? '';
  57. loaded = true;
  58. }
  59. </script>
  60. <template>
  61. <div class="mx-auto">
  62. <div class="chart-container">
  63. <v-chart ref="chart" class="chart" :option="option" @finished="onFinished" />
  64. </div>
  65. </div>
  66. </template>
  67. <style scoped lang="scss">
  68. .chart-container {
  69. position: relative;
  70. padding-bottom: 50%;
  71. > .chart {
  72. position: absolute;
  73. top: 0;
  74. left: 0;
  75. width: 100%;
  76. height: 100%;
  77. }
  78. }
  79. </style>