doughnut.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <template>
  2. <div class="db--chart">
  3. <doughnut
  4. :options="myOptions"
  5. :data="myData"
  6. />
  7. </div>
  8. </template>
  9. <script setup>
  10. import { Doughnut } from "vue-chartjs"
  11. import {
  12. Chart as ChartJS,
  13. Title,
  14. Tooltip,
  15. Legend,
  16. BarElement,
  17. LineController,
  18. LineElement,
  19. PointElement,
  20. CategoryScale,
  21. ArcElement,
  22. LinearScale,
  23. Filler,
  24. } from "chart.js"
  25. ChartJS.register(
  26. Title,
  27. Tooltip,
  28. Legend,
  29. BarElement,
  30. LineController,
  31. LineElement,
  32. PointElement,
  33. CategoryScale,
  34. ArcElement,
  35. LinearScale,
  36. Filler
  37. )
  38. // props
  39. const props = defineProps({
  40. propsChartData: {
  41. type: Object,
  42. default: function () {
  43. return {}
  44. }
  45. },
  46. propsChartOptions: {
  47. type: Object,
  48. default: function () {
  49. return {}
  50. }
  51. },
  52. })
  53. const centerTextPlugin = {
  54. id: 'centerText',
  55. beforeDraw(chart) {
  56. if(chart.config.type === 'doughnut'){
  57. const { width, height, ctx } = chart;
  58. const centerTextOptions = chart.config.options.plugins.centerText;
  59. if (centerTextOptions && !useUtil.isNull(centerTextOptions.currentValue) && !useUtil.isNull(centerTextOptions.maxValue)) {
  60. const currentValue = centerTextOptions.currentValue;
  61. const maxValue = centerTextOptions.maxValue;
  62. const percentage = Math.round((currentValue / maxValue) * 100);
  63. ctx.restore();
  64. const fontSize = (height / 150).toFixed(2);
  65. ctx.font = `${fontSize}em`;
  66. const text = `${currentValue}/${maxValue}`;
  67. const textX = Math.round((width - ctx.measureText(text).width) / 2);
  68. const textY = height / 2 - 10;
  69. ctx.fillText(text, textX, textY);
  70. const percentText = `${percentage}%`;
  71. const percentTextX = Math.round((width - ctx.measureText(percentText).width) / 2);
  72. const percentTextY = height / 2 + 15;
  73. ctx.fillText(percentText, percentTextX, percentTextY);
  74. ctx.save();
  75. }
  76. }
  77. }
  78. };
  79. ChartJS.register(centerTextPlugin)
  80. const chartData = ref({
  81. labels: ['현재 가입자 수', '최대 가입자 수'],
  82. datasets: [
  83. {
  84. data: [70,30],
  85. backgroundColor: ['#438dff','#EAEAEA'],
  86. borderWidth: 0,
  87. borderRadius: 200,
  88. }
  89. ]
  90. })
  91. const chartOptions = ref({
  92. responsive: true,
  93. maintainAspectRatio: false,
  94. cutout: '60%',
  95. plugins: {
  96. centerText: {
  97. currentValue: 65,
  98. maxValue: 100,
  99. },
  100. legend: {
  101. display: false
  102. },
  103. tooltip: {
  104. callbacks: {
  105. label: function(tooltipItem) {
  106. return tooltipItem.label + ': '+ tooltipItem.raw;// + tooltipItem.raw.toFixed(2) + '%'
  107. }
  108. }
  109. },
  110. centerText: centerTextPlugin
  111. }
  112. })
  113. const myData = computed(()=>{
  114. const tempData = ref(_cloneDeep(chartData.value))
  115. tempData.value.datasets[0].data = props.propsChartData
  116. return tempData.value
  117. })
  118. const myOptions = computed(()=>{
  119. const tempOptions = ref(_cloneDeep(chartOptions.value))
  120. tempOptions.value.plugins.centerText = props.propsChartOptions
  121. return tempOptions.value
  122. })
  123. </script>