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 / coupons / chart.php
vikappointments / admin / layouts / statistics / widgets / finance / coupons Last commit date
chart.php 5 days ago index.html 5 days ago table.php 5 days ago
chart.php
255 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-coupons-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_COUPONS_CHARTS === 'undefined') {
42 var FINANCE_COUPONS_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 coupon code from dataset
98 let coupon = data.datasets[item.datasetIndex].label;
99 let label = VAPCurrency.getInstance().format(item.value);
100
101 if (coupon) {
102 label = coupon + ': ' + label;
103 }
104
105 // create label in the form "COUPON: TOTAL DISCOUNT"
106 return ' ' + label;
107 }
108
109 // prepare chart data
110 var chartData = {
111 labels: Object.keys(data),
112 datasets: {},
113 };
114
115 // iterate all dates
116 $.each(data, (lbl, coupons) => {
117 // iterate all coupons
118 $.each(coupons, (couponCode, value) => {
119 // check whether we already created the dataset for this coupon code
120 if (!chartData.datasets.hasOwnProperty(couponCode)) {
121 // get progressive color
122 let color = colorsPreset[colorIndex++ % colorsPreset.length];
123
124 // nope, init data set
125 chartData.datasets[couponCode] = {
126 // the label string that appears when hovering the mouse above the lines intersection points
127 label: couponCode,
128 // the background color drawn behind the line (33 = 20% opacity)
129 backgroundColor: "#" + color + "33",
130 // the fill color of the line
131 borderColor: "#" + color,
132 // the fill color of the points
133 pointBackgroundColor: "#" + color,
134 // the border color of the points
135 pointBorderColor: "#fff",
136 // the radius of the points (in pixel)
137 pointRadius: 4,
138 // the fill color of the points when hovered
139 pointHoverBackgroundColor: "#fff",
140 // the border color of the points when hovered
141 pointHoverBorderColor: "#" + color,
142 // the radius of the points (in pixel) when hovered
143 pointHoverRadius: 5,
144 // the line dataset
145 data: [],
146 };
147 }
148
149 // include value within the dataset
150 chartData.datasets[couponCode].data.push(value);
151 });
152 });
153
154 // convert datasets into a linear array
155 chartData.datasets = Object.values(chartData.datasets);
156
157 // init chart from scratch if NULL
158 if (!FINANCE_COUPONS_CHARTS.hasOwnProperty(id)) {
159 // prepare chart configuration
160 var options = {
161 legend: {
162 // draw legend only if we are printing the document and the
163 // user selected at least a coupon code
164 display: <?php echo isset($data) && array_filter($widget->getOption('coupons', [])) ? 'true' : 'false'; ?>,
165 },
166 // axes handling
167 scales: {
168 // Y Axis properties
169 yAxes: [{
170 // make sure the chart starts at 0
171 ticks: {
172 // format value as currency
173 callback: formatAxisY,
174 beginAtZero: true,
175 },
176 }],
177 },
178 // tooltip handling
179 tooltips: {
180 // tooltip callbacks are used to customize default texts
181 callbacks: {
182 // format the tooltip text displayed when hovering a point
183 label: formatPointTooltip,
184 // change label colors because, by default, the legend background is blank
185 labelColor: (tooltipItem, chart) => {
186 // get tooltip item meta data
187 var meta = chart.data.datasets[tooltipItem.datasetIndex];
188
189 return {
190 // use white border
191 borderColor: 'rgb(0,0,0)',
192 // use same item background color
193 backgroundColor: meta.borderColor,
194 };
195 },
196 },
197 },
198 animation: {
199 // unset duration in case we are exporting the chart
200 duration: <?php echo isset($data) ? 0 : 1000; ?>,
201 },
202 };
203
204 // get 2D canvas for LINE chart
205 var canvas = $(widget).find('canvas')[0];
206 var ctx = canvas.getContext('2d');
207
208 // init chart from scratch if undefined
209 FINANCE_COUPONS_CHARTS[id] = new Chart(ctx, {
210 type: 'line',
211 data: chartData,
212 options: options,
213 });
214 }
215 // otherwise update labels and values
216 else {
217 // update chart data
218 FINANCE_COUPONS_CHARTS[id].data = chartData;
219
220 // update format callbacks
221 FINANCE_COUPONS_CHARTS[id].options.scales.yAxes[0].ticks.callback = formatAxisY;
222 FINANCE_COUPONS_CHARTS[id].options.tooltips.callbacks.label = formatPointTooltip;
223
224 // refresh chart
225 FINANCE_COUPONS_CHARTS[id].update();
226 }
227 }
228
229 <?php
230
231 ////////////////////////
232 ///// EXPORT UTILS /////
233 ////////////////////////
234
235 if (isset($data))
236 {
237 ?>
238 $(function() {
239 // auto-invoke callback on page loading completion
240 WIDGET_CALLBACKS[<?php echo $widget->getID(); ?>](
241 // exported assume, there should be only one widget displayed
242 $('.finance-coupons-chart'),
243 // JSON-encode the passed chart data
244 <?php echo json_encode($data); ?>,
245 // JSON-encode the widget configuration
246 <?php echo json_encode($widget->getOptions()); ?>
247 );
248 });
249 <?php
250 }
251 ?>
252 })(jQuery);
253
254 </script>
255