trendBar.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <template>
  2. <div
  3. class="db--chart"
  4. >
  5. <Bar
  6. :data="myData"
  7. :options="chartOptions"
  8. />
  9. <div class="chart--legend">
  10. <div
  11. v-for="(legend, idx) in legends"
  12. :key="`bar-chart-legend-${idx}`"
  13. class="legend"
  14. >
  15. <span class="line" />
  16. <p>{{ legend }}</p>
  17. </div>
  18. </div>
  19. </div>
  20. </template>
  21. <script setup>
  22. /***********************
  23. * import
  24. ************************/
  25. import { Bar } from "vue-chartjs"
  26. import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, LineController, LineElement, PointElement, ArcElement, CategoryScale, LinearScale } from 'chart.js';
  27. import dayjs from "#build/dayjs.imports.mjs";
  28. /***********************
  29. * plugins inject
  30. ************************/
  31. // props
  32. const props = defineProps({
  33. chartItem: {
  34. type: Object,
  35. default: () => {}
  36. },
  37. })
  38. ChartJS.register(
  39. Title,
  40. Tooltip,
  41. Legend,
  42. BarElement,
  43. LineController,
  44. LineElement,
  45. PointElement,
  46. CategoryScale,
  47. ArcElement,
  48. LinearScale,
  49. )
  50. /***********************
  51. * data & created
  52. ************************/
  53. const colorset = ref([
  54. '#FF531E',
  55. '#44C5FF',
  56. '#FF00C7',
  57. '#AF70FF',
  58. '#4862FF',
  59. '#55E074',
  60. ]);
  61. const legends = ref([]);
  62. const chartOptions = ref({
  63. layout: {
  64. padding: {
  65. top: 0,
  66. },
  67. },
  68. responsive: true,
  69. maintainAspectRatio: false,
  70. duration: 1000,
  71. plugins: {
  72. legend: {
  73. display: false,
  74. },
  75. datalabels: {
  76. display: false,
  77. },
  78. tooltip: {
  79. displayColors : false,
  80. callbacks: {
  81. title : function(tooltipItem, data){
  82. return tooltipItem[0].label.substr(0,10) + " " + tooltipItem[0].label.substr(11)
  83. },
  84. titleFont: { // 타이틀 영역 폰트 스타일
  85. size: 10,
  86. weight:500,
  87. family:'Inter',
  88. },
  89. titleColor : '#f00', // 타이틀 영역 폰트 컬러
  90. titleAlign : 'right', // 타이틀 영역 align (left, center, right)
  91. titleMarginBottom : 3,
  92. },
  93. },
  94. },
  95. scales: {
  96. x: {
  97. beginAtZero: true,
  98. stacked: true,
  99. title: {
  100. text: "",
  101. align: "end",
  102. display: false,
  103. font: {
  104. color: "#666",
  105. size: 12,
  106. weight: "500",
  107. },
  108. },
  109. grid: {
  110. display: false,
  111. drawTicks: false,
  112. drawBorder: false,
  113. color: "transparent",
  114. },
  115. ticks: {
  116. padding: 20,
  117. font: {
  118. size: function(context){
  119. const clientW = document.querySelector("body").clientWidth;
  120. if(clientW <= 1930){
  121. return 11
  122. }else if(clientW >= 2550 && clientW < 3840){
  123. return 17
  124. }else if(clientW >= 3840){
  125. return 22
  126. }
  127. },
  128. weight: "400",
  129. },
  130. color: "#838FAC",
  131. align:'center',
  132. },
  133. },
  134. y: {
  135. border: {
  136. display: false,
  137. },
  138. beginAtZero: true,
  139. stacked: false,
  140. title: {
  141. display: false,
  142. text: "",
  143. },
  144. ticks: {
  145. display: true,
  146. padding: 10,
  147. font: {
  148. size: function(context){
  149. const clientW = document.querySelector("body").clientWidth;
  150. if(clientW <= 1930){
  151. return 11
  152. }else if(clientW >= 2550 && clientW < 3840){
  153. return 17
  154. }else if(clientW >= 3840){
  155. return 22
  156. }
  157. },
  158. weight: "400",
  159. },
  160. color: "#b1b1b1",
  161. },
  162. min:0
  163. },
  164. },
  165. animation: {
  166. duration: 0,
  167. },
  168. })
  169. const myData = computed(() => fnGetChartDate(props.chartItem));
  170. /***********************
  171. * Methods
  172. ************************/
  173. const fnGetChartDate = (chartItem) => {
  174. const chartData = { labels: [], datasets: [],}
  175. const { items } = chartItem;
  176. if(!chartItem || !items || items.length < 1) {
  177. return chartData;
  178. }
  179. const labels = []
  180. const datasets = items.reduce((acc, curr, i) => {
  181. Object.keys(curr).forEach((key) => {
  182. if(key == 'INIT_TIME') labels.push(dayjs(curr.INIT_TIME).format('HH:mm'));
  183. else {
  184. if(acc[key]) acc[key].push(curr[key]);
  185. else acc[key] = [curr[key]];
  186. }
  187. })
  188. return acc;
  189. }, {})
  190. legends.value = Object.keys(datasets);
  191. chartData.labels = labels;
  192. chartData.datasets = legends.value.map((key, idx) => {
  193. return {
  194. label: key,
  195. borderWidth : 2,
  196. pointBackgroundColor: colorset.value[idx],
  197. borderColor: colorset.value[idx],
  198. pointRadius : 0,
  199. hoverRadius : 0,
  200. pointStyle : "circle",
  201. data: datasets[key],
  202. type: "line",
  203. fill : false,
  204. }
  205. })
  206. return chartData;
  207. }
  208. </script>