PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.14.10
Independent Analytics – WordPress Analytics Plugin v2.14.10
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 2 months 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 examiner_controller.js 2 months ago examiner_header_controller.js 11 months ago export_overview_controller.js 9 months ago export_reports_controller.js 2 years ago filters_controller.js 6 months ago group_controller.js 2 years ago import_reports_controller.js 2 years ago journey_controller.js 6 months ago map_controller.js 9 months ago migration_redirect_controller.js 2 years ago modal_controller.js 2 years ago pause_emails_controller.js 6 months ago pie_chart_controller.js 6 months ago plugin_group_options_controller.js 1 year ago pruner_controller.js 5 months ago quick_stats_controller.js 1 year ago real_time_controller.js 6 months ago refresh_overview_controller.js 1 year ago rename_report_controller.js 2 years ago report_controller.js 2 months 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 tooltip_controller.js 6 months ago woocommerce_settings_controller.js 1 year ago
real_time_controller.js
303 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 border: {
234 color: '#DEDAE6',
235 dash: [2, 4]
236 },
237 grid: {
238 tickColor: '#DEDAE6',
239 display: true,
240 drawOnChartArea: true,
241 },
242 beginAtZero: true,
243 suggestedMax: 5,
244 ticks: {
245 color: isDarkMode() ? '#ffffff' : '#6D6A73',
246 precision: 0
247 }
248 },
249 x: {
250 stacked: true,
251 border: {
252 color: '#DEDAE6',
253 },
254 grid: {
255 tickColor: '#DEDAE6',
256 display: true,
257 drawOnChartArea: false,
258 },
259 ticks: {
260 color: isDarkMode() ? '#ffffff' : '#6D6A73',
261 beginAtZero: true,
262 callback: function (value, index, values) {
263 return labelsShort[index];
264 }
265 }
266 }
267 },
268 plugins: {
269 mode: String, // 'light' or 'dark'
270 htmlLegend: {
271 container: element.parentNode.querySelector('.legend')
272 },
273 legend: {
274 display: false
275 },
276 corsair: {
277 dash: [2, 4],
278 color: '#777',
279 width: 1
280 },
281 },
282 },
283 plugins: [
284 corsairPlugin,
285 htmlLegendPlugin
286 ],
287 };
288
289 new Chart(element, config);
290 }
291
292 updateChart({
293 element,
294 views
295 }) {
296 const chart = Chart.getChart(element);
297 chart.data.datasets.forEach((dataset, index) => {
298 dataset.data.splice(0, dataset.data.length, ...views)
299 });
300 chart.update('none');
301 }
302 }
303