campaign_builder_controller.js
2 years ago
chart_controller.js
2 years ago
chart_geo_controller.js
2 years ago
chart_interval_controller.js
2 years ago
clipboard_controller.js
2 years ago
copy_report_controller.js
2 years ago
create_report_controller.js
2 years ago
dates_controller.js
2 years ago
delete_data_controller.js
2 years ago
delete_report_controller.js
2 years ago
easepick_controller.js
2 years ago
export_reports_controller.js
2 years ago
filters_controller.js
2 years ago
group_controller.js
2 years ago
import_reports_controller.js
2 years ago
migration_redirect_controller.js
2 years ago
modal_controller.js
2 years ago
plugin_group_options_controller.js
2 years ago
quick_stats_controller.js
2 years ago
real_time_controller.js
2 years ago
rename_report_controller.js
2 years ago
report_controller.js
2 years ago
reset_analytics_controller.js
2 years ago
save_report_controller.js
2 years ago
select_input_controller.js
2 years ago
set_favorite_report_controller.js
2 years ago
sort_controller.js
2 years ago
sortable_reports_controller.js
2 years ago
table_columns_controller.js
2 years ago
chart_controller.js
345 lines
| 1 | import {Controller} from "@hotwired/stimulus" |
| 2 | import corsairPlugin from '../chart_plugins/corsair_plugin' |
| 3 | import htmlLegendPlugin from '../chart_plugins/html_legend_plugin' |
| 4 | import {Chart, registerables} from 'chart.js'; |
| 5 | |
| 6 | Chart.register(...registerables); |
| 7 | |
| 8 | export default class extends Controller { |
| 9 | static values = { |
| 10 | locale: String, |
| 11 | currency: { |
| 12 | type: String, |
| 13 | default: 'USD' |
| 14 | }, |
| 15 | preview: Boolean, |
| 16 | usingWooCommerce: Boolean, |
| 17 | labels: Array, |
| 18 | views: Array, |
| 19 | visitors: Array, |
| 20 | sessions: Array, |
| 21 | woocommerceOrders: Array, |
| 22 | woocommerceNetSales: Array, |
| 23 | visibleDatasets: Array |
| 24 | } |
| 25 | |
| 26 | get locale() { |
| 27 | try { |
| 28 | new Intl.NumberFormat(this.localeValue) |
| 29 | return this.localeValue |
| 30 | } catch (e) { |
| 31 | return 'en-US' |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | isPreview() { |
| 36 | return this.previewValue === true |
| 37 | } |
| 38 | |
| 39 | isUsingWooCommerce() { |
| 40 | return this.usingWooCommerceValue === true |
| 41 | } |
| 42 | |
| 43 | formatCurrency(value) { |
| 44 | return new Intl.NumberFormat(this.localeValue, { |
| 45 | style: 'currency', |
| 46 | currency: this.currencyValue, |
| 47 | minimumFractionDigits: 0, |
| 48 | maximumFractionDigits: 0, |
| 49 | }).format(value); |
| 50 | } |
| 51 | |
| 52 | tooltipTitle(tooltip) { |
| 53 | const label = JSON.parse(tooltip[0].label) |
| 54 | |
| 55 | return label.tooltipLabel |
| 56 | } |
| 57 | |
| 58 | tooltipLabel(tooltip) { |
| 59 | if (typeof tooltip.dataset.tooltipLabel === 'function') { |
| 60 | return tooltip.dataset.tooltipLabel(tooltip) |
| 61 | } |
| 62 | |
| 63 | return tooltip.dataset.label + ': ' + tooltip.formattedValue |
| 64 | } |
| 65 | |
| 66 | tickText(value) { |
| 67 | const label = JSON.parse(this.getLabelForValue(value)) |
| 68 | |
| 69 | return label.tick |
| 70 | } |
| 71 | |
| 72 | currencyTickText = (value) => { |
| 73 | return this.formatCurrency(value) |
| 74 | } |
| 75 | |
| 76 | getVisitorsDataset() { |
| 77 | return { |
| 78 | id: 'visitors', |
| 79 | label: iawpText.visitors, |
| 80 | data: this.visitorsValue, |
| 81 | borderColor: 'rgba(246,157,10,1)', |
| 82 | fill: true, |
| 83 | backgroundColor: 'rgba(246,157,10,0.2)', |
| 84 | pointBackgroundColor: 'rgba(246,157,10,1)', |
| 85 | tension: 0.4, |
| 86 | yAxisID: 'y', |
| 87 | hidden: !this.visibleDatasetsValue.includes('visitors') |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | getViewsDataset() { |
| 92 | return { |
| 93 | id: 'views', |
| 94 | label: iawpText.views, |
| 95 | data: this.viewsValue, |
| 96 | borderColor: 'rgba(108,70,174,1)', |
| 97 | fill: true, |
| 98 | backgroundColor: 'rgba(108,70,174,0.2)', |
| 99 | pointBackgroundColor: 'rgba(108,70,174,1)', |
| 100 | tension: 0.4, |
| 101 | yAxisID: 'y', |
| 102 | hidden: !this.visibleDatasetsValue.includes('views') |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | getSessionsDataset() { |
| 107 | if (this.isPreview()) { |
| 108 | return null; |
| 109 | } |
| 110 | |
| 111 | return { |
| 112 | id: 'sessions', |
| 113 | label: iawpText.sessions, |
| 114 | data: this.sessionsValue, |
| 115 | borderColor: 'rgba(217, 59, 41, 1)', |
| 116 | fill: true, |
| 117 | backgroundColor: 'rgba(217, 59, 41, 0.2)', |
| 118 | pointBackgroundColor: 'rgba(217, 59, 41, 1)', |
| 119 | tension: 0.4, |
| 120 | yAxisID: 'y', |
| 121 | hidden: !this.visibleDatasetsValue.includes('sessions') |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | getOrdersDataset() { |
| 126 | if (this.isPreview() || !this.isUsingWooCommerce()) { |
| 127 | return null; |
| 128 | } |
| 129 | |
| 130 | return { |
| 131 | id: 'orders', |
| 132 | label: iawpText.orders, |
| 133 | data: this.woocommerceOrdersValue, |
| 134 | borderColor: 'rgba(35, 125, 68, 1)', |
| 135 | fill: true, |
| 136 | backgroundColor: 'rgba(35, 125, 68, .2)', |
| 137 | pointBackgroundColor: 'rgba(35, 125, 68, 1)', |
| 138 | tension: 0.4, |
| 139 | yAxisID: 'y1', |
| 140 | hidden: !this.visibleDatasetsValue.includes('orders') |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | getNetSalesDataset() { |
| 145 | if (this.isPreview() || !this.isUsingWooCommerce()) { |
| 146 | return null; |
| 147 | } |
| 148 | |
| 149 | return { |
| 150 | id: 'net-sales', |
| 151 | label: iawpText.netSales, |
| 152 | data: this.woocommerceNetSalesValue, |
| 153 | borderColor: 'rgba(52, 152, 219, 1)', |
| 154 | fill: true, |
| 155 | backgroundColor: 'rgba(52, 152, 219, 0.2)', |
| 156 | pointBackgroundColor: 'rgba(52, 152, 219, 1)', |
| 157 | tension: 0.4, |
| 158 | yAxisID: 'y2', |
| 159 | tooltipLabel: (tooltip) => { |
| 160 | return tooltip.dataset.label + ': ' + this.formatCurrency(tooltip.raw) |
| 161 | }, |
| 162 | hidden: !this.visibleDatasetsValue.includes('net-sales') |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | connect() { |
| 167 | Chart.defaults.font.family = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"'; |
| 168 | const element = document.getElementById('myChart'); |
| 169 | const labels = this.labelsValue |
| 170 | |
| 171 | const data = { |
| 172 | labels: labels, |
| 173 | datasets: ([ |
| 174 | this.getVisitorsDataset(), |
| 175 | this.getViewsDataset(), |
| 176 | this.getSessionsDataset(), |
| 177 | this.getOrdersDataset(), |
| 178 | this.getNetSalesDataset() |
| 179 | ]).filter((dataset) => dataset !== null) |
| 180 | }; |
| 181 | |
| 182 | const options = { |
| 183 | locale: this.locale, |
| 184 | animation: { |
| 185 | duration: 0 |
| 186 | }, |
| 187 | interaction: { |
| 188 | intersect: false, |
| 189 | mode: 'index' |
| 190 | }, |
| 191 | scales: { |
| 192 | y: { |
| 193 | title: { |
| 194 | text: `${iawpText.visitors} / ${iawpText.views} / ${iawpText.sessions}`, |
| 195 | display: this.previewValue ? false : true |
| 196 | }, |
| 197 | grid: { |
| 198 | borderColor: '#DEDAE6', |
| 199 | tickColor: '#DEDAE6', |
| 200 | display: true, |
| 201 | drawOnChartArea: true, |
| 202 | borderDash: [2, 4] |
| 203 | }, |
| 204 | beginAtZero: true, |
| 205 | suggestedMax: 10, |
| 206 | // grace: '26%', |
| 207 | ticks: { |
| 208 | color: document.body.classList.contains('iawp-dark-mode') ? '#ffffff' : '#6D6A73', |
| 209 | font: { |
| 210 | size: 14, |
| 211 | weight: 400, |
| 212 | }, |
| 213 | precision: 0 |
| 214 | }, |
| 215 | }, |
| 216 | y1: { |
| 217 | |
| 218 | title: { |
| 219 | text: iawpText.orders, |
| 220 | display: true, |
| 221 | color: 'rgba(35, 125, 68, 1)', |
| 222 | }, |
| 223 | position: 'right', |
| 224 | display: 'auto', |
| 225 | grid: { |
| 226 | borderColor: 'rgba(35, 125, 68, 1)', |
| 227 | tickColor: 'rgba(35, 125, 68, 1)', |
| 228 | display: false, |
| 229 | drawOnChartArea: false, |
| 230 | borderDash: [2, 4] |
| 231 | }, |
| 232 | beginAtZero: true, |
| 233 | suggestedMax: 10, |
| 234 | // grace: '26%', |
| 235 | ticks: { |
| 236 | // color: document.body.classList.contains('iawp-dark-mode') ? '#ffffff' : '#6D6A73', |
| 237 | color: 'rgba(35, 125, 68, 1)', |
| 238 | font: { |
| 239 | size: 14, |
| 240 | weight: 400, |
| 241 | }, |
| 242 | precision: 0, |
| 243 | }, |
| 244 | }, |
| 245 | y2: { |
| 246 | title: { |
| 247 | text: iawpText.netSales, |
| 248 | display: true, |
| 249 | color: 'rgba(52, 152, 219, 1)', |
| 250 | }, |
| 251 | position: 'right', |
| 252 | display: 'auto', |
| 253 | grid: { |
| 254 | borderColor: 'rgba(52, 152, 219, 1)', |
| 255 | tickColor: 'rgba(52, 152, 219, 1)', |
| 256 | display: false, |
| 257 | drawOnChartArea: false, |
| 258 | borderDash: [2, 4] |
| 259 | }, |
| 260 | beginAtZero: true, |
| 261 | suggestedMax: 10, |
| 262 | // grace: '26%', |
| 263 | ticks: { |
| 264 | // color: document.body.classList.contains('iawp-dark-mode') ? '#ffffff' : '#6D6A73', |
| 265 | color: 'rgba(52, 152, 219, 1)', |
| 266 | font: { |
| 267 | size: 14, |
| 268 | weight: 400, |
| 269 | }, |
| 270 | precision: 0, |
| 271 | callback: this.currencyTickText |
| 272 | }, |
| 273 | }, |
| 274 | x: { |
| 275 | grid: { |
| 276 | borderColor: '#DEDAE6', |
| 277 | tickColor: '#DEDAE6', |
| 278 | display: true, |
| 279 | drawOnChartArea: false, |
| 280 | }, |
| 281 | ticks: { |
| 282 | color: document.body.classList.contains('iawp-dark-mode') ? '#ffffff' : '#6D6A73', |
| 283 | autoSkip: true, |
| 284 | autoSkipPadding: 16, |
| 285 | maxRotation: 0, |
| 286 | // maxTicksLimit: 20, |
| 287 | font: { |
| 288 | size: 14, |
| 289 | weight: 400 |
| 290 | }, |
| 291 | callback: this.tickText |
| 292 | }, |
| 293 | }, |
| 294 | }, |
| 295 | plugins: { |
| 296 | mode: String, // 'light' or 'dark' |
| 297 | htmlLegend: { |
| 298 | container: element.parentNode.querySelector('.legend'), |
| 299 | callback: function (visibleDatasets) { |
| 300 | // Todo - Actually track visible datasets |
| 301 | document.dispatchEvent( |
| 302 | new CustomEvent('iawp:changeVisibleDatasets', { |
| 303 | detail: { |
| 304 | visibleDatasets: visibleDatasets |
| 305 | } |
| 306 | }) |
| 307 | ) |
| 308 | } |
| 309 | }, |
| 310 | legend: { |
| 311 | display: false |
| 312 | }, |
| 313 | corsair: { |
| 314 | dash: [2, 4], |
| 315 | color: '#777', |
| 316 | width: 1 |
| 317 | }, |
| 318 | tooltip: { |
| 319 | callbacks: { |
| 320 | title: this.tooltipTitle, |
| 321 | label: this.tooltipLabel |
| 322 | } |
| 323 | } |
| 324 | }, |
| 325 | elements: { |
| 326 | point: { |
| 327 | radius: 4 |
| 328 | } |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | const config = { |
| 333 | type: 'line', |
| 334 | data: data, |
| 335 | options: options, |
| 336 | plugins: [ |
| 337 | htmlLegendPlugin, |
| 338 | corsairPlugin |
| 339 | |
| 340 | ], |
| 341 | }; |
| 342 | |
| 343 | window.iawp_chart = new Chart(element, config); |
| 344 | } |
| 345 | } |