PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.0.4
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.0.4
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
acymailing / back / Helpers / global / chart.php

chart.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 11.0.4, at back/Helpers/global/chart.php

701 lines 25.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined('ABSPATH') || die('Restricted Access');
3
4 function acym_lineChart(array $dataMonth, array $dataDay, array $dataHour, bool $ajax = false): void
5 {
6 acym_initializeChart();
7
8 $month = [];
9 $openMonth = [];
10 $clickMonth = [];
11
12 foreach ($dataMonth as $key => $data) {
13 $month[] = $key;
14 $openMonth[] = $data['open'];
15 $clickMonth[] = $data['click'];
16 }
17
18 $day = [];
19 $openDay = [];
20 $clickDay = [];
21
22 foreach ($dataDay as $key => $data) {
23 $day[] = $key;
24 $openDay[] = $data['open'];
25 $clickDay[] = $data['click'];
26 }
27
28 $hour = [];
29 $openHour = [];
30 $clickHour = [];
31
32 foreach ($dataHour as $key => $data) {
33 $hour[] = $key;
34 $openHour[] = $data['open'];
35 $clickHour[] = $data['click'];
36 }
37
38 $randNumber = acym_rand(1000, 9000);
39 $idCanvas = 'acy_canvas_rand_id'.$randNumber;
40 $idLegend = 'acy_legend_rand_id'.$randNumber;
41
42 $nbDataDay = count($dataDay);
43 $nbDataHour = count($dataHour);
44 $selectedChartHour = "";
45 $selectedChartDay = "";
46 $selectedChartMonth = "";
47
48 if ($nbDataHour < 49) {
49 $selectedChartHour = "selected__choose_by";
50 $displayed = $hour;
51 $clickDisplayed = $clickHour;
52 $openDisplayed = $openHour;
53 } elseif ($nbDataDay < 63) {
54 $selectedChartDay = "selected__choose_by";
55 $displayed = $day;
56 $clickDisplayed = $clickDay;
57 $openDisplayed = $openDay;
58 } else {
59 $selectedChartMonth = "selected__choose_by";
60 $displayed = $month;
61 $clickDisplayed = $clickMonth;
62 $openDisplayed = $openMonth;
63 }
64 ?>
65
66 <div class="acym__chart__line__container">
67 <div class="acym__chart__line__choose__by">
68 <p class="acym__chart__line__choose__by__one <?php echo esc_attr($selectedChartMonth); ?>" onclick="acymChartLineUpdate(this, 'month')">
69 <?php echo esc_html(acym_translation('ACYM_BY_MONTH')); ?>
70 </p>
71 <p class="acym__chart__line__choose__by__one <?php echo esc_attr($selectedChartDay); ?>" onclick="acymChartLineUpdate(this, 'day')">
72 <?php echo esc_html(acym_translation('ACYM_BY_DAY')); ?>
73 </p>
74 <p class="acym__chart__line__choose__by__one <?php echo esc_attr($selectedChartHour); ?>" onclick="acymChartLineUpdate(this, 'hour')">
75 <?php echo esc_html(acym_translation('ACYM_BY_HOUR')); ?>
76 </p>
77 </div>
78 <div class="acym__chart__line__legend" id="<?php echo esc_attr($idLegend); ?>"></div>
79 <canvas id="<?php echo esc_attr($idCanvas); ?>" height="400" width="400"></canvas>
80 </div>
81
82 <script>
83 <?php echo $ajax ? '' : 'document.addEventListener("DOMContentLoaded", function () {'; ?>
84 const ctx = document.getElementById(<?php echo json_encode($idCanvas); ?>).getContext('2d');
85
86 //Background color under the line
87 const gradientBlue = ctx.createLinearGradient(0, 0, 0, 400);
88 gradientBlue.addColorStop(0, 'rgba(128,182,244,0.5)');
89 gradientBlue.addColorStop(0.5, 'rgba(128,182,244,0.25)');
90 gradientBlue.addColorStop(1, 'rgba(128,182,244,0)');
91
92 const gradientRed = ctx.createLinearGradient(0, 0, 0, 400);
93 gradientRed.addColorStop(0., 'rgba(255,82,89,0.5)');
94 gradientRed.addColorStop(0.5, 'rgba(255,82,89,0.25)');
95 gradientRed.addColorStop(1, 'rgba(255,82,89,0)');
96
97 const config = {
98 type: 'line',
99 data: {
100 labels: <?php echo json_encode(array_merge([acym_translation('ACYM_SENT')], $displayed)); ?>,
101 datasets: [
102 {
103 label: <?php echo json_encode(acym_translation('ACYM_CLICK')); ?>,
104 data: <?php echo json_encode(array_merge(['0'], $clickDisplayed)); ?>,
105 borderColor: '#00a4ff',
106 fill: true,
107 backgroundColor: gradientBlue,
108 borderWidth: 3,
109 pointBackgroundColor: '#ffffff',
110 pointRadius: 5
111 },
112 {
113 label: <?php echo json_encode(acym_translation('ACYM_OPEN')); ?>,
114 data: <?php echo json_encode(array_merge(['0'], $openDisplayed)); ?>,
115 borderColor: '#ff5259',
116 fill: true,
117 backgroundColor: gradientRed,
118 borderWidth: 3,
119 pointBackgroundColor: '#ffffff',
120 pointRadius: 5
121 }
122 ]
123 },
124 options: {
125 responsive: true,
126 legend: {
127 display: false
128 },
129 tooltips: {
130 backgroundColor: '#fff',
131 borderWidth: 2,
132 borderColor: '#303e46',
133 titleFontSize: 16,
134 titleFontColor: '#303e46',
135 bodyFontColor: '#303e46',
136 bodyFontSize: 14,
137 displayColors: false
138 },
139 maintainAspectRatio: false,
140 scales: {
141 yAxes: [
142 {
143 gridLines: {
144 display: false
145 },
146 ticks: {
147 display: true,
148 fontColor: '#0a0a0a'
149 }
150 }
151 ],
152 xAxes: [
153 {
154 gridLines: {
155 display: false
156 },
157 ticks: {
158 display: true,
159 fontSize: 14,
160 fontColor: '#0a0a0a'
161 }
162 }
163 ]
164 },
165 legendCallback: function (chart) {
166 const text = [];
167 for (let i = 0 ; i < chart.data.datasets.length ; i++) {
168 if (chart.data.datasets[i].label) {
169 text.push(`<div onclick="updateDataset(event, ${chart.legend.legendItems[i].datasetIndex}, this)" class="acym_chart_line_labels">
170 <div class="acym_chart_line_labels_circle" style="background-color: ${chart.data.datasets[i].borderColor}"></div>
171 <span>${chart.data.datasets[i].label}</span>
172 </div>`);
173 }
174 }
175 return text.join('');
176 }
177 }
178 };
179
180 const chart = new Chart(ctx, config);
181 document.getElementById(<?php echo json_encode($idLegend); ?>).innerHTML = chart.generateLegend();
182
183 updateDataset = function (e, datasetIndex, element) {
184 element = element.children[1];
185 const index = datasetIndex;
186 const ci = e.view.chart;
187 const meta = ci.getDatasetMeta(index);
188
189 meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
190
191 if (element.style.textDecoration === 'line-through') {
192 element.style.textDecoration = 'none';
193 } else {
194 element.style.textDecoration = 'line-through';
195 }
196
197 ci.update();
198 };
199
200 acymChartLineUpdate = function (elem, by) {
201 document.getElementById('acym__time__linechart__input').value = by;
202 const chartLineLabels = document.getElementsByClassName('acym_chart_line_labels');
203 for (let i = 0 ; i < chartLineLabels.length ; i++) {
204 chartLineLabels[i].getElementsByTagName('span')[0].style.textDecoration = 'none';
205 }
206
207 let labels = [];
208 let dataOpen = [];
209 let dataClick = [];
210
211 if (by === 'month') {
212 labels = <?php echo json_encode(array_merge([acym_translation('ACYM_SENT')], $month)); ?>;
213 dataOpen = <?php echo json_encode(array_merge(['0'], $openMonth)); ?>;
214 dataClick = <?php echo json_encode(array_merge(['0'], $clickMonth)); ?>;
215 } else if (by === 'day') {
216 labels = <?php echo json_encode(array_merge([acym_translation('ACYM_SENT')], $day)); ?>;
217 dataOpen = <?php echo json_encode(array_merge(['0'], $openDay)); ?>;
218 dataClick = <?php echo json_encode(array_merge(['0'], $clickDay)); ?>;
219 } else if (by === 'hour') {
220 labels = <?php echo json_encode(array_merge([acym_translation('ACYM_SENT')], $hour)); ?>;
221 dataOpen = <?php echo json_encode(array_merge(['0'], $openHour)); ?>;
222 dataClick = <?php echo json_encode(array_merge(['0'], $clickHour)); ?>;
223 }
224
225 chart.config.data.labels = labels;
226 chart.config.data.datasets = [
227 {
228 label: <?php echo json_encode(acym_translation('ACYM_CLICK')); ?>,
229 data: dataClick,
230 borderColor: '#00a4ff',
231 fill: true,
232 backgroundColor: gradientBlue,
233 borderWidth: 3,
234 pointBackgroundColor: '#ffffff',
235 pointRadius: 5
236 },
237 {
238 label: <?php echo json_encode(acym_translation('ACYM_OPEN')); ?>,
239 data: dataOpen,
240 borderColor: '#ff5259',
241 fill: true,
242 backgroundColor: gradientRed,
243 borderWidth: 3,
244 pointBackgroundColor: '#ffffff',
245 pointRadius: 5
246 }
247 ];
248 chart.update();
249 const allChooseBy = document.getElementsByClassName('acym__chart__line__choose__by__one');
250 for (let i = 0 ; i < allChooseBy.length ; i++) {
251 allChooseBy[i].classList.remove('selected__choose_by');
252 }
253 elem.classList.add('selected__choose_by');
254 };
255
256 document.querySelector('.selected__choose_by').click();
257 <?php echo $ajax ? '' : '});'; ?>
258 </script>
259 <?php
260 }
261
262 function acym_initializeChart(): void
263 {
264 static $loaded = false;
265
266 if (!$loaded) {
267 acym_addScript(false, ACYM_JS.'libraries/chart.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'chart.min.js'), ['defer' => false, 'needTagScript' => true]);
268 $loaded = true;
269 }
270 }
271
272 function acym_displayRoundChart($percentage, string $type = '', string $class = '', string $topLabel = ''): void
273 {
274 if (empty($percentage) && $percentage !== 0) {
275 return;
276 }
277
278 acym_initializeChart();
279
280 $randNumber = acym_rand(1000, 9000);
281 $id = 'acy_round_chart_rand_id'.$randNumber;
282 $idCanvas = 'acy_canvas_rand_id'.$randNumber;
283
284 $green = '#3dea91';
285 $red = '#ff5259';
286 $orange = '#ffab15';
287 $defaultColor = '#00a4ff';
288
289 $isFixColor = false;
290 $isInverted = false;
291
292 switch ($type) {
293 case 'click':
294 $valueHigh = 5;
295 $valueLow = 1;
296 break;
297 case 'open':
298 $valueHigh = 30;
299 $valueLow = 18;
300 break;
301 case 'delivery':
302 $valueHigh = 90;
303 $valueLow = 70;
304 break;
305 case 'fail':
306 $valueHigh = 30;
307 $valueLow = 10;
308 $isInverted = true;
309 break;
310 case 'unsubscribe':
311 $valueHigh = 10;
312 $valueLow = 1;
313 $isInverted = true;
314 break;
315 default:
316 $isFixColor = true;
317 }
318
319 $color = $defaultColor;
320 if (!$isFixColor) {
321 if ($percentage >= $valueHigh) {
322 $color = $isInverted ? $red : $green;
323 } elseif ($percentage >= $valueLow) {
324 $color = $orange;
325 } else {
326 $color = $isInverted ? $green : $red;
327 }
328 }
329 ?>
330
331 <div class="<?php echo esc_attr($class); ?> acym__chart__doughnut text-center">
332 <p class="text-center acym__chart__doughnut__container__top-label"><?php echo wp_kses($topLabel, ['span' => ['class' => true], 'label' => []]); ?></p>
333 <div class="acym__chart__doughnut__container" id="<?php echo esc_attr($id); ?>">
334 <canvas id="<?php echo esc_attr($idCanvas); ?>" width="200" height="200"></canvas>
335 </div>
336 </div>
337
338 <script>
339 // Override to add text in the middle of chart
340 document.addEventListener('DOMContentLoaded', function () {
341 Chart.pluginService.register({
342 beforeDraw: function (chart) {
343 if (chart.config.options.elements.center) {
344 const ctx = chart.chart.ctx;
345
346 //Get options from the center object in options
347 const centerConfig = chart.config.options.elements.center;
348 const fontStyle = centerConfig.fontStyle || 'Arial';
349 const txt = centerConfig.text;
350 const color = centerConfig.color || '#000';
351 //Set font settings to draw it correctly.
352 ctx.textAlign = 'center';
353 ctx.textBaseline = 'middle';
354 const centerX = (
355 (
356 chart.chartArea.left + chart.chartArea.right
357 ) / 2
358 );
359 const centerY = (
360 (
361 chart.chartArea.top + chart.chartArea.bottom
362 ) / 2
363 );
364 ctx.font = '15px ' + fontStyle;
365 ctx.fillStyle = color;
366
367 //Draw text in center
368 ctx.fillText(txt, centerX, centerY);
369 }
370 }
371 });
372
373 const ctx = document.getElementById(<?php echo json_encode($idCanvas); ?>).getContext('2d');
374 const config = {
375 type: 'doughnut',
376 data: {
377 datasets: [
378 {
379 data: <?php echo json_encode([$percentage, 100 - $percentage]); ?>,
380 backgroundColor: <?php echo json_encode([$color, "#f1f1f1"]); ?>,
381 borderWidth: 0
382 }
383 ]
384 },
385 options: {
386 responsive: true,
387 legend: {
388 display: false
389 },
390 elements: {
391 center: {
392 text: <?php echo json_encode($percentage.'%'); ?>,
393 color: '#363636',
394 fontStyle: 'Poppins',
395 sidePadding: 70
396 }
397 },
398 cutoutPercentage: 90, // Thickness
399 tooltips: {
400 enabled: false // Disable tooltips on hover
401 }
402 }
403 };
404
405 new Chart(ctx, config);
406 });
407 </script>
408 <?php
409 }
410
411 function acym_pieChart(array $data = [], string $class = '', string $topLabel = '', bool $cap = true, bool $perList = false): void
412 {
413 if (empty($data)) {
414 return;
415 }
416
417 acym_initializeChart();
418
419 $randNumber = acym_rand(1000, 9000);
420 $id = 'acy_pie_chart_rand_id'.$randNumber;
421 $idCanvas = 'acy_canvas_rand_id'.$randNumber;
422 $idLegend = 'acy_legend_rand_id'.$randNumber;
423
424 $allLabelsArray = [];
425 $colors = [];
426
427 // Sort values higher to lower
428 asort($data);
429 $data = array_reverse($data, true);
430
431 // Move Others to the bottom
432 if (isset($data['ACYM_OTHER'])) {
433 $otherValue = $data['ACYM_OTHER'];
434 unset($data['ACYM_OTHER']);
435 $data['ACYM_OTHER'] = $otherValue;
436 }
437
438 $position = 0;
439 $othersValue = 0;
440 $nbOthers = 0;
441 if ($perList) {
442 foreach ($data as $itemId => $item) {
443 if ($position > 9 && $cap) {
444 $othersValue += (float)$item['value'];
445 unset($data[$itemId]);
446 $nbOthers++;
447 continue;
448 }
449 $data[$itemId] = (float)$item['value'];
450 $allLabelsArray[] = $item['label'];
451 $colors[] = $item['color'];
452 $position++;
453 }
454
455 if ($othersValue > 0) {
456 $othersValue = $othersValue / $nbOthers;
457 }
458 } else {
459 foreach ($data as $label => $number) {
460 if ($position > 9 && $cap) {
461 $othersValue += (float)$number;
462 unset($data[$label]);
463 continue;
464 }
465 $data[$label] = (float)$number;
466 $allLabelsArray[] = acym_translation($label);
467 $colors[] = acym_getChartColor($position);
468 $position++;
469 }
470 }
471
472 // We capped the number of elements shown, add the remaining values as "Others" at the end
473 if ($othersValue > 0) {
474 $data['ACYM_OTHER'] = $othersValue;
475 $allLabelsArray[] = acym_translation('ACYM_OTHER');
476 $colors[] = acym_getChartColor($position);
477 }
478 ?>
479 <div class="<?php echo esc_attr($class); ?> acym__chart__pie grid-x">
480 <p class="text-center acym__chart__pie__container__top-label cell medium-6"><?php echo wp_kses($topLabel, ['span' => ['class' => true], 'label' => []]); ?></p>
481 <div class="acym__chart__pie__container grid-x cell" id="<?php echo esc_attr($id); ?>">
482 <div class="acym__chart__pie__canvas_container cell medium-6">
483 <canvas id="<?php echo esc_attr($idCanvas); ?>" width="200" height="200"></canvas>
484 </div>
485 <div class="acym__chart__pie__legend cell medium-6 padding-left-1" id="<?php echo esc_attr($idLegend); ?>"></div>
486 </div>
487 </div>
488
489 <script>
490 document.addEventListener('DOMContentLoaded', function () {
491 const chart = new Chart(document.getElementById(<?php echo json_encode($idCanvas); ?>).getContext('2d'), {
492 type: 'pie',
493 data: {
494 datasets: [
495 {
496 data: <?php echo json_encode(array_values($data)); ?>,
497 backgroundColor: <?php echo json_encode($colors); ?>,
498 }
499 ],
500 labels: <?php echo json_encode($allLabelsArray); ?>
501 },
502 options: {
503 responsive: true,
504 legend: {
505 display: false
506 },
507 tooltips: {
508 backgroundColor: '#fff',
509 borderWidth: 2,
510 borderColor: '#303e46',
511 titleFontSize: 16,
512 titleFontColor: '#303e46',
513 bodyFontColor: '#303e46',
514 bodyFontSize: 14
515 },
516 legendCallback: function (chart) {
517 const dataSets = chart.data.datasets;
518 const colors = dataSets[0].backgroundColor;
519 const numbers = dataSets[0].data;
520 const labels = chart.data.labels;
521 const text = [];
522
523 if (colors.length !== labels.length) {
524 return '';
525 }
526
527 for (let i = 0 ; i < labels.length ; i++) {
528 text.push(`
529 <div class="acym_chart_pie_labels">
530 <div class="acym_chart_pie_labels_circle" style="background-color: ${colors[i]}"></div>
531 ${labels[i]} (${numbers[i]})
532 </div>`);
533 }
534
535 return text.join('');
536 }
537 }
538 });
539
540 document.getElementById(<?php echo json_encode($idLegend); ?>).innerHTML = chart.generateLegend();
541 });
542 </script>
543 <?php
544 }
545
546 function acym_displayBarChart(array $data = [], string $topLabel = ''): void
547 {
548 if (empty($data)) {
549 return;
550 }
551
552 acym_initializeChart();
553
554 $randNumber = acym_rand(1000, 9000);
555 $id = 'acy_pie_chart_rand_id'.$randNumber;
556 $idCanvas = 'acy_canvas_rand_id'.$randNumber;
557 $idLegend = 'acy_legend_rand_id'.$randNumber;
558
559 $allLabelsArray = [];
560 $colors = [];
561
562 asort($data);
563 $data = array_reverse($data, true);
564 $position = 0;
565 $cappedValue = 0;
566 $nbOther = 0;
567 foreach ($data as $itemId => $item) {
568 if ($position > 9) {
569 $cappedValue += (float)$item['value'];
570 unset($data[$itemId]);
571 $nbOther++;
572 continue;
573 }
574 $data[$itemId] = (float)$item['value'];
575 $allLabelsArray[] = $item['label'];
576 $colors[] = $item['color'];
577 $position++;
578 }
579
580 if ($cappedValue > 0) {
581 $cappedValue = $cappedValue / $nbOther;
582 $data[acym_translation('ACYM_OTHER')] = $cappedValue;
583 $allLabelsArray[] = acym_translation('ACYM_OTHER');
584 $colors[] = acym_getChartColor($position);
585 }
586 ?>
587
588 <div class="acym__chart__pie grid-x">
589 <p class="text-center acym__chart__pie__container__top-label cell medium-6"><?php echo wp_kses($topLabel, ['span' => ['class' => true], 'label' => []]); ?></p>
590 <div class="acym__chart__pie__container grid-x cell" id="<?php echo esc_attr($id); ?>">
591 <div class="acym__chart__pie__canvas_container cell medium-6">
592 <canvas id="<?php echo esc_attr($idCanvas); ?>" width="200" height="200"></canvas>
593 </div>
594 <div class="acym__chart__pie__legend cell medium-6 padding-left-1" id="<?php echo esc_attr($idLegend); ?>"></div>
595 </div>
596 </div>
597
598 <script>
599 document.addEventListener('DOMContentLoaded', function () {
600 const ctx = document.getElementById("<?php echo esc_attr($idCanvas); ?>").getContext('2d');
601 const config = {
602 type: 'bar',
603 data: {
604 datasets: [
605 {
606 data: <?php echo json_encode(array_values($data)); ?>,
607 backgroundColor: <?php echo json_encode($colors); ?>,
608 }
609 ],
610 labels: <?php echo json_encode($allLabelsArray); ?>
611 },
612 options: {
613 responsive: true,
614 legend: {
615 display: false
616 },
617 tooltips: {
618 backgroundColor: '#fff',
619 borderWidth: 2,
620 borderColor: '#303e46',
621 titleFontSize: 16,
622 titleFontColor: '#303e46',
623 bodyFontColor: '#303e46',
624 bodyFontSize: 14
625 },
626 legendCallback: function (chart) {
627 let dataSets = chart.data.datasets;
628 let colors = dataSets[0].backgroundColor;
629 let numbers = dataSets[0].data;
630 let labels = chart.data.labels;
631 let text = [];
632
633 if (colors.length !== labels.length) {
634 return '';
635 }
636
637 for (let i = 0 ; i < labels.length ; i++) {
638 text.push(`<div class="acym_chart_pie_labels">
639 <div class="acym_chart_pie_labels_circle" style="background-color: ${colors[i]}"></div>
640 ${labels[i]} (${numbers[i]}%)
641 </div>`);
642 }
643
644 return text.join('');
645 },
646
647 scales: {
648 xAxes: [
649 {
650 gridLines: {
651 drawTicks: false
652 },
653 ticks: {
654 display: false
655 }
656 }
657 ],
658 yAxes: [
659 {
660 gridLines: {
661 drawTicks: false
662 },
663 ticks: {
664 min: 0,
665 max: 100,
666 padding: 10
667 }
668 }
669 ]
670 }
671
672 }
673 };
674 const chart = new Chart(ctx, config);
675 document.getElementById(<?php echo json_encode($idLegend); ?>).innerHTML = (
676 chart.generateLegend()
677 );
678 });
679 </script>
680 <?php
681 }
682
683 function acym_getChartColor(int $position): string
684 {
685 $colors = [
686 '#845EC2',
687 '#D65DB1',
688 '#FF6F91',
689 '#FF9671',
690 '#FFC75F',
691 '#F9F871',
692 '#8BE884',
693 '#00CFA9',
694 '#00AFC6',
695 '#008AC9',
696 '#2261AC',
697 ];
698
699 return $colors[$position % 11];
700 }
701