PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.11.5
Independent Analytics – WordPress Analytics Plugin v2.11.5
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / javascript-source / controllers / real_time_controller.js
independent-analytics / javascript-source / controllers Last commit date
overview 1 year ago campaign_builder_controller.js 1 year ago chart_controller.js 1 year 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 1 year ago delete_data_controller.js 1 year ago delete_report_controller.js 2 years ago easepick_controller.js 2 years ago export_overview_controller.js 1 year 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 map_controller.js 1 year ago migration_redirect_controller.js 2 years ago modal_controller.js 2 years ago pie_chart_controller.js 1 year ago plugin_group_options_controller.js 1 year ago pruner_controller.js 1 year ago quick_stats_controller.js 1 year ago real_time_controller.js 1 year ago refresh_overview_controller.js 1 year ago rename_report_controller.js 2 years ago report_controller.js 1 year ago reset_analytics_controller.js 1 year ago reset_overview_controller.js 1 year 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
298 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 import {isDarkMode} from "../utils/appearance";
7
8 Chart.register(...registerables);
9 Chart.defaults.font.family = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';
10
11 export default class extends Controller {
12 static targets = [
13 'minuteChart',
14 'secondChart',
15 'visitorMessage',
16 'pageMessage',
17 'referrerMessage',
18 'countryMessage',
19 'pagesList',
20 'referrersList',
21 'countriesList',
22 'campaignsList',
23 'device_typesList'
24 ]
25 static values = {
26 chartData: Object,
27 nonce: String,
28 visible: {
29 type: Boolean,
30 default: true
31 }
32 }
33
34 connect() {
35 document.addEventListener('visibilitychange', this.tabVisibilityChanged)
36 this.initializeChart({
37 element: this.minuteChartTarget,
38 views: this.chartDataValue['minute_interval_views'],
39 labelsShort: this.chartDataValue['minute_interval_labels_short'],
40 labelsFull: this.chartDataValue['minute_interval_labels_full']
41 })
42 this.initializeChart({
43 element: this.secondChartTarget,
44 views: this.chartDataValue['second_interval_views'],
45 labelsShort: this.chartDataValue['second_interval_labels_short'],
46 labelsFull: this.chartDataValue['second_interval_labels_full']
47 })
48 this.startServerPolling()
49 }
50
51 disconnect() {
52 document.removeEventListener('visibilitychange', this.tabVisibilityChanged)
53 }
54
55 tabVisibilityChanged = () => {
56 this.visibleValue = !document.hidden
57
58 if (this.visibleValue) {
59 this.refresh()
60 this.startServerPolling()
61 }
62 }
63
64 startServerPolling() {
65 clearInterval(this.interval)
66 this.interval = setInterval(() => {
67 if (this.visibleValue) {
68 this.refresh()
69 } else {
70 clearInterval(this.interval)
71 }
72 }, 10000)
73 }
74
75 refresh() {
76 const data = {
77 ...iawpActions.real_time_data
78 };
79
80 jQuery.post(ajaxurl, data, (response, a, b) => {
81 document.getElementById('real-time-dashboard').classList.remove('refreshed')
82 void document.getElementById('real-time-dashboard').offsetWidth
83 document.getElementById('real-time-dashboard').classList.add('refreshed')
84 if (response.success) {
85 this.rerender(response.data)
86 }
87 });
88 }
89
90 rerender(data) {
91 this.visitorMessageTarget.textContent = data.visitor_message
92 this.pageMessageTarget.textContent = data.page_message
93 this.referrerMessageTarget.textContent = data.referrer_message
94 this.countryMessageTarget.textContent = data.country_message
95 this.updateChart({
96 element: this.minuteChartTarget,
97 visitors: data.chart_data.minute_interval_visitors,
98 views: data.chart_data.minute_interval_views,
99 })
100 this.updateChart({
101 element: this.secondChartTarget,
102 visitors: data.chart_data.second_interval_visitors,
103 views: data.chart_data.second_interval_views
104 })
105 this.updateList({
106 element: this.pagesListTarget,
107 entries: data.lists.pages.entries
108 })
109 this.updateList({
110 element: this.referrersListTarget,
111 entries: data.lists.referrers.entries
112 })
113 this.updateList({
114 element: this.countriesListTarget,
115 entries: data.lists.countries.entries
116 })
117 this.updateList({
118 element: this.campaignsListTarget,
119 entries: data.lists.campaigns.entries
120 })
121 this.updateList({
122 element: this.device_typesListTarget,
123 entries: data.lists.device_types.entries
124 })
125 }
126
127 existingElements() {
128 return Array.from(this.element.querySelectorAll('li:not(.exiting)'))
129 }
130
131 existingIds() {
132 return this.existingElements().map((existingElement) => existingElement.dataset.id)
133 }
134
135 updateList({
136 element,
137 entries
138 }) {
139 let iso = element.iso
140
141 if (!iso) {
142 iso = element.iso = new Isotope(element, {
143 itemSelector: "li",
144 layoutMode: "vertical",
145 sortColumn: "position",
146 getSortData: {
147 position: (element) => {
148 return parseInt(element.dataset.position);
149 }
150 }
151 })
152 }
153
154 // Remove existing elements
155 this.existingElements().forEach((existingElement) => {
156 iso.remove(existingElement)
157 })
158
159 // Add new elements
160 entries.forEach((entry, index) => {
161 const entryElement = this.elementFromEntry(entry)
162 iso.insert(entryElement)
163 })
164
165 iso.arrange()
166
167 const totalElements = iso.items.length
168 const emptyMessage = element.parentNode.querySelector('.most-popular-empty-message')
169
170 if (totalElements > 0) {
171 emptyMessage.classList.add('hide')
172 } else {
173 emptyMessage.classList.remove('hide')
174 }
175 }
176
177 elementFromEntry(entry) {
178 const id = entry['id']
179 const position = entry['position']
180 const title = entry['title']
181 const subtitle = entry['subtitle']
182 const views = entry['views']
183 const flag = entry['flag'] ? entry['flag'] : ''
184 const subtitleHTML = subtitle ? `<span class="real-time-subtitle">${subtitle}</span>` : '';
185
186 const li = `
187 <li data-id="${id}" data-position="${position}">
188 <span class="real-time-position">${position}.</span>
189 ${flag}
190 <span class="real-time-resource">${title} ${subtitleHTML}</span>
191 <span class="real-time-stat">${views}</span>
192 </li>
193 `
194 const el = document.createElement('div');
195 el.innerHTML = li;
196 return el.firstElementChild;
197 }
198
199 initializeChart({
200 element,
201 views,
202 labelsShort,
203 labelsFull
204 }) {
205 const data = {
206 labels: labelsFull,
207 datasets: [{
208 id: 'views',
209 label: iawpText.views,
210 data: views,
211 backgroundColor: 'rgba(108,70,174,0.2)',
212 borderColor: 'rgba(108,70,174,1)',
213 borderWidth: {
214 bottom: 0,
215 top: 3,
216 left: 0,
217 right: 0
218 }
219 },]
220 }
221
222 const config = {
223 type: 'bar',
224 data,
225 options: {
226 interaction: {
227 intersect: false,
228 mode: 'index'
229 },
230 responsive: true,
231 scales: {
232 y: {
233 grid: {
234 borderColor: '#DEDAE6',
235 tickColor: '#DEDAE6',
236 display: true,
237 drawOnChartArea: true,
238 borderDash: [2, 4]
239 },
240 beginAtZero: true,
241 suggestedMax: 5,
242 ticks: {
243 color: isDarkMode() ? '#ffffff' : '#6D6A73',
244 precision: 0
245 }
246 },
247 x: {
248 stacked: true,
249 grid: {
250 borderColor: '#DEDAE6',
251 tickColor: '#DEDAE6',
252 display: true,
253 drawOnChartArea: false,
254 },
255 ticks: {
256 color: isDarkMode() ? '#ffffff' : '#6D6A73',
257 beginAtZero: true,
258 callback: function (value, index, values) {
259 return labelsShort[index];
260 }
261 }
262 }
263 },
264 plugins: {
265 mode: String, // 'light' or 'dark'
266 htmlLegend: {
267 container: element.parentNode.querySelector('.legend')
268 },
269 legend: {
270 display: false
271 },
272 corsair: {
273 dash: [2, 4],
274 color: '#777',
275 width: 1
276 },
277 },
278 },
279 plugins: [
280 corsairPlugin,
281 htmlLegendPlugin
282 ],
283 };
284
285 new Chart(element, config);
286 }
287
288 updateChart({
289 element,
290 views
291 }) {
292 const chart = Chart.getChart(element);
293 chart.data.datasets.forEach((dataset, index) => {
294 dataset.data.splice(0, dataset.data.length, ...views)
295 });
296 chart.update('none');
297 }
298 }