PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.0.5
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.0.5
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.5, at back/Helpers/global/chart.php

707 lines 25.2 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 = '', string $centerText = ''): void
273 {
274 if (empty($percentage) && $percentage !== 0) {
275 return;
276 }
277
278 acym_initializeChart();
279
280 // A total-based value can exceed 100% (e.g. anonymized opens/clicks): clamp the ring so it never overflows
281 $gauge = max(0, min(100, (float)$percentage));
282 if ($centerText === '') {
283 $centerText = $percentage.'%';
284 }
285
286 $randNumber = acym_rand(1000, 9000);
287 $id = 'acy_round_chart_rand_id'.$randNumber;
288 $idCanvas = 'acy_canvas_rand_id'.$randNumber;
289
290 $green = '#3dea91';
291 $red = '#ff5259';
292 $orange = '#ffab15';
293 $defaultColor = '#00a4ff';
294
295 $isFixColor = false;
296 $isInverted = false;
297
298 switch ($type) {
299 case 'click':
300 $valueHigh = 5;
301 $valueLow = 1;
302 break;
303 case 'open':
304 $valueHigh = 30;
305 $valueLow = 18;
306 break;
307 case 'delivery':
308 $valueHigh = 90;
309 $valueLow = 70;
310 break;
311 case 'fail':
312 $valueHigh = 30;
313 $valueLow = 10;
314 $isInverted = true;
315 break;
316 case 'unsubscribe':
317 $valueHigh = 10;
318 $valueLow = 1;
319 $isInverted = true;
320 break;
321 default:
322 $isFixColor = true;
323 }
324
325 $color = $defaultColor;
326 if (!$isFixColor) {
327 if ($percentage >= $valueHigh) {
328 $color = $isInverted ? $red : $green;
329 } elseif ($percentage >= $valueLow) {
330 $color = $orange;
331 } else {
332 $color = $isInverted ? $green : $red;
333 }
334 }
335 ?>
336
337 <div class="<?php echo esc_attr($class); ?> acym__chart__doughnut text-center">
338 <p class="text-center acym__chart__doughnut__container__top-label"><?php echo wp_kses($topLabel, ['span' => ['class' => true], 'label' => []]); ?></p>
339 <div class="acym__chart__doughnut__container" id="<?php echo esc_attr($id); ?>">
340 <canvas id="<?php echo esc_attr($idCanvas); ?>" width="200" height="200"></canvas>
341 </div>
342 </div>
343
344 <script>
345 // Override to add text in the middle of chart
346 document.addEventListener('DOMContentLoaded', function () {
347 Chart.pluginService.register({
348 beforeDraw: function (chart) {
349 if (chart.config.options.elements.center) {
350 const ctx = chart.chart.ctx;
351
352 //Get options from the center object in options
353 const centerConfig = chart.config.options.elements.center;
354 const fontStyle = centerConfig.fontStyle || 'Arial';
355 const txt = centerConfig.text;
356 const color = centerConfig.color || '#000';
357 //Set font settings to draw it correctly.
358 ctx.textAlign = 'center';
359 ctx.textBaseline = 'middle';
360 const centerX = (
361 (
362 chart.chartArea.left + chart.chartArea.right
363 ) / 2
364 );
365 const centerY = (
366 (
367 chart.chartArea.top + chart.chartArea.bottom
368 ) / 2
369 );
370 ctx.font = '15px ' + fontStyle;
371 ctx.fillStyle = color;
372
373 //Draw text in center
374 ctx.fillText(txt, centerX, centerY);
375 }
376 }
377 });
378
379 const ctx = document.getElementById(<?php echo json_encode($idCanvas); ?>).getContext('2d');
380 const config = {
381 type: 'doughnut',
382 data: {
383 datasets: [
384 {
385 data: <?php echo json_encode([$gauge, 100 - $gauge]); ?>,
386 backgroundColor: <?php echo json_encode([$color, "#f1f1f1"]); ?>,
387 borderWidth: 0
388 }
389 ]
390 },
391 options: {
392 responsive: true,
393 legend: {
394 display: false
395 },
396 elements: {
397 center: {
398 text: <?php echo json_encode($centerText); ?>,
399 color: '#363636',
400 fontStyle: 'Poppins',
401 sidePadding: 70
402 }
403 },
404 cutoutPercentage: 90, // Thickness
405 tooltips: {
406 enabled: false // Disable tooltips on hover
407 }
408 }
409 };
410
411 new Chart(ctx, config);
412 });
413 </script>
414 <?php
415 }
416
417 function acym_pieChart(array $data = [], string $class = '', string $topLabel = '', bool $cap = true, bool $perList = false): void
418 {
419 if (empty($data)) {
420 return;
421 }
422
423 acym_initializeChart();
424
425 $randNumber = acym_rand(1000, 9000);
426 $id = 'acy_pie_chart_rand_id'.$randNumber;
427 $idCanvas = 'acy_canvas_rand_id'.$randNumber;
428 $idLegend = 'acy_legend_rand_id'.$randNumber;
429
430 $allLabelsArray = [];
431 $colors = [];
432
433 // Sort values higher to lower
434 asort($data);
435 $data = array_reverse($data, true);
436
437 // Move Others to the bottom
438 if (isset($data['ACYM_OTHER'])) {
439 $otherValue = $data['ACYM_OTHER'];
440 unset($data['ACYM_OTHER']);
441 $data['ACYM_OTHER'] = $otherValue;
442 }
443
444 $position = 0;
445 $othersValue = 0;
446 $nbOthers = 0;
447 if ($perList) {
448 foreach ($data as $itemId => $item) {
449 if ($position > 9 && $cap) {
450 $othersValue += (float)$item['value'];
451 unset($data[$itemId]);
452 $nbOthers++;
453 continue;
454 }
455 $data[$itemId] = (float)$item['value'];
456 $allLabelsArray[] = $item['label'];
457 $colors[] = $item['color'];
458 $position++;
459 }
460
461 if ($othersValue > 0) {
462 $othersValue = $othersValue / $nbOthers;
463 }
464 } else {
465 foreach ($data as $label => $number) {
466 if ($position > 9 && $cap) {
467 $othersValue += (float)$number;
468 unset($data[$label]);
469 continue;
470 }
471 $data[$label] = (float)$number;
472 $allLabelsArray[] = acym_translation($label);
473 $colors[] = acym_getChartColor($position);
474 $position++;
475 }
476 }
477
478 // We capped the number of elements shown, add the remaining values as "Others" at the end
479 if ($othersValue > 0) {
480 $data['ACYM_OTHER'] = $othersValue;
481 $allLabelsArray[] = acym_translation('ACYM_OTHER');
482 $colors[] = acym_getChartColor($position);
483 }
484 ?>
485 <div class="<?php echo esc_attr($class); ?> acym__chart__pie grid-x">
486 <p class="text-center acym__chart__pie__container__top-label cell medium-6"><?php echo wp_kses($topLabel, ['span' => ['class' => true], 'label' => []]); ?></p>
487 <div class="acym__chart__pie__container grid-x cell" id="<?php echo esc_attr($id); ?>">
488 <div class="acym__chart__pie__canvas_container cell medium-6">
489 <canvas id="<?php echo esc_attr($idCanvas); ?>" width="200" height="200"></canvas>
490 </div>
491 <div class="acym__chart__pie__legend cell medium-6 padding-left-1" id="<?php echo esc_attr($idLegend); ?>"></div>
492 </div>
493 </div>
494
495 <script>
496 document.addEventListener('DOMContentLoaded', function () {
497 const chart = new Chart(document.getElementById(<?php echo json_encode($idCanvas); ?>).getContext('2d'), {
498 type: 'pie',
499 data: {
500 datasets: [
501 {
502 data: <?php echo json_encode(array_values($data)); ?>,
503 backgroundColor: <?php echo json_encode($colors); ?>,
504 }
505 ],
506 labels: <?php echo json_encode($allLabelsArray); ?>
507 },
508 options: {
509 responsive: true,
510 legend: {
511 display: false
512 },
513 tooltips: {
514 backgroundColor: '#fff',
515 borderWidth: 2,
516 borderColor: '#303e46',
517 titleFontSize: 16,
518 titleFontColor: '#303e46',
519 bodyFontColor: '#303e46',
520 bodyFontSize: 14
521 },
522 legendCallback: function (chart) {
523 const dataSets = chart.data.datasets;
524 const colors = dataSets[0].backgroundColor;
525 const numbers = dataSets[0].data;
526 const labels = chart.data.labels;
527 const text = [];
528
529 if (colors.length !== labels.length) {
530 return '';
531 }
532
533 for (let i = 0 ; i < labels.length ; i++) {
534 text.push(`
535 <div class="acym_chart_pie_labels">
536 <div class="acym_chart_pie_labels_circle" style="background-color: ${colors[i]}"></div>
537 ${labels[i]} (${numbers[i]})
538 </div>`);
539 }
540
541 return text.join('');
542 }
543 }
544 });
545
546 document.getElementById(<?php echo json_encode($idLegend); ?>).innerHTML = chart.generateLegend();
547 });
548 </script>
549 <?php
550 }
551
552 function acym_displayBarChart(array $data = [], string $topLabel = ''): void
553 {
554 if (empty($data)) {
555 return;
556 }
557
558 acym_initializeChart();
559
560 $randNumber = acym_rand(1000, 9000);
561 $id = 'acy_pie_chart_rand_id'.$randNumber;
562 $idCanvas = 'acy_canvas_rand_id'.$randNumber;
563 $idLegend = 'acy_legend_rand_id'.$randNumber;
564
565 $allLabelsArray = [];
566 $colors = [];
567
568 asort($data);
569 $data = array_reverse($data, true);
570 $position = 0;
571 $cappedValue = 0;
572 $nbOther = 0;
573 foreach ($data as $itemId => $item) {
574 if ($position > 9) {
575 $cappedValue += (float)$item['value'];
576 unset($data[$itemId]);
577 $nbOther++;
578 continue;
579 }
580 $data[$itemId] = (float)$item['value'];
581 $allLabelsArray[] = $item['label'];
582 $colors[] = $item['color'];
583 $position++;
584 }
585
586 if ($cappedValue > 0) {
587 $cappedValue = $cappedValue / $nbOther;
588 $data[acym_translation('ACYM_OTHER')] = $cappedValue;
589 $allLabelsArray[] = acym_translation('ACYM_OTHER');
590 $colors[] = acym_getChartColor($position);
591 }
592 ?>
593
594 <div class="acym__chart__pie grid-x">
595 <p class="text-center acym__chart__pie__container__top-label cell medium-6"><?php echo wp_kses($topLabel, ['span' => ['class' => true], 'label' => []]); ?></p>
596 <div class="acym__chart__pie__container grid-x cell" id="<?php echo esc_attr($id); ?>">
597 <div class="acym__chart__pie__canvas_container cell medium-6">
598 <canvas id="<?php echo esc_attr($idCanvas); ?>" width="200" height="200"></canvas>
599 </div>
600 <div class="acym__chart__pie__legend cell medium-6 padding-left-1" id="<?php echo esc_attr($idLegend); ?>"></div>
601 </div>
602 </div>
603
604 <script>
605 document.addEventListener('DOMContentLoaded', function () {
606 const ctx = document.getElementById("<?php echo esc_attr($idCanvas); ?>").getContext('2d');
607 const config = {
608 type: 'bar',
609 data: {
610 datasets: [
611 {
612 data: <?php echo json_encode(array_values($data)); ?>,
613 backgroundColor: <?php echo json_encode($colors); ?>,
614 }
615 ],
616 labels: <?php echo json_encode($allLabelsArray); ?>
617 },
618 options: {
619 responsive: true,
620 legend: {
621 display: false
622 },
623 tooltips: {
624 backgroundColor: '#fff',
625 borderWidth: 2,
626 borderColor: '#303e46',
627 titleFontSize: 16,
628 titleFontColor: '#303e46',
629 bodyFontColor: '#303e46',
630 bodyFontSize: 14
631 },
632 legendCallback: function (chart) {
633 let dataSets = chart.data.datasets;
634 let colors = dataSets[0].backgroundColor;
635 let numbers = dataSets[0].data;
636 let labels = chart.data.labels;
637 let text = [];
638
639 if (colors.length !== labels.length) {
640 return '';
641 }
642
643 for (let i = 0 ; i < labels.length ; i++) {
644 text.push(`<div class="acym_chart_pie_labels">
645 <div class="acym_chart_pie_labels_circle" style="background-color: ${colors[i]}"></div>
646 ${labels[i]} (${numbers[i]}%)
647 </div>`);
648 }
649
650 return text.join('');
651 },
652
653 scales: {
654 xAxes: [
655 {
656 gridLines: {
657 drawTicks: false
658 },
659 ticks: {
660 display: false
661 }
662 }
663 ],
664 yAxes: [
665 {
666 gridLines: {
667 drawTicks: false
668 },
669 ticks: {
670 min: 0,
671 max: 100,
672 padding: 10
673 }
674 }
675 ]
676 }
677
678 }
679 };
680 const chart = new Chart(ctx, config);
681 document.getElementById(<?php echo json_encode($idLegend); ?>).innerHTML = (
682 chart.generateLegend()
683 );
684 });
685 </script>
686 <?php
687 }
688
689 function acym_getChartColor(int $position): string
690 {
691 $colors = [
692 '#845EC2',
693 '#D65DB1',
694 '#FF6F91',
695 '#FF9671',
696 '#FFC75F',
697 '#F9F871',
698 '#8BE884',
699 '#00CFA9',
700 '#00AFC6',
701 '#008AC9',
702 '#2261AC',
703 ];
704
705 return $colors[$position % 11];
706 }
707