campaign_builder_controller.js
1 year ago
chart_controller.js
1 year ago
chart_geo_controller.js
2 years ago
chart_interval_controller.js
2 years ago
clipboard_controller.js
1 year ago
copy_report_controller.js
2 years ago
create_report_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
1 year 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
1 year ago
pruner_controller.js
1 year ago
quick_stats_controller.js
2 years ago
real_time_controller.js
1 year ago
rename_report_controller.js
2 years ago
report_controller.js
1 year 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
woocommerce_settings_controller.js
1 year ago
real_time_controller.js
297 lines
| 1 | import {Controller} from "@hotwired/stimulus" |
| 2 | import {Chart, registerables} from 'chart.js' |
| 3 | import Isotope from "isotope-layout" |
| 4 | import htmlLegendPlugin from "../chart_plugins/html_legend_plugin"; |
| 5 | import corsairPlugin from "../chart_plugins/corsair_plugin"; |
| 6 | |
| 7 | Chart.register(...registerables); |
| 8 | Chart.defaults.font.family = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"'; |
| 9 | |
| 10 | export default class extends Controller { |
| 11 | static targets = [ |
| 12 | 'minuteChart', |
| 13 | 'secondChart', |
| 14 | 'visitorMessage', |
| 15 | 'pageMessage', |
| 16 | 'referrerMessage', |
| 17 | 'countryMessage', |
| 18 | 'pagesList', |
| 19 | 'referrersList', |
| 20 | 'countriesList', |
| 21 | 'campaignsList', |
| 22 | 'device_typesList' |
| 23 | ] |
| 24 | static values = { |
| 25 | chartData: Object, |
| 26 | nonce: String, |
| 27 | visible: { |
| 28 | type: Boolean, |
| 29 | default: true |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | connect() { |
| 34 | document.addEventListener('visibilitychange', this.tabVisibilityChanged) |
| 35 | this.initializeChart({ |
| 36 | element: this.minuteChartTarget, |
| 37 | views: this.chartDataValue['minute_interval_views'], |
| 38 | labelsShort: this.chartDataValue['minute_interval_labels_short'], |
| 39 | labelsFull: this.chartDataValue['minute_interval_labels_full'] |
| 40 | }) |
| 41 | this.initializeChart({ |
| 42 | element: this.secondChartTarget, |
| 43 | views: this.chartDataValue['second_interval_views'], |
| 44 | labelsShort: this.chartDataValue['second_interval_labels_short'], |
| 45 | labelsFull: this.chartDataValue['second_interval_labels_full'] |
| 46 | }) |
| 47 | this.startServerPolling() |
| 48 | } |
| 49 | |
| 50 | disconnect() { |
| 51 | document.removeEventListener('visibilitychange', this.tabVisibilityChanged) |
| 52 | } |
| 53 | |
| 54 | tabVisibilityChanged = () => { |
| 55 | this.visibleValue = !document.hidden |
| 56 | |
| 57 | if (this.visibleValue) { |
| 58 | this.refresh() |
| 59 | this.startServerPolling() |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | startServerPolling() { |
| 64 | clearInterval(this.interval) |
| 65 | this.interval = setInterval(() => { |
| 66 | if (this.visibleValue) { |
| 67 | this.refresh() |
| 68 | } else { |
| 69 | clearInterval(this.interval) |
| 70 | } |
| 71 | }, 10000) |
| 72 | } |
| 73 | |
| 74 | refresh() { |
| 75 | const data = { |
| 76 | ...iawpActions.real_time_data |
| 77 | }; |
| 78 | |
| 79 | jQuery.post(ajaxurl, data, (response, a, b) => { |
| 80 | document.getElementById('real-time-dashboard').classList.remove('refreshed') |
| 81 | void document.getElementById('real-time-dashboard').offsetWidth |
| 82 | document.getElementById('real-time-dashboard').classList.add('refreshed') |
| 83 | if (response.success) { |
| 84 | this.rerender(response.data) |
| 85 | } |
| 86 | }); |
| 87 | } |
| 88 | |
| 89 | rerender(data) { |
| 90 | this.visitorMessageTarget.textContent = data.visitor_message |
| 91 | this.pageMessageTarget.textContent = data.page_message |
| 92 | this.referrerMessageTarget.textContent = data.referrer_message |
| 93 | this.countryMessageTarget.textContent = data.country_message |
| 94 | this.updateChart({ |
| 95 | element: this.minuteChartTarget, |
| 96 | visitors: data.chart_data.minute_interval_visitors, |
| 97 | views: data.chart_data.minute_interval_views, |
| 98 | }) |
| 99 | this.updateChart({ |
| 100 | element: this.secondChartTarget, |
| 101 | visitors: data.chart_data.second_interval_visitors, |
| 102 | views: data.chart_data.second_interval_views |
| 103 | }) |
| 104 | this.updateList({ |
| 105 | element: this.pagesListTarget, |
| 106 | entries: data.lists.pages.entries |
| 107 | }) |
| 108 | this.updateList({ |
| 109 | element: this.referrersListTarget, |
| 110 | entries: data.lists.referrers.entries |
| 111 | }) |
| 112 | this.updateList({ |
| 113 | element: this.countriesListTarget, |
| 114 | entries: data.lists.countries.entries |
| 115 | }) |
| 116 | this.updateList({ |
| 117 | element: this.campaignsListTarget, |
| 118 | entries: data.lists.campaigns.entries |
| 119 | }) |
| 120 | this.updateList({ |
| 121 | element: this.device_typesListTarget, |
| 122 | entries: data.lists.device_types.entries |
| 123 | }) |
| 124 | } |
| 125 | |
| 126 | existingElements() { |
| 127 | return Array.from(this.element.querySelectorAll('li:not(.exiting)')) |
| 128 | } |
| 129 | |
| 130 | existingIds() { |
| 131 | return this.existingElements().map((existingElement) => existingElement.dataset.id) |
| 132 | } |
| 133 | |
| 134 | updateList({ |
| 135 | element, |
| 136 | entries |
| 137 | }) { |
| 138 | let iso = element.iso |
| 139 | |
| 140 | if (!iso) { |
| 141 | iso = element.iso = new Isotope(element, { |
| 142 | itemSelector: "li", |
| 143 | layoutMode: "vertical", |
| 144 | sortColumn: "position", |
| 145 | getSortData: { |
| 146 | position: (element) => { |
| 147 | return parseInt(element.dataset.position); |
| 148 | } |
| 149 | } |
| 150 | }) |
| 151 | } |
| 152 | |
| 153 | // Remove existing elements |
| 154 | this.existingElements().forEach((existingElement) => { |
| 155 | iso.remove(existingElement) |
| 156 | }) |
| 157 | |
| 158 | // Add new elements |
| 159 | entries.forEach((entry, index) => { |
| 160 | const entryElement = this.elementFromEntry(entry) |
| 161 | iso.insert(entryElement) |
| 162 | }) |
| 163 | |
| 164 | iso.arrange() |
| 165 | |
| 166 | const totalElements = iso.items.length |
| 167 | const emptyMessage = element.parentNode.querySelector('.most-popular-empty-message') |
| 168 | |
| 169 | if (totalElements > 0) { |
| 170 | emptyMessage.classList.add('hide') |
| 171 | } else { |
| 172 | emptyMessage.classList.remove('hide') |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | elementFromEntry(entry) { |
| 177 | const id = entry['id'] |
| 178 | const position = entry['position'] |
| 179 | const title = entry['title'] |
| 180 | const subtitle = entry['subtitle'] |
| 181 | const views = entry['views'] |
| 182 | const flag = entry['flag'] ? entry['flag'] : '' |
| 183 | const subtitleHTML = subtitle ? `<span class="real-time-subtitle">${subtitle}</span>` : ''; |
| 184 | |
| 185 | const li = ` |
| 186 | <li data-id="${id}" data-position="${position}"> |
| 187 | <span class="real-time-position">${position}.</span> |
| 188 | ${flag} |
| 189 | <span class="real-time-resource">${title} ${subtitleHTML}</span> |
| 190 | <span class="real-time-stat">${views}</span> |
| 191 | </li> |
| 192 | ` |
| 193 | const el = document.createElement('div'); |
| 194 | el.innerHTML = li; |
| 195 | return el.firstElementChild; |
| 196 | } |
| 197 | |
| 198 | initializeChart({ |
| 199 | element, |
| 200 | views, |
| 201 | labelsShort, |
| 202 | labelsFull |
| 203 | }) { |
| 204 | const data = { |
| 205 | labels: labelsFull, |
| 206 | datasets: [{ |
| 207 | id: 'views', |
| 208 | label: iawpText.views, |
| 209 | data: views, |
| 210 | backgroundColor: 'rgba(108,70,174,0.2)', |
| 211 | borderColor: 'rgba(108,70,174,1)', |
| 212 | borderWidth: { |
| 213 | bottom: 0, |
| 214 | top: 3, |
| 215 | left: 0, |
| 216 | right: 0 |
| 217 | } |
| 218 | },] |
| 219 | } |
| 220 | |
| 221 | const config = { |
| 222 | type: 'bar', |
| 223 | data, |
| 224 | options: { |
| 225 | interaction: { |
| 226 | intersect: false, |
| 227 | mode: 'index' |
| 228 | }, |
| 229 | responsive: true, |
| 230 | scales: { |
| 231 | y: { |
| 232 | grid: { |
| 233 | borderColor: '#DEDAE6', |
| 234 | tickColor: '#DEDAE6', |
| 235 | display: true, |
| 236 | drawOnChartArea: true, |
| 237 | borderDash: [2, 4] |
| 238 | }, |
| 239 | beginAtZero: true, |
| 240 | suggestedMax: 5, |
| 241 | ticks: { |
| 242 | color: document.body.classList.contains('iawp-dark-mode') ? '#ffffff' : '#6D6A73', |
| 243 | precision: 0 |
| 244 | } |
| 245 | }, |
| 246 | x: { |
| 247 | stacked: true, |
| 248 | grid: { |
| 249 | borderColor: '#DEDAE6', |
| 250 | tickColor: '#DEDAE6', |
| 251 | display: true, |
| 252 | drawOnChartArea: false, |
| 253 | }, |
| 254 | ticks: { |
| 255 | color: document.body.classList.contains('iawp-dark-mode') ? '#ffffff' : '#6D6A73', |
| 256 | beginAtZero: true, |
| 257 | callback: function (value, index, values) { |
| 258 | return labelsShort[index]; |
| 259 | } |
| 260 | } |
| 261 | } |
| 262 | }, |
| 263 | plugins: { |
| 264 | mode: String, // 'light' or 'dark' |
| 265 | htmlLegend: { |
| 266 | container: element.parentNode.querySelector('.legend') |
| 267 | }, |
| 268 | legend: { |
| 269 | display: false |
| 270 | }, |
| 271 | corsair: { |
| 272 | dash: [2, 4], |
| 273 | color: '#777', |
| 274 | width: 1 |
| 275 | }, |
| 276 | }, |
| 277 | }, |
| 278 | plugins: [ |
| 279 | corsairPlugin, |
| 280 | htmlLegendPlugin |
| 281 | ], |
| 282 | }; |
| 283 | |
| 284 | new Chart(element, config); |
| 285 | } |
| 286 | |
| 287 | updateChart({ |
| 288 | element, |
| 289 | views |
| 290 | }) { |
| 291 | const chart = Chart.getChart(element); |
| 292 | chart.data.datasets.forEach((dataset, index) => { |
| 293 | dataset.data.splice(0, dataset.data.length, ...views) |
| 294 | }); |
| 295 | chart.update('none'); |
| 296 | } |
| 297 | } |