adminator-admin-dashboard 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/CLAUDE.md +162 -0
  2. package/LICENSE +21 -0
  3. package/README.md +376 -0
  4. package/RELEASE_NOTES.md +92 -0
  5. package/dist/1e59d2330b4c6deb84b3.ttf +0 -0
  6. package/dist/20fd1704ea223900efa9.woff2 +0 -0
  7. package/dist/29b39089170885ae2967.woff +0 -0
  8. package/dist/404.html +24 -0
  9. package/dist/500.html +24 -0
  10. package/dist/55b07f26c86c8e3d3754.svg +1 -0
  11. package/dist/8b43027f47b20503057d.eot +0 -0
  12. package/dist/9bad94440d49256265a5.eot +0 -0
  13. package/dist/9fad440d8ee7a949a9a9.svg +1 -0
  14. package/dist/assets/c1e38fd9e0e74ba58f7a2b77ef29fdd3.svg +2671 -0
  15. package/dist/assets/f0fc8c798eac5636249c4ea287832422.svg +362 -0
  16. package/dist/assets/static/fonts/icons/fontawesome/FontAwesome.otf +0 -0
  17. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.eot +0 -0
  18. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.svg +2671 -0
  19. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.ttf +0 -0
  20. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.woff +0 -0
  21. package/dist/assets/static/fonts/icons/fontawesome/fontawesome-webfont.woff2 +0 -0
  22. package/dist/assets/static/fonts/icons/themify/themify.eot +0 -0
  23. package/dist/assets/static/fonts/icons/themify/themify.svg +362 -0
  24. package/dist/assets/static/fonts/icons/themify/themify.ttf +0 -0
  25. package/dist/assets/static/fonts/icons/themify/themify.woff +0 -0
  26. package/dist/assets/static/images/404.png +0 -0
  27. package/dist/assets/static/images/500.png +0 -0
  28. package/dist/assets/static/images/bg.jpg +0 -0
  29. package/dist/assets/static/images/datatables/sort_asc.png +0 -0
  30. package/dist/assets/static/images/datatables/sort_asc_disabled.png +0 -0
  31. package/dist/assets/static/images/datatables/sort_both.png +0 -0
  32. package/dist/assets/static/images/datatables/sort_desc.png +0 -0
  33. package/dist/assets/static/images/datatables/sort_desc_disabled.png +0 -0
  34. package/dist/assets/static/images/logo-circle.svg +7 -0
  35. package/dist/assets/static/images/logo-gradient.svg +13 -0
  36. package/dist/assets/static/images/logo-outline.svg +7 -0
  37. package/dist/assets/static/images/logo.png +0 -0
  38. package/dist/assets/static/images/logo.svg +5 -0
  39. package/dist/basic-table.html +715 -0
  40. package/dist/blank.html +522 -0
  41. package/dist/buttons.html +467 -0
  42. package/dist/calendar.html +692 -0
  43. package/dist/charts.html +681 -0
  44. package/dist/chat.html +730 -0
  45. package/dist/compose.html +643 -0
  46. package/dist/datatable.html +1009 -0
  47. package/dist/eda8b94308c6f538f04a.ttf +0 -0
  48. package/dist/email.html +992 -0
  49. package/dist/f691f37e57f04c152e23.woff +0 -0
  50. package/dist/forms.html +760 -0
  51. package/dist/google-maps.html +530 -0
  52. package/dist/index.html +1090 -0
  53. package/dist/main.js +61239 -0
  54. package/dist/main.js.map +1 -0
  55. package/dist/signin.html +107 -0
  56. package/dist/signup.html +104 -0
  57. package/dist/test.html +91 -0
  58. package/dist/ui.html +931 -0
  59. package/dist/vector-maps.html +529 -0
  60. package/package.json +112 -0
  61. package/src/404.html +24 -0
  62. package/src/500.html +24 -0
  63. package/src/assets/scripts/app.js +644 -0
  64. package/src/assets/scripts/charts/chartJS/index.js +148 -0
  65. package/src/assets/scripts/charts/easyPieChart/index.js +200 -0
  66. package/src/assets/scripts/charts/index.js +3 -0
  67. package/src/assets/scripts/charts/sparkline/index.js +208 -0
  68. package/src/assets/scripts/chat/index.js +11 -0
  69. package/src/assets/scripts/components/Chart.js +1390 -0
  70. package/src/assets/scripts/components/Sidebar.js +241 -0
  71. package/src/assets/scripts/constants/colors.js +274 -0
  72. package/src/assets/scripts/datatable/index.js +379 -0
  73. package/src/assets/scripts/datepicker/index.js +302 -0
  74. package/src/assets/scripts/email/index.js +25 -0
  75. package/src/assets/scripts/fullcalendar/index.js +86 -0
  76. package/src/assets/scripts/googleMaps/index.js +93 -0
  77. package/src/assets/scripts/index.js +18 -0
  78. package/src/assets/scripts/masonry/index.js +14 -0
  79. package/src/assets/scripts/popover/index.js +109 -0
  80. package/src/assets/scripts/scrollbar/index.js +10 -0
  81. package/src/assets/scripts/search/index.js +15 -0
  82. package/src/assets/scripts/sidebar/index.js +140 -0
  83. package/src/assets/scripts/skycons/index.js +52 -0
  84. package/src/assets/scripts/ui/index.js +412 -0
  85. package/src/assets/scripts/utils/date.js +242 -0
  86. package/src/assets/scripts/utils/dom.js +349 -0
  87. package/src/assets/scripts/utils/index.js +45 -0
  88. package/src/assets/scripts/utils/theme.js +105 -0
  89. package/src/assets/scripts/vectorMaps/index.js +277 -0
  90. package/src/assets/static/fonts/icons/fontawesome/FontAwesome.otf +0 -0
  91. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.eot +0 -0
  92. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.svg +2671 -0
  93. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.ttf +0 -0
  94. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.woff +0 -0
  95. package/src/assets/static/fonts/icons/fontawesome/fontawesome-webfont.woff2 +0 -0
  96. package/src/assets/static/fonts/icons/themify/themify.eot +0 -0
  97. package/src/assets/static/fonts/icons/themify/themify.svg +362 -0
  98. package/src/assets/static/fonts/icons/themify/themify.ttf +0 -0
  99. package/src/assets/static/fonts/icons/themify/themify.woff +0 -0
  100. package/src/assets/static/images/404.png +0 -0
  101. package/src/assets/static/images/500.png +0 -0
  102. package/src/assets/static/images/bg.jpg +0 -0
  103. package/src/assets/static/images/datatables/sort_asc.png +0 -0
  104. package/src/assets/static/images/datatables/sort_asc_disabled.png +0 -0
  105. package/src/assets/static/images/datatables/sort_both.png +0 -0
  106. package/src/assets/static/images/datatables/sort_desc.png +0 -0
  107. package/src/assets/static/images/datatables/sort_desc_disabled.png +0 -0
  108. package/src/assets/static/images/logo-circle.svg +7 -0
  109. package/src/assets/static/images/logo-gradient.svg +13 -0
  110. package/src/assets/static/images/logo-outline.svg +7 -0
  111. package/src/assets/static/images/logo.png +0 -0
  112. package/src/assets/static/images/logo.svg +5 -0
  113. package/src/assets/styles/index.scss +801 -0
  114. package/src/assets/styles/spec/components/easyPieChart.scss +11 -0
  115. package/src/assets/styles/spec/components/footer.scss +4 -0
  116. package/src/assets/styles/spec/components/forms.scss +288 -0
  117. package/src/assets/styles/spec/components/index.scss +9 -0
  118. package/src/assets/styles/spec/components/loader.scss +46 -0
  119. package/src/assets/styles/spec/components/masonry.scss +1 -0
  120. package/src/assets/styles/spec/components/pageContainer.scss +255 -0
  121. package/src/assets/styles/spec/components/progressBar.scss +6 -0
  122. package/src/assets/styles/spec/components/sidebar.scss +642 -0
  123. package/src/assets/styles/spec/components/topbar.scss +455 -0
  124. package/src/assets/styles/spec/generic/base.scss +102 -0
  125. package/src/assets/styles/spec/generic/index.scss +1 -0
  126. package/src/assets/styles/spec/index.scss +4 -0
  127. package/src/assets/styles/spec/screens/chat.scss +147 -0
  128. package/src/assets/styles/spec/screens/email.scss +108 -0
  129. package/src/assets/styles/spec/screens/index.scss +2 -0
  130. package/src/assets/styles/spec/settings/baseColors.scss +103 -0
  131. package/src/assets/styles/spec/settings/borders.scss +6 -0
  132. package/src/assets/styles/spec/settings/breakpoints.scss +26 -0
  133. package/src/assets/styles/spec/settings/fonts.scss +4 -0
  134. package/src/assets/styles/spec/settings/index.scss +4 -0
  135. package/src/assets/styles/spec/settings/materialColors.scss +550 -0
  136. package/src/assets/styles/spec/tools/index.scss +1 -0
  137. package/src/assets/styles/spec/tools/mixins/clearfix.scss +15 -0
  138. package/src/assets/styles/spec/tools/mixins/index.scss +3 -0
  139. package/src/assets/styles/spec/tools/mixins/mediaQueriesRanges.scss +58 -0
  140. package/src/assets/styles/spec/tools/mixins/placeholder.scss +10 -0
  141. package/src/assets/styles/spec/utils/colors.scss +33 -0
  142. package/src/assets/styles/spec/utils/index.scss +2 -0
  143. package/src/assets/styles/spec/utils/layout/helpers/border.scss +78 -0
  144. package/src/assets/styles/spec/utils/layout/helpers/flex.scss +220 -0
  145. package/src/assets/styles/spec/utils/layout/helpers/index.scss +11 -0
  146. package/src/assets/styles/spec/utils/layout/helpers/layout.scss +137 -0
  147. package/src/assets/styles/spec/utils/layout/helpers/lists.scss +23 -0
  148. package/src/assets/styles/spec/utils/layout/helpers/margin.scss +266 -0
  149. package/src/assets/styles/spec/utils/layout/helpers/objects.scss +91 -0
  150. package/src/assets/styles/spec/utils/layout/helpers/padding.scss +147 -0
  151. package/src/assets/styles/spec/utils/layout/helpers/positions.scss +118 -0
  152. package/src/assets/styles/spec/utils/layout/helpers/pseudo.scss +6 -0
  153. package/src/assets/styles/spec/utils/layout/helpers/sizes.scss +157 -0
  154. package/src/assets/styles/spec/utils/layout/helpers/typography.scss +127 -0
  155. package/src/assets/styles/spec/utils/layout/index.scss +3 -0
  156. package/src/assets/styles/spec/utils/layout/mixins/generateResponsive.scss +25 -0
  157. package/src/assets/styles/spec/utils/layout/mixins/index.scss +2 -0
  158. package/src/assets/styles/spec/utils/layout/mixins/mediaQueryCondition.scss +28 -0
  159. package/src/assets/styles/spec/utils/layout/utils/center.scss +54 -0
  160. package/src/assets/styles/spec/utils/layout/utils/gap.scss +229 -0
  161. package/src/assets/styles/spec/utils/layout/utils/index.scss +5 -0
  162. package/src/assets/styles/spec/utils/layout/utils/layers.scss +5 -0
  163. package/src/assets/styles/spec/utils/layout/utils/peers.scss +35 -0
  164. package/src/assets/styles/utils/mobile.scss +954 -0
  165. package/src/assets/styles/utils/theme.css +97 -0
  166. package/src/assets/styles/vendor/datepicker.scss +183 -0
  167. package/src/assets/styles/vendor/font-awesome.css +2337 -0
  168. package/src/assets/styles/vendor/fullcalendar.scss +217 -0
  169. package/src/assets/styles/vendor/index.scss +8 -0
  170. package/src/assets/styles/vendor/jquery.datatables.scss +162 -0
  171. package/src/assets/styles/vendor/perfectScrollbar.scss +4 -0
  172. package/src/assets/styles/vendor/sparkline.scss +6 -0
  173. package/src/assets/styles/vendor/themify-icons.css +1081 -0
  174. package/src/basic-table.html +725 -0
  175. package/src/blank.html +532 -0
  176. package/src/buttons.html +477 -0
  177. package/src/calendar.html +702 -0
  178. package/src/charts.html +691 -0
  179. package/src/chat.html +740 -0
  180. package/src/compose.html +653 -0
  181. package/src/datatable.html +1019 -0
  182. package/src/email.html +1002 -0
  183. package/src/forms.html +770 -0
  184. package/src/google-maps.html +540 -0
  185. package/src/index.html +1100 -0
  186. package/src/signin.html +107 -0
  187. package/src/signup.html +104 -0
  188. package/src/test.html +96 -0
  189. package/src/ui.html +941 -0
  190. package/src/vector-maps.html +539 -0
  191. package/webpack.config.js +3 -0
@@ -0,0 +1,1390 @@
1
+ /**
2
+ * Modern Chart Component
3
+ * Replaces jQuery Sparkline with Chart.js
4
+ */
5
+
6
+ import { Chart, registerables } from 'chart.js';
7
+ import { COLORS } from '../constants/colors';
8
+
9
+ // Register Chart.js components
10
+ Chart.register(...registerables);
11
+
12
+ class ChartComponent {
13
+ constructor() {
14
+ this.charts = new Map(); // Store chart instances
15
+ this.debounceTimer = null;
16
+ this.init();
17
+ }
18
+
19
+ init() {
20
+ // Only disable resizing for small sparkline charts
21
+ this.createSparklines();
22
+ this.createOtherCharts();
23
+ this.setupResizeHandler();
24
+ }
25
+
26
+
27
+
28
+ /**
29
+ * Create sparklines (only for dashboard page)
30
+ */
31
+ createSparklines() {
32
+ // Only create sparklines if we're on a page that has them
33
+ const sparklineExists = document.getElementById('sparklinedash');
34
+ if (!sparklineExists) {
35
+ return;
36
+ }
37
+
38
+ const sparklineConfigs = [
39
+ {
40
+ id: 'sparklinedash',
41
+ data: [0, 5, 6, 10, 9, 12, 4, 9],
42
+ color: '#4caf50',
43
+ },
44
+ {
45
+ id: 'sparklinedash2',
46
+ data: [0, 5, 6, 10, 9, 12, 4, 9],
47
+ color: '#9675ce',
48
+ },
49
+ {
50
+ id: 'sparklinedash3',
51
+ data: [0, 5, 6, 10, 9, 12, 4, 9],
52
+ color: '#03a9f3',
53
+ },
54
+ {
55
+ id: 'sparklinedash4',
56
+ data: [0, 5, 6, 10, 9, 12, 4, 9],
57
+ color: '#f96262',
58
+ },
59
+ ];
60
+
61
+ sparklineConfigs.forEach(config => {
62
+ // Only create if the target element exists
63
+ if (document.getElementById(config.id)) {
64
+ this.createSparklineChart(config);
65
+ }
66
+ });
67
+ }
68
+
69
+ /**
70
+ * Create sparkline chart from configuration
71
+ */
72
+ createSparklineChart({ id, data, color }) {
73
+ let canvas = document.getElementById(id);
74
+
75
+ // Only proceed if we have a valid target element
76
+ if (!canvas) {
77
+ return;
78
+ }
79
+
80
+ // If element exists but isn't a canvas, replace it with canvas
81
+ if (canvas.tagName !== 'CANVAS') {
82
+ const parent = canvas.parentNode;
83
+ if (!parent) {
84
+ return;
85
+ }
86
+
87
+ // Create new canvas element
88
+ const newCanvas = document.createElement('canvas');
89
+ newCanvas.id = id;
90
+ newCanvas.width = 100;
91
+ newCanvas.height = 20;
92
+ newCanvas.style.width = '100px';
93
+ newCanvas.style.height = '20px';
94
+
95
+ // Replace the span with canvas
96
+ parent.replaceChild(newCanvas, canvas);
97
+ canvas = newCanvas;
98
+ } else {
99
+ // Set canvas dimensions to match original sparkline
100
+ canvas.width = 100;
101
+ canvas.height = 20;
102
+ canvas.style.width = '100px';
103
+ canvas.style.height = '20px';
104
+ }
105
+
106
+ const ctx = canvas.getContext('2d');
107
+
108
+ const chart = new Chart(ctx, {
109
+ type: 'bar',
110
+ data: {
111
+ labels: data.map((_, i) => i),
112
+ datasets: [{
113
+ data,
114
+ backgroundColor: color,
115
+ borderColor: color,
116
+ borderWidth: 0,
117
+ barPercentage: 0.6,
118
+ categoryPercentage: 0.8,
119
+ }],
120
+ },
121
+ options: {
122
+ responsive: false,
123
+ maintainAspectRatio: false,
124
+ animation: false,
125
+ events: [],
126
+ onResize: null,
127
+ scales: {
128
+ x: {
129
+ display: false,
130
+ },
131
+ y: {
132
+ display: false,
133
+ },
134
+ },
135
+ plugins: {
136
+ legend: {
137
+ display: false,
138
+ },
139
+ tooltip: {
140
+ enabled: false,
141
+ },
142
+ },
143
+ elements: {
144
+ bar: {
145
+ borderRadius: 1,
146
+ },
147
+ },
148
+ },
149
+ });
150
+
151
+ this.charts.set(id, chart);
152
+ }
153
+
154
+ /**
155
+ * Create other chart types (only if they exist on the page)
156
+ */
157
+ createOtherCharts() {
158
+ // Determine if we're on the dashboard or charts page
159
+ const isChartsPage = document.getElementById('area-chart') !== null;
160
+ const isDashboard = !isChartsPage && document.getElementById('line-chart') !== null;
161
+
162
+ // Create Monthly Stats chart with enhanced dual-line data (dashboard only)
163
+ if (isDashboard) {
164
+ this.createMonthlyStatsChart();
165
+ }
166
+
167
+ // Charts page specific charts (only on charts page)
168
+ if (isChartsPage) {
169
+ this.createChartsPageCharts();
170
+ }
171
+
172
+ // Only create charts if their target elements exist
173
+ if (document.getElementById('sparkline')) {
174
+ this.createLineChart('sparkline', [5, 6, 7, 9, 9, 5, 3, 2, 2, 4, 6, 7]);
175
+ }
176
+
177
+ if (document.getElementById('compositebar')) {
178
+ this.createCompositeChart('compositebar', [4, 1, 5, 7, 9, 9, 8, 7, 6, 6, 4, 7, 8, 4, 3, 2, 2, 5, 6, 7]);
179
+ }
180
+
181
+ // Regular sparklines with custom colors (only on pages that have them)
182
+ this.createCustomSparklines();
183
+
184
+ // Easy Pie Charts (only if they exist)
185
+ this.createEasyPieCharts();
186
+ }
187
+
188
+ /**
189
+ * Create enhanced Monthly Stats chart with dual lines and more data
190
+ */
191
+ createMonthlyStatsChart() {
192
+ const canvas = document.getElementById('line-chart');
193
+ if (!canvas) return;
194
+
195
+ const ctx = canvas.getContext('2d');
196
+
197
+ // Enhanced data for monthly stats
198
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
199
+ const salesData = [120, 135, 145, 165, 180, 195, 210, 225, 240, 220, 200, 185];
200
+ const profitData = [45, 52, 58, 62, 68, 75, 82, 88, 92, 85, 78, 72];
201
+
202
+ const chart = new Chart(ctx, {
203
+ type: 'line',
204
+ data: {
205
+ labels: months,
206
+ datasets: [
207
+ {
208
+ label: 'Sales ($K)',
209
+ data: salesData,
210
+ borderColor: '#4caf50',
211
+ backgroundColor: 'rgba(76, 175, 80, 0.1)',
212
+ borderWidth: 3,
213
+ pointRadius: 5,
214
+ pointHoverRadius: 7,
215
+ pointBackgroundColor: '#4caf50',
216
+ pointBorderColor: '#ffffff',
217
+ pointBorderWidth: 2,
218
+ tension: 0.4,
219
+ fill: false,
220
+ },
221
+ {
222
+ label: 'Profit ($K)',
223
+ data: profitData,
224
+ borderColor: '#2196f3',
225
+ backgroundColor: 'rgba(33, 150, 243, 0.1)',
226
+ borderWidth: 3,
227
+ pointRadius: 5,
228
+ pointHoverRadius: 7,
229
+ pointBackgroundColor: '#2196f3',
230
+ pointBorderColor: '#ffffff',
231
+ pointBorderWidth: 2,
232
+ tension: 0.4,
233
+ fill: false,
234
+ },
235
+ ],
236
+ },
237
+ options: {
238
+ responsive: true,
239
+ maintainAspectRatio: false,
240
+ plugins: {
241
+ legend: {
242
+ display: true,
243
+ position: 'top',
244
+ labels: {
245
+ padding: 20,
246
+ font: {
247
+ size: 12,
248
+ weight: '600',
249
+ },
250
+ },
251
+ },
252
+ tooltip: {
253
+ enabled: true,
254
+ cornerRadius: 8,
255
+ displayColors: true,
256
+ intersect: false,
257
+ mode: 'index',
258
+ callbacks: {
259
+ label(context) {
260
+ return `${context.dataset.label }: $${ context.parsed.y }K`;
261
+ },
262
+ },
263
+ },
264
+ },
265
+ scales: {
266
+ x: {
267
+ grid: {
268
+ display: false,
269
+ },
270
+ ticks: {
271
+ font: {
272
+ size: 11,
273
+ },
274
+ },
275
+ },
276
+ y: {
277
+ beginAtZero: true,
278
+ grid: {
279
+ borderDash: [5, 5],
280
+ },
281
+ ticks: {
282
+ font: {
283
+ size: 11,
284
+ },
285
+ callback(value) {
286
+ return `$${ value }K`;
287
+ },
288
+ },
289
+ },
290
+ },
291
+ interaction: {
292
+ intersect: false,
293
+ mode: 'index',
294
+ },
295
+ },
296
+ });
297
+
298
+ this.charts.set('line-chart', chart);
299
+ }
300
+
301
+ /**
302
+ * Create line chart (only if target exists)
303
+ */
304
+ createLineChart(id, data) {
305
+ let canvas = document.getElementById(id);
306
+
307
+ // Only proceed if target element exists
308
+ if (!canvas) {
309
+ return;
310
+ }
311
+
312
+ // If element exists but isn't a canvas, replace it with canvas
313
+ if (canvas.tagName !== 'CANVAS') {
314
+ const parent = canvas.parentNode;
315
+ if (!parent) {
316
+ return;
317
+ }
318
+
319
+ // Create new canvas element
320
+ const newCanvas = document.createElement('canvas');
321
+ newCanvas.id = id;
322
+ newCanvas.width = 100;
323
+ newCanvas.height = 20;
324
+ newCanvas.style.width = '100px';
325
+ newCanvas.style.height = '20px';
326
+
327
+ // Replace element with canvas
328
+ parent.replaceChild(newCanvas, canvas);
329
+ canvas = newCanvas;
330
+ } else {
331
+ canvas.width = 100;
332
+ canvas.height = 20;
333
+ canvas.style.width = '100px';
334
+ canvas.style.height = '20px';
335
+ }
336
+
337
+ const ctx = canvas.getContext('2d');
338
+
339
+ const chart = new Chart(ctx, {
340
+ type: 'line',
341
+ data: {
342
+ labels: data.map((_, i) => i),
343
+ datasets: [{
344
+ data,
345
+ borderColor: COLORS['blue-500'],
346
+ backgroundColor: 'transparent',
347
+ borderWidth: 1,
348
+ pointRadius: 0,
349
+ tension: 0.4,
350
+ }],
351
+ },
352
+ options: {
353
+ responsive: false,
354
+ maintainAspectRatio: false,
355
+ animation: false,
356
+ events: [],
357
+ onResize: null,
358
+ scales: {
359
+ x: { display: false },
360
+ y: { display: false },
361
+ },
362
+ plugins: {
363
+ legend: { display: false },
364
+ tooltip: { enabled: false },
365
+ },
366
+ },
367
+ });
368
+
369
+ this.charts.set(id, chart);
370
+ }
371
+
372
+ /**
373
+ * Create composite chart (only if target exists)
374
+ */
375
+ createCompositeChart(id, data) {
376
+ let canvas = document.getElementById(id);
377
+
378
+ // Only proceed if target element exists
379
+ if (!canvas) {
380
+ return;
381
+ }
382
+
383
+ // If element exists but isn't a canvas, replace it with canvas
384
+ if (canvas.tagName !== 'CANVAS') {
385
+ const parent = canvas.parentNode;
386
+ if (!parent) {
387
+ return;
388
+ }
389
+
390
+ // Create new canvas element
391
+ const newCanvas = document.createElement('canvas');
392
+ newCanvas.id = id;
393
+ newCanvas.width = 100;
394
+ newCanvas.height = 20;
395
+ newCanvas.style.width = '100px';
396
+ newCanvas.style.height = '20px';
397
+
398
+ // Replace element with canvas
399
+ parent.replaceChild(newCanvas, canvas);
400
+ canvas = newCanvas;
401
+ } else {
402
+ canvas.width = 100;
403
+ canvas.height = 20;
404
+ canvas.style.width = '100px';
405
+ canvas.style.height = '20px';
406
+ }
407
+
408
+ const ctx = canvas.getContext('2d');
409
+
410
+ const chart = new Chart(ctx, {
411
+ type: 'bar',
412
+ data: {
413
+ labels: data.map((_, i) => i),
414
+ datasets: [
415
+ {
416
+ type: 'bar',
417
+ data,
418
+ backgroundColor: '#aaf',
419
+ borderColor: '#aaf',
420
+ borderWidth: 0,
421
+ },
422
+ {
423
+ type: 'line',
424
+ data,
425
+ borderColor: 'red',
426
+ backgroundColor: 'transparent',
427
+ borderWidth: 1,
428
+ pointRadius: 0,
429
+ tension: 0.4,
430
+ },
431
+ ],
432
+ },
433
+ options: {
434
+ responsive: false,
435
+ maintainAspectRatio: false,
436
+ animation: false,
437
+ events: [],
438
+ onResize: null,
439
+ scales: {
440
+ x: { display: false },
441
+ y: { display: false },
442
+ },
443
+ plugins: {
444
+ legend: { display: false },
445
+ tooltip: { enabled: false },
446
+ },
447
+ },
448
+ });
449
+
450
+ this.charts.set(id, chart);
451
+ }
452
+
453
+ /**
454
+ * Create custom sparklines for different elements (only if they exist)
455
+ */
456
+ createCustomSparklines() {
457
+ const sparklineElements = document.querySelectorAll('.sparkline');
458
+ const sparkbarElements = document.querySelectorAll('.sparkbar');
459
+ const sparktriElements = document.querySelectorAll('.sparktri');
460
+ const sparkdiscElements = document.querySelectorAll('.sparkdisc');
461
+ const sparkbullElements = document.querySelectorAll('.sparkbull');
462
+ const sparkboxElements = document.querySelectorAll('.sparkbox');
463
+
464
+ // Only create if we have elements
465
+ if (sparklineElements.length === 0 && sparkbarElements.length === 0 &&
466
+ sparktriElements.length === 0 && sparkdiscElements.length === 0 &&
467
+ sparkbullElements.length === 0 && sparkboxElements.length === 0) {
468
+ return;
469
+ }
470
+
471
+ const values = [5, 4, 5, -2, 0, 3, -5, 6, 7, 9, 9, 5, -3, -2, 2, -4];
472
+ const valuesAlt = [1, 1, 0, 1, -1, -1, 1, -1, 0, 0, 1, 1];
473
+
474
+ sparklineElements.forEach((element, index) => {
475
+ this.createCustomLineChart(element, values, `sparkline-${index}`);
476
+ });
477
+
478
+ sparkbarElements.forEach((element, index) => {
479
+ this.createCustomBarChart(element, values, `sparkbar-${index}`);
480
+ });
481
+
482
+ sparktriElements.forEach((element, index) => {
483
+ this.createTristateChart(element, valuesAlt, `sparktri-${index}`);
484
+ });
485
+
486
+ sparkdiscElements.forEach((element, index) => {
487
+ this.createDiscreteChart(element, values, `sparkdisc-${index}`);
488
+ });
489
+
490
+ sparkbullElements.forEach((element, index) => {
491
+ this.createBulletChart(element, values, `sparkbull-${index}`);
492
+ });
493
+
494
+ sparkboxElements.forEach((element, index) => {
495
+ this.createBoxChart(element, values, `sparkbox-${index}`);
496
+ });
497
+ }
498
+
499
+ /**
500
+ * Create custom line chart for sparkline elements
501
+ */
502
+ createCustomLineChart(element, data, id) {
503
+ // Create canvas if it doesn't exist
504
+ let canvas = element.querySelector('canvas');
505
+ if (!canvas) {
506
+ canvas = document.createElement('canvas');
507
+ canvas.width = 100;
508
+ canvas.height = 20;
509
+ canvas.style.width = '100px';
510
+ canvas.style.height = '20px';
511
+ element.appendChild(canvas);
512
+ }
513
+
514
+ const ctx = canvas.getContext('2d');
515
+
516
+ const chart = new Chart(ctx, {
517
+ type: 'line',
518
+ data: {
519
+ labels: data.map((_, i) => i),
520
+ datasets: [{
521
+ data,
522
+ borderColor: COLORS['red-500'],
523
+ backgroundColor: 'transparent',
524
+ borderWidth: 2,
525
+ pointRadius: 3,
526
+ pointBackgroundColor: COLORS['red-500'],
527
+ tension: 0.4,
528
+ }],
529
+ },
530
+ options: {
531
+ responsive: false,
532
+ maintainAspectRatio: false,
533
+ animation: false, // Disable animations to prevent resize triggers
534
+ events: [], // Disable all events to prevent resize
535
+ onResize: null, // Explicitly disable resize callback
536
+ scales: {
537
+ x: { display: false },
538
+ y: { display: false },
539
+ },
540
+ plugins: {
541
+ legend: { display: false },
542
+ tooltip: { enabled: false }, // Disable tooltip to prevent events
543
+ },
544
+ },
545
+ });
546
+
547
+
548
+
549
+ this.charts.set(id, chart);
550
+ }
551
+
552
+ /**
553
+ * Create custom bar chart for sparkbar elements
554
+ */
555
+ createCustomBarChart(element, data, id) {
556
+ // Create canvas if it doesn't exist
557
+ let canvas = element.querySelector('canvas');
558
+ if (!canvas) {
559
+ canvas = document.createElement('canvas');
560
+ canvas.width = 100;
561
+ canvas.height = 20;
562
+ canvas.style.width = '100px';
563
+ canvas.style.height = '20px';
564
+ element.appendChild(canvas);
565
+ }
566
+
567
+ const ctx = canvas.getContext('2d');
568
+
569
+ const chart = new Chart(ctx, {
570
+ type: 'bar',
571
+ data: {
572
+ labels: data.map((_, i) => i),
573
+ datasets: [{
574
+ data,
575
+ backgroundColor: data.map(val => val < 0 ? COLORS['deep-purple-500'] : '#39f'),
576
+ borderColor: data.map(val => val < 0 ? COLORS['deep-purple-500'] : '#39f'),
577
+ borderWidth: 1,
578
+ barPercentage: 0.8,
579
+ }],
580
+ },
581
+ options: {
582
+ responsive: false,
583
+ maintainAspectRatio: false,
584
+ scales: {
585
+ x: { display: false },
586
+ y: { display: false },
587
+ },
588
+ plugins: {
589
+ legend: { display: false },
590
+ tooltip: {
591
+ enabled: true,
592
+ callbacks: {
593
+ label: (context) => `${context.parsed.y}°Celsius`,
594
+ },
595
+ },
596
+ },
597
+ },
598
+ });
599
+
600
+ this.charts.set(id, chart);
601
+ }
602
+
603
+ /**
604
+ * Setup resize handler for charts
605
+ */
606
+ setupResizeHandler() {
607
+ // Setup responsive resize for large charts only
608
+ window.addEventListener('resize', () => {
609
+ this.debounceResize();
610
+ });
611
+
612
+ // Listen for sidebar toggle events
613
+ window.addEventListener('sidebar:toggle', () => {
614
+ this.debounceResize();
615
+ });
616
+ }
617
+
618
+ /**
619
+ * Debounced resize handler
620
+ */
621
+ debounceResize() {
622
+ if (this.debounceTimer) {
623
+ clearTimeout(this.debounceTimer);
624
+ }
625
+ this.debounceTimer = setTimeout(() => {
626
+ this.redrawLargeChartsOnly();
627
+ }, 150);
628
+ }
629
+
630
+ /**
631
+ * Redraw only large charts, not sparklines
632
+ */
633
+ redrawLargeChartsOnly() {
634
+ const largeChartIds = [
635
+ 'line-chart', 'area-chart', 'scatter-chart', 'bar-chart',
636
+ 'doughnut-chart', 'polar-chart', 'radar-chart', 'mixed-chart', 'bubble-chart',
637
+ ];
638
+
639
+ largeChartIds.forEach(id => {
640
+ const chart = this.charts.get(id);
641
+ if (chart && chart.options.responsive) {
642
+ chart.resize();
643
+ }
644
+ });
645
+ }
646
+
647
+ /**
648
+ * Redraw all charts (used sparingly)
649
+ */
650
+ redrawCharts() {
651
+ this.charts.forEach((chart) => {
652
+ if (chart.options.responsive) {
653
+ chart.resize();
654
+ }
655
+ });
656
+ }
657
+
658
+ /**
659
+ * Update chart data
660
+ */
661
+ updateChart(id, newData) {
662
+ const chart = this.charts.get(id);
663
+ if (chart) {
664
+ chart.data.datasets[0].data = newData;
665
+ chart.update();
666
+ }
667
+ }
668
+
669
+ /**
670
+ * Create charts for the charts.html page
671
+ */
672
+ createChartsPageCharts() {
673
+ // Line Chart
674
+ this.createLargeChart('line-chart', 'line', {
675
+ labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
676
+ datasets: [{
677
+ label: 'Dataset 1',
678
+ data: [65, 59, 80, 81, 56, 55, 40],
679
+ borderColor: 'rgb(75, 192, 192)',
680
+ backgroundColor: 'rgba(75, 192, 192, 0.2)',
681
+ tension: 0.4,
682
+ }],
683
+ });
684
+
685
+ // Area Chart
686
+ this.createLargeChart('area-chart', 'line', {
687
+ labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
688
+ datasets: [{
689
+ label: 'Dataset 1',
690
+ data: [65, 59, 80, 81, 56, 55, 40],
691
+ borderColor: 'rgb(54, 162, 235)',
692
+ backgroundColor: 'rgba(54, 162, 235, 0.4)',
693
+ fill: true,
694
+ tension: 0.4,
695
+ }],
696
+ });
697
+
698
+ // Scatter Chart with more data points
699
+ this.createLargeChart('scatter-chart', 'scatter', {
700
+ datasets: [{
701
+ label: 'Dataset 1',
702
+ data: [
703
+ {x: -15, y: 8}, {x: -12, y: 12}, {x: -8, y: 3}, {x: -5, y: 15},
704
+ {x: -2, y: 7}, {x: 0, y: 10}, {x: 3, y: 18}, {x: 6, y: 5},
705
+ {x: 9, y: 22}, {x: 12, y: 8}, {x: 15, y: 14}, {x: 18, y: 19},
706
+ {x: -10, y: 0}, {x: 10, y: 5}, {x: 0.5, y: 5.5}, {x: 7, y: 12},
707
+ {x: -7, y: 17}, {x: 4, y: 9}, {x: 11, y: 16}, {x: -3, y: 11},
708
+ ],
709
+ backgroundColor: 'rgba(255, 99, 132, 0.7)',
710
+ borderColor: 'rgb(255, 99, 132)',
711
+ borderWidth: 1,
712
+ }, {
713
+ label: 'Dataset 2',
714
+ data: [
715
+ {x: -13, y: 4}, {x: -9, y: 8}, {x: -6, y: 13}, {x: -1, y: 6},
716
+ {x: 2, y: 11}, {x: 5, y: 15}, {x: 8, y: 2}, {x: 13, y: 17},
717
+ {x: 16, y: 9}, {x: -4, y: 14}, {x: 1, y: 20}, {x: 14, y: 4},
718
+ ],
719
+ backgroundColor: 'rgba(54, 162, 235, 0.7)',
720
+ borderColor: 'rgb(54, 162, 235)',
721
+ borderWidth: 1,
722
+ }],
723
+ });
724
+
725
+ // Bar Chart
726
+ this.createLargeChart('bar-chart', 'bar', {
727
+ labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
728
+ datasets: [{
729
+ label: '# of Votes',
730
+ data: [12, 19, 3, 5, 2, 3],
731
+ backgroundColor: [
732
+ 'rgba(255, 99, 132, 0.6)',
733
+ 'rgba(54, 162, 235, 0.6)',
734
+ 'rgba(255, 205, 86, 0.6)',
735
+ 'rgba(75, 192, 192, 0.6)',
736
+ 'rgba(153, 102, 255, 0.6)',
737
+ 'rgba(255, 159, 64, 0.6)',
738
+ ],
739
+ borderColor: [
740
+ 'rgba(255, 99, 132, 1)',
741
+ 'rgba(54, 162, 235, 1)',
742
+ 'rgba(255, 205, 86, 1)',
743
+ 'rgba(75, 192, 192, 1)',
744
+ 'rgba(153, 102, 255, 1)',
745
+ 'rgba(255, 159, 64, 1)',
746
+ ],
747
+ borderWidth: 1,
748
+ }],
749
+ });
750
+
751
+ // Doughnut Chart
752
+ this.createLargeChart('doughnut-chart', 'doughnut', {
753
+ labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
754
+ datasets: [{
755
+ label: 'My First Dataset',
756
+ data: [300, 50, 100, 75, 120, 60],
757
+ backgroundColor: [
758
+ 'rgba(255, 99, 132, 0.8)',
759
+ 'rgba(54, 162, 235, 0.8)',
760
+ 'rgba(255, 205, 86, 0.8)',
761
+ 'rgba(75, 192, 192, 0.8)',
762
+ 'rgba(153, 102, 255, 0.8)',
763
+ 'rgba(255, 159, 64, 0.8)',
764
+ ],
765
+ borderColor: [
766
+ 'rgba(255, 99, 132, 1)',
767
+ 'rgba(54, 162, 235, 1)',
768
+ 'rgba(255, 205, 86, 1)',
769
+ 'rgba(75, 192, 192, 1)',
770
+ 'rgba(153, 102, 255, 1)',
771
+ 'rgba(255, 159, 64, 1)',
772
+ ],
773
+ borderWidth: 2,
774
+ hoverOffset: 10,
775
+ }],
776
+ });
777
+
778
+ // Polar Area Chart
779
+ this.createLargeChart('polar-chart', 'polarArea', {
780
+ labels: ['Red', 'Green', 'Yellow', 'Grey', 'Blue'],
781
+ datasets: [{
782
+ label: 'My First Dataset',
783
+ data: [11, 16, 7, 3, 14],
784
+ backgroundColor: [
785
+ 'rgba(255, 99, 132, 0.7)',
786
+ 'rgba(75, 192, 192, 0.7)',
787
+ 'rgba(255, 205, 86, 0.7)',
788
+ 'rgba(201, 203, 207, 0.7)',
789
+ 'rgba(54, 162, 235, 0.7)',
790
+ ],
791
+ borderColor: [
792
+ 'rgb(255, 99, 132)',
793
+ 'rgb(75, 192, 192)',
794
+ 'rgb(255, 205, 86)',
795
+ 'rgb(201, 203, 207)',
796
+ 'rgb(54, 162, 235)',
797
+ ],
798
+ borderWidth: 2,
799
+ }],
800
+ });
801
+
802
+ // Radar Chart
803
+ this.createLargeChart('radar-chart', 'radar', {
804
+ labels: ['Speed', 'Reliability', 'Comfort', 'Safety', 'Efficiency', 'Innovation'],
805
+ datasets: [{
806
+ label: 'Product A',
807
+ data: [65, 59, 90, 81, 56, 55],
808
+ fill: true,
809
+ backgroundColor: 'rgba(54, 162, 235, 0.2)',
810
+ borderColor: 'rgb(54, 162, 235)',
811
+ borderWidth: 2,
812
+ pointBackgroundColor: 'rgb(54, 162, 235)',
813
+ pointBorderColor: '#fff',
814
+ pointHoverBackgroundColor: '#fff',
815
+ pointHoverBorderColor: 'rgb(54, 162, 235)',
816
+ }, {
817
+ label: 'Product B',
818
+ data: [28, 48, 40, 95, 86, 27],
819
+ fill: true,
820
+ backgroundColor: 'rgba(255, 99, 132, 0.2)',
821
+ borderColor: 'rgb(255, 99, 132)',
822
+ borderWidth: 2,
823
+ pointBackgroundColor: 'rgb(255, 99, 132)',
824
+ pointBorderColor: '#fff',
825
+ pointHoverBackgroundColor: '#fff',
826
+ pointHoverBorderColor: 'rgb(255, 99, 132)',
827
+ }],
828
+ });
829
+
830
+ // Mixed Chart (Bar + Line)
831
+ this.createLargeChart('mixed-chart', 'bar', {
832
+ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
833
+ datasets: [{
834
+ type: 'bar',
835
+ label: 'Sales',
836
+ data: [12, 19, 3, 5, 2, 3],
837
+ backgroundColor: 'rgba(54, 162, 235, 0.7)',
838
+ borderColor: 'rgb(54, 162, 235)',
839
+ borderWidth: 1,
840
+ }, {
841
+ type: 'line',
842
+ label: 'Revenue',
843
+ data: [18, 25, 8, 15, 12, 18],
844
+ fill: false,
845
+ borderColor: 'rgb(255, 99, 132)',
846
+ backgroundColor: 'rgba(255, 99, 132, 0.2)',
847
+ borderWidth: 3,
848
+ tension: 0.4,
849
+ pointRadius: 5,
850
+ pointHoverRadius: 7,
851
+ }],
852
+ });
853
+
854
+ // Bubble Chart
855
+ this.createLargeChart('bubble-chart', 'bubble', {
856
+ datasets: [{
857
+ label: 'First Dataset',
858
+ data: [
859
+ {x: 20, y: 30, r: 15},
860
+ {x: 40, y: 10, r: 10},
861
+ {x: 30, y: 40, r: 20},
862
+ {x: 50, y: 35, r: 12},
863
+ {x: 10, y: 50, r: 8},
864
+ {x: 60, y: 20, r: 18},
865
+ {x: 25, y: 25, r: 14},
866
+ ],
867
+ backgroundColor: 'rgba(54, 162, 235, 0.6)',
868
+ borderColor: 'rgb(54, 162, 235)',
869
+ borderWidth: 2,
870
+ }, {
871
+ label: 'Second Dataset',
872
+ data: [
873
+ {x: 15, y: 45, r: 12},
874
+ {x: 35, y: 15, r: 16},
875
+ {x: 45, y: 25, r: 9},
876
+ {x: 55, y: 45, r: 14},
877
+ {x: 25, y: 35, r: 11},
878
+ ],
879
+ backgroundColor: 'rgba(255, 99, 132, 0.6)',
880
+ borderColor: 'rgb(255, 99, 132)',
881
+ borderWidth: 2,
882
+ }],
883
+ });
884
+ }
885
+
886
+ /**
887
+ * Create large chart for charts page
888
+ */
889
+ createLargeChart(id, type, data) {
890
+ const canvas = document.getElementById(id);
891
+ if (!canvas) return;
892
+
893
+ const ctx = canvas.getContext('2d');
894
+
895
+ // Define chart-specific options
896
+ const chartOptions = this.getChartOptions(type);
897
+
898
+ const chart = new Chart(ctx, {
899
+ type,
900
+ data,
901
+ options: chartOptions,
902
+ });
903
+
904
+ this.charts.set(id, chart);
905
+ }
906
+
907
+ /**
908
+ * Get chart-specific options based on chart type
909
+ */
910
+ getChartOptions(type) {
911
+ const baseOptions = {
912
+ responsive: true,
913
+ maintainAspectRatio: false,
914
+ plugins: {
915
+ legend: {
916
+ display: true,
917
+ position: 'top',
918
+ labels: {
919
+ padding: 20,
920
+ font: {
921
+ size: 12,
922
+ weight: '600',
923
+ },
924
+ },
925
+ },
926
+ tooltip: {
927
+ enabled: true,
928
+ cornerRadius: 8,
929
+ displayColors: true,
930
+ },
931
+ },
932
+ };
933
+
934
+ // Chart type specific configurations
935
+ switch (type) {
936
+ case 'doughnut':
937
+ case 'pie':
938
+ return {
939
+ ...baseOptions,
940
+ plugins: {
941
+ ...baseOptions.plugins,
942
+ legend: {
943
+ ...baseOptions.plugins.legend,
944
+ position: 'right',
945
+ },
946
+ },
947
+ interaction: {
948
+ intersect: false,
949
+ },
950
+ };
951
+
952
+ case 'polarArea':
953
+ return {
954
+ ...baseOptions,
955
+ scales: {
956
+ r: {
957
+ pointLabels: {
958
+ display: true,
959
+ centerPointLabels: true,
960
+ font: {
961
+ size: 10,
962
+ },
963
+ },
964
+ grid: {
965
+ },
966
+ },
967
+ },
968
+ };
969
+
970
+ case 'radar':
971
+ return {
972
+ ...baseOptions,
973
+ scales: {
974
+ r: {
975
+ angleLines: {
976
+ display: true,
977
+ },
978
+ grid: {
979
+ },
980
+ pointLabels: {
981
+ font: {
982
+ size: 11,
983
+ },
984
+ },
985
+ ticks: {
986
+ display: true,
987
+ font: {
988
+ size: 10,
989
+ },
990
+ },
991
+ },
992
+ },
993
+ };
994
+
995
+ case 'bubble':
996
+ return {
997
+ ...baseOptions,
998
+ scales: {
999
+ x: {
1000
+ type: 'linear',
1001
+ position: 'bottom',
1002
+ grid: {
1003
+ borderDash: [5, 5],
1004
+ },
1005
+ ticks: {
1006
+ font: {
1007
+ size: 11,
1008
+ },
1009
+ },
1010
+ },
1011
+ y: {
1012
+ beginAtZero: true,
1013
+ grid: {
1014
+ borderDash: [5, 5],
1015
+ },
1016
+ ticks: {
1017
+ font: {
1018
+ size: 11,
1019
+ },
1020
+ },
1021
+ },
1022
+ },
1023
+ plugins: {
1024
+ ...baseOptions.plugins,
1025
+ tooltip: {
1026
+ ...baseOptions.plugins.tooltip,
1027
+ callbacks: {
1028
+ label(context) {
1029
+ return `${context.dataset.label}: (${context.parsed.x}, ${context.parsed.y}), Size: ${context.parsed._custom}`;
1030
+ },
1031
+ },
1032
+ },
1033
+ },
1034
+ };
1035
+
1036
+ case 'scatter':
1037
+ return {
1038
+ ...baseOptions,
1039
+ scales: {
1040
+ x: {
1041
+ type: 'linear',
1042
+ position: 'bottom',
1043
+ grid: {
1044
+ borderDash: [5, 5],
1045
+ },
1046
+ ticks: {
1047
+ font: {
1048
+ size: 11,
1049
+ },
1050
+ },
1051
+ },
1052
+ y: {
1053
+ grid: {
1054
+ borderDash: [5, 5],
1055
+ },
1056
+ ticks: {
1057
+ font: {
1058
+ size: 11,
1059
+ },
1060
+ },
1061
+ },
1062
+ },
1063
+ };
1064
+
1065
+ default:
1066
+ // For line, bar, area, mixed charts
1067
+ return {
1068
+ ...baseOptions,
1069
+ scales: {
1070
+ x: {
1071
+ grid: {
1072
+ borderDash: [5, 5],
1073
+ },
1074
+ ticks: {
1075
+ font: {
1076
+ size: 11,
1077
+ },
1078
+ },
1079
+ },
1080
+ y: {
1081
+ beginAtZero: true,
1082
+ grid: {
1083
+ borderDash: [5, 5],
1084
+ },
1085
+ ticks: {
1086
+ font: {
1087
+ size: 11,
1088
+ },
1089
+ },
1090
+ },
1091
+ },
1092
+ };
1093
+ }
1094
+ }
1095
+
1096
+ /**
1097
+ * Create tristate chart (for .sparktri elements)
1098
+ */
1099
+ createTristateChart(element, data, id) {
1100
+ let canvas = element.querySelector('canvas');
1101
+ if (!canvas) {
1102
+ canvas = document.createElement('canvas');
1103
+ canvas.width = 100;
1104
+ canvas.height = 20;
1105
+ canvas.style.width = '100px';
1106
+ canvas.style.height = '20px';
1107
+ element.appendChild(canvas);
1108
+ }
1109
+
1110
+ const ctx = canvas.getContext('2d');
1111
+
1112
+ const chart = new Chart(ctx, {
1113
+ type: 'bar',
1114
+ data: {
1115
+ labels: data.map((_, i) => i),
1116
+ datasets: [{
1117
+ data: data.map(val => Math.abs(val)),
1118
+ backgroundColor: data.map(val => {
1119
+ if (val > 0) return COLORS['light-blue-500'];
1120
+ if (val < 0) return '#f90';
1121
+ return '#000';
1122
+ }),
1123
+ borderColor: data.map(val => {
1124
+ if (val > 0) return COLORS['light-blue-500'];
1125
+ if (val < 0) return '#f90';
1126
+ return '#000';
1127
+ }),
1128
+ borderWidth: 1,
1129
+ barPercentage: 0.8,
1130
+ }],
1131
+ },
1132
+ options: {
1133
+ responsive: false,
1134
+ maintainAspectRatio: false,
1135
+ scales: {
1136
+ x: { display: false },
1137
+ y: { display: false },
1138
+ },
1139
+ plugins: {
1140
+ legend: { display: false },
1141
+ tooltip: {
1142
+ enabled: true,
1143
+ callbacks: {
1144
+ label: (context) => `${context.parsed.y}°Celsius`,
1145
+ },
1146
+ },
1147
+ },
1148
+ },
1149
+ });
1150
+
1151
+ this.charts.set(id, chart);
1152
+ }
1153
+
1154
+ /**
1155
+ * Create discrete chart (for .sparkdisc elements)
1156
+ */
1157
+ createDiscreteChart(element, data, id) {
1158
+ let canvas = element.querySelector('canvas');
1159
+ if (!canvas) {
1160
+ canvas = document.createElement('canvas');
1161
+ canvas.width = 100;
1162
+ canvas.height = 20;
1163
+ canvas.style.width = '100px';
1164
+ canvas.style.height = '20px';
1165
+ element.appendChild(canvas);
1166
+ }
1167
+
1168
+ const ctx = canvas.getContext('2d');
1169
+
1170
+ const chart = new Chart(ctx, {
1171
+ type: 'scatter',
1172
+ data: {
1173
+ datasets: [{
1174
+ data: data.map((val, index) => ({x: index, y: val})),
1175
+ backgroundColor: '#9f0',
1176
+ borderColor: '#9f0',
1177
+ pointRadius: 2,
1178
+ showLine: false,
1179
+ }],
1180
+ },
1181
+ options: {
1182
+ responsive: false,
1183
+ maintainAspectRatio: false,
1184
+ scales: {
1185
+ x: { display: false },
1186
+ y: { display: false },
1187
+ },
1188
+ plugins: {
1189
+ legend: { display: false },
1190
+ tooltip: {
1191
+ enabled: true,
1192
+ callbacks: {
1193
+ label: (context) => `${context.parsed.y}°Celsius`,
1194
+ },
1195
+ },
1196
+ },
1197
+ },
1198
+ });
1199
+
1200
+ this.charts.set(id, chart);
1201
+ }
1202
+
1203
+ /**
1204
+ * Create bullet chart (for .sparkbull elements)
1205
+ */
1206
+ createBulletChart(element, data, id) {
1207
+ let canvas = element.querySelector('canvas');
1208
+ if (!canvas) {
1209
+ canvas = document.createElement('canvas');
1210
+ canvas.width = 100;
1211
+ canvas.height = 20;
1212
+ canvas.style.width = '100px';
1213
+ canvas.style.height = '20px';
1214
+ element.appendChild(canvas);
1215
+ }
1216
+
1217
+ const ctx = canvas.getContext('2d');
1218
+
1219
+ // Simplified bullet chart as horizontal bar
1220
+ const chart = new Chart(ctx, {
1221
+ type: 'bar',
1222
+ data: {
1223
+ labels: [''],
1224
+ datasets: [{
1225
+ data: [Math.max(...data)],
1226
+ backgroundColor: COLORS['amber-500'],
1227
+ borderColor: COLORS['amber-500'],
1228
+ borderWidth: 1,
1229
+ barPercentage: 0.6,
1230
+ }],
1231
+ },
1232
+ options: {
1233
+ responsive: false,
1234
+ maintainAspectRatio: false,
1235
+ indexAxis: 'y',
1236
+ scales: {
1237
+ x: { display: false },
1238
+ y: { display: false },
1239
+ },
1240
+ plugins: {
1241
+ legend: { display: false },
1242
+ tooltip: {
1243
+ enabled: true,
1244
+ callbacks: {
1245
+ label: (context) => `${context.parsed.x}°Celsius`,
1246
+ },
1247
+ },
1248
+ },
1249
+ },
1250
+ });
1251
+
1252
+ this.charts.set(id, chart);
1253
+ }
1254
+
1255
+ /**
1256
+ * Create box chart (for .sparkbox elements)
1257
+ */
1258
+ createBoxChart(element, data, id) {
1259
+ let canvas = element.querySelector('canvas');
1260
+ if (!canvas) {
1261
+ canvas = document.createElement('canvas');
1262
+ canvas.width = 100;
1263
+ canvas.height = 20;
1264
+ canvas.style.width = '100px';
1265
+ canvas.style.height = '20px';
1266
+ element.appendChild(canvas);
1267
+ }
1268
+
1269
+ const ctx = canvas.getContext('2d');
1270
+
1271
+ // Box plot simplified as bar chart showing quartiles
1272
+ const sortedData = [...data].sort((a, b) => a - b);
1273
+ const q1 = sortedData[Math.floor(sortedData.length * 0.25)];
1274
+ const median = sortedData[Math.floor(sortedData.length * 0.5)];
1275
+ const q3 = sortedData[Math.floor(sortedData.length * 0.75)];
1276
+
1277
+ const chart = new Chart(ctx, {
1278
+ type: 'bar',
1279
+ data: {
1280
+ labels: ['Q1', 'Med', 'Q3'],
1281
+ datasets: [{
1282
+ data: [q1, median, q3],
1283
+ backgroundColor: '#9f0',
1284
+ borderColor: '#9f0',
1285
+ borderWidth: 1,
1286
+ barPercentage: 0.8,
1287
+ }],
1288
+ },
1289
+ options: {
1290
+ responsive: false,
1291
+ maintainAspectRatio: false,
1292
+ scales: {
1293
+ x: { display: false },
1294
+ y: { display: false },
1295
+ },
1296
+ plugins: {
1297
+ legend: { display: false },
1298
+ tooltip: {
1299
+ enabled: true,
1300
+ callbacks: {
1301
+ label: (context) => `${context.parsed.y}°Celsius`,
1302
+ },
1303
+ },
1304
+ },
1305
+ },
1306
+ });
1307
+
1308
+ this.charts.set(id, chart);
1309
+ }
1310
+
1311
+ /**
1312
+ * Create Easy Pie Charts (replaces jQuery Easy Pie Chart)
1313
+ */
1314
+ createEasyPieCharts() {
1315
+ const easyPieElements = document.querySelectorAll('.easy-pie-chart');
1316
+
1317
+ easyPieElements.forEach((element, index) => {
1318
+ const size = parseInt(element.dataset.size) || 80;
1319
+ const percent = parseInt(element.dataset.percent) || 0;
1320
+ const barColor = element.dataset.barColor || '#f44336';
1321
+
1322
+ // Create canvas for the pie chart
1323
+ let canvas = element.querySelector('canvas');
1324
+ if (!canvas) {
1325
+ canvas = document.createElement('canvas');
1326
+ canvas.width = size;
1327
+ canvas.height = size;
1328
+ canvas.style.width = `${size}px`;
1329
+ canvas.style.height = `${size}px`;
1330
+ element.appendChild(canvas);
1331
+ }
1332
+
1333
+ // Create percentage display
1334
+ const percentDisplay = element.querySelector('span');
1335
+ if (percentDisplay) {
1336
+ percentDisplay.textContent = `${percent}%`;
1337
+ percentDisplay.style.position = 'absolute';
1338
+ percentDisplay.style.top = '50%';
1339
+ percentDisplay.style.left = '50%';
1340
+ percentDisplay.style.transform = 'translate(-50%, -50%)';
1341
+ percentDisplay.style.fontSize = '14px';
1342
+ percentDisplay.style.fontWeight = 'bold';
1343
+ }
1344
+
1345
+ // Set element position to relative for absolute positioning of text
1346
+ element.style.position = 'relative';
1347
+ element.style.display = 'inline-block';
1348
+
1349
+ const ctx = canvas.getContext('2d');
1350
+
1351
+ const chart = new Chart(ctx, {
1352
+ type: 'doughnut',
1353
+ data: {
1354
+ datasets: [{
1355
+ data: [percent, 100 - percent],
1356
+ backgroundColor: [barColor, '#f0f0f0'],
1357
+ borderWidth: 0,
1358
+ cutout: '70%',
1359
+ }],
1360
+ },
1361
+ options: {
1362
+ responsive: false,
1363
+ maintainAspectRatio: false,
1364
+ plugins: {
1365
+ legend: { display: false },
1366
+ tooltip: { enabled: false },
1367
+ },
1368
+ },
1369
+ });
1370
+
1371
+ this.charts.set(`easy-pie-${index}`, chart);
1372
+ });
1373
+ }
1374
+
1375
+ /**
1376
+ * Destroy all charts
1377
+ */
1378
+ destroy() {
1379
+ this.charts.forEach(chart => {
1380
+ chart.destroy();
1381
+ });
1382
+ this.charts.clear();
1383
+
1384
+ if (this.debounceTimer) {
1385
+ clearTimeout(this.debounceTimer);
1386
+ }
1387
+ }
1388
+ }
1389
+
1390
+ export default ChartComponent;