PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.21
VikAppointments Services Booking Calendar v1.2.21
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / admin / layouts / statistics / widgets / finance / payments / chart.php
vikappointments / admin / layouts / statistics / widgets / finance / payments Last commit date
chart.php 5 days ago index.html 5 days ago table.php 5 days ago
chart.php
248 lines
1 <?php
2 /**
3 * @package VikAppointments
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * Layout variables
16 * -----------------
17 * @var VAPStatisticsWidget $widget The instance of the widget to be displayed.
18 * @var mixed $data The chart data to immediately display.
19 */
20 extract($displayData);
21
22 // include chart JS dependencies
23 JHtml::fetch('vaphtml.assets.chartjs');
24
25 // get list of preset colors
26 $colors = JHtml::fetch('vaphtml.color.preset', $list = true, $group = false);
27
28 ?>
29
30 <div class="canvas-align-bottom finance-payments-chart">
31 <canvas></canvas>
32 </div>
33
34 <script>
35
36 /**
37 * Defines a pool of charts, if undefined.
38 *
39 * @var object
40 */
41 if (typeof FINANCE_PAYMENTS_CHARTS === 'undefined') {
42 var FINANCE_PAYMENTS_CHARTS = {};
43 }
44
45 // init callbacks pool in case the caller didn't declare it
46 if (typeof WIDGET_CALLBACKS === 'undefined') {
47 var WIDGET_CALLBACKS = {};
48 }
49
50 (function($) {
51 'use strict';
52
53 // get default system preset of colors
54 const colorsPreset = <?php echo json_encode($colors); ?>;
55
56 /**
57 * Register callback to be executed after
58 * completing the update request.
59 *
60 * @param mixed widget The widget selector.
61 * @param mixed data The AJAX response.
62 * @param object config The widget configuration.
63 *
64 * @return void
65 */
66 WIDGET_CALLBACKS[<?php echo $widget->getID(); ?>] = (widget, data, config) => {
67 // get widget ID
68 var id = $(widget).attr('id');
69
70 // start from first position of the preset
71 let colorIndex = 0;
72
73 /**
74 * Create callback used to format the values displayed
75 * on the Y axis, according to the saved configuration.
76 *
77 * @param mixed value The value passed by the chart.
78 *
79 * @return string The formatted value.
80 */
81 const formatAxisY = (value) => {
82 // do not display decimal values on Y axis
83 return VAPCurrency.getInstance().format(value, 0);
84 }
85
86 /**
87 * Create callback used to format the values displayed
88 * with the tooltips of the hovered points, according
89 * to the saved configuration.
90 *
91 * @param mixed item The item to display.
92 * @param mixed data The chart data.
93 *
94 * @return string The formatted value.
95 */
96 const formatPointTooltip = (item, data) => {
97 // extract payment name from dataset
98 let payName = data.datasets[item.datasetIndex].label;
99 // create label in the form "PAYMENT: TOTAL"
100 return ' ' + payName + ': ' + VAPCurrency.getInstance().format(item.value);
101 }
102
103 // prepare chart data
104 var chartData = {
105 labels: Object.keys(data),
106 datasets: {},
107 };
108
109 // iterate all dates
110 $.each(data, (lbl, payments) => {
111 // iterate all payments
112 $.each(payments, (paymentName, value) => {
113 // check whether we already created the dataset for this payment gateway
114 if (!chartData.datasets.hasOwnProperty(paymentName)) {
115 // get progressive color
116 let color = colorsPreset[colorIndex++ % colorsPreset.length];
117
118 // nope, init data set
119 chartData.datasets[paymentName] = {
120 // the label string that appears when hovering the mouse above the lines intersection points
121 label: paymentName,
122 // the background color drawn behind the line (33 = 20% opacity)
123 backgroundColor: "#" + color + "33",
124 // the fill color of the line
125 borderColor: "#" + color,
126 // the fill color of the points
127 pointBackgroundColor: "#" + color,
128 // the border color of the points
129 pointBorderColor: "#fff",
130 // the radius of the points (in pixel)
131 pointRadius: 4,
132 // the fill color of the points when hovered
133 pointHoverBackgroundColor: "#fff",
134 // the border color of the points when hovered
135 pointHoverBorderColor: "#" + color,
136 // the radius of the points (in pixel) when hovered
137 pointHoverRadius: 5,
138 // the line dataset
139 data: [],
140 };
141 }
142
143 // include value within the dataset
144 chartData.datasets[paymentName].data.push(value);
145 });
146 });
147
148 // convert datasets into a linear array
149 chartData.datasets = Object.values(chartData.datasets);
150
151 // init chart from scratch if NULL
152 if (!FINANCE_PAYMENTS_CHARTS.hasOwnProperty(id)) {
153 // prepare chart configuration
154 var options = {
155 legend: {
156 // draw legend only if we are printing the document
157 display: <?php echo isset($data) ? 'true' : 'false'; ?>,
158 },
159 // axes handling
160 scales: {
161 // Y Axis properties
162 yAxes: [{
163 // make sure the chart starts at 0
164 ticks: {
165 // format value as currency
166 callback: formatAxisY,
167 beginAtZero: true,
168 },
169 }],
170 },
171 // tooltip handling
172 tooltips: {
173 // tooltip callbacks are used to customize default texts
174 callbacks: {
175 // format the tooltip text displayed when hovering a point
176 label: formatPointTooltip,
177 // change label colors because, by default, the legend background is blank
178 labelColor: (tooltipItem, chart) => {
179 // get tooltip item meta data
180 var meta = chart.data.datasets[tooltipItem.datasetIndex];
181
182 return {
183 // use white border
184 borderColor: 'rgb(0,0,0)',
185 // use same item background color
186 backgroundColor: meta.borderColor,
187 };
188 },
189 },
190 },
191 animation: {
192 // unset duration in case we are exporting the chart
193 duration: <?php echo isset($data) ? 0 : 1000; ?>,
194 },
195 };
196
197 // get 2D canvas for LINE chart
198 var canvas = $(widget).find('canvas')[0];
199 var ctx = canvas.getContext('2d');
200
201 // init chart from scratch if undefined
202 FINANCE_PAYMENTS_CHARTS[id] = new Chart(ctx, {
203 type: 'line',
204 data: chartData,
205 options: options,
206 });
207 }
208 // otherwise update labels and values
209 else {
210 // update chart data
211 FINANCE_PAYMENTS_CHARTS[id].data = chartData;
212
213 // update format callbacks
214 FINANCE_PAYMENTS_CHARTS[id].options.scales.yAxes[0].ticks.callback = formatAxisY;
215 FINANCE_PAYMENTS_CHARTS[id].options.tooltips.callbacks.label = formatPointTooltip;
216
217 // refresh chart
218 FINANCE_PAYMENTS_CHARTS[id].update();
219 }
220 }
221
222 <?php
223
224 ////////////////////////
225 ///// EXPORT UTILS /////
226 ////////////////////////
227
228 if (isset($data))
229 {
230 ?>
231 $(function() {
232 // auto-invoke callback on page loading completion
233 WIDGET_CALLBACKS[<?php echo $widget->getID(); ?>](
234 // exported assume, there should be only one widget displayed
235 $('.finance-payments-chart'),
236 // JSON-encode the passed chart data
237 <?php echo json_encode($data); ?>,
238 // JSON-encode the widget configuration
239 <?php echo json_encode($widget->getOptions()); ?>
240 );
241 });
242 <?php
243 }
244 ?>
245 })(jQuery);
246
247 </script>
248