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 / appointments / times / chart.php
vikappointments / admin / layouts / statistics / widgets / appointments / times Last commit date
chart.php 5 days ago index.html 5 days ago
chart.php
246 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 JText::script('VAP_N_RESERVATIONS');
26 JText::script('VAP_N_RESERVATIONS_1');
27
28 ?>
29
30 <div class="canvas-align-bottom appointments-times-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 APPOINTMENTS_TIMES_CHARTS === 'undefined') {
42 var APPOINTMENTS_TIMES_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 /**
54 * Register callback to be executed after
55 * completing the update request.
56 *
57 * @param mixed widget The widget selector.
58 * @param mixed data The AJAX response.
59 * @param object config The widget configuration.
60 *
61 * @return void
62 */
63 WIDGET_CALLBACKS[<?php echo $widget->getID(); ?>] = (widget, data, config) => {
64 // get widget ID
65 var id = $(widget).attr('id');
66
67 // fetch color
68 if (config.color && config.color.match(/^#?[0-9a-f]{6,6}$/i))
69 {
70 // use specified color
71 config.color = config.color.replace(/^#/, '');
72 }
73 else
74 {
75 // use default one
76 config.color = 'e68714';
77 }
78
79 // in case the chart already exists and the config type doesn't match, unset the cached chart, because
80 // we have to manually recreate it, as the chart type have been changed from line to bar or viceversa
81 if (APPOINTMENTS_TIMES_CHARTS.hasOwnProperty(id) && APPOINTMENTS_TIMES_CHARTS[id].config.type != config.chart) {
82 APPOINTMENTS_TIMES_CHARTS[id].destroy();
83 delete APPOINTMENTS_TIMES_CHARTS[id];
84 }
85
86 // prepare chart data
87 var chartData = {
88 labels: Object.keys(data).map((elem) => {
89 // remove literal added to keep the correct ordering of the object keys
90 return elem.replace(/^H/, '');
91 }),
92 datasets: [],
93 };
94
95 chartData.datasets.push({
96 // the label string that appears when hovering the mouse above the lines intersection points
97 label: "Dataset",
98 // the background color drawn behind the line (99 = 60% opacity)
99 backgroundColor: "#" + config.color + "99",
100 // the fill color of the line
101 borderColor: "#" + config.color,
102 // the line dataset
103 data: Object.values(data).map((elem) => {
104 if (config.chart == 'radar') {
105 return Math.round(elem.percent);
106 }
107
108 return elem.count;
109 }),
110 });
111
112 // init chart from scratch if NULL
113 if (!APPOINTMENTS_TIMES_CHARTS.hasOwnProperty(id)) {
114 var options;
115
116 if (config.chart == 'bar') {
117 // prepare chart configuration
118 options = {
119 // axes handling
120 scales: {
121 // Y Axis properties
122 yAxes: [{
123 // make sure the chart starts at 0
124 ticks: {
125 beginAtZero: true,
126 },
127 }],
128 },
129 // tooltip handling
130 tooltips: {
131 // tooltip callbacks are used to customize default texts
132 callbacks: {
133 // format the tooltip text displayed when hovering a point
134 label: (item, data) => {
135 var label = '';
136
137 var count = parseInt(item.value);
138 var langk = 'VAP_N_RESERVATIONS';
139
140 // format label by fetching singular/plural form
141 if (count == 1) {
142 label = Joomla.JText._(langk + '_1');
143 } else {
144 label = Joomla.JText._(langk).replace(/%d/, count);
145 }
146
147 return ' ' + label;
148 },
149 // change label colors because, by default, the legend background is blank
150 labelColor: (tooltipItem, chart) => {
151 // get tooltip item meta data
152 var meta = chart.data.datasets[tooltipItem.datasetIndex];
153
154 return {
155 // use white border
156 borderColor: 'rgb(0,0,0)',
157 // use same item background color
158 backgroundColor: meta.borderColor,
159 };
160 },
161 },
162 },
163 };
164 } else {
165 // prepare chart configuration
166 options = {
167 // tooltip handling
168 tooltips: {
169 // tooltip callbacks are used to customize default texts
170 callbacks: {
171 // format the hour title displayed above the point
172 title: (item, data) => {
173 if (item[0].value == 0) {
174 // do not show title for null items
175 return '';
176 }
177
178 return data.labels[item[0].index];
179 },
180 // format the tooltip text displayed when hovering a point
181 label: (item, data) => {
182 return Math.round(item.value) + '%';
183 },
184 },
185 },
186 };
187 }
188
189 // turn off legend
190 options.legend = {
191 display: false,
192 };
193
194 // unset duration in case we are exporting the chart
195 options.animation = {
196 duration: <?php echo isset($data) ? 0 : 1000; ?>,
197 };
198
199 // get 2D canvas for LINE chart
200 var canvas = $(widget).find('canvas')[0];
201 var ctx = canvas.getContext('2d');
202
203 // init chart from scratch if undefined
204 APPOINTMENTS_TIMES_CHARTS[id] = new Chart(ctx, {
205 type: config.chart,
206 data: chartData,
207 options: options,
208 });
209 }
210 // otherwise update labels and values
211 else {
212 // update chart data
213 APPOINTMENTS_TIMES_CHARTS[id].data = chartData;
214
215 // refresh chart
216 APPOINTMENTS_TIMES_CHARTS[id].update();
217 }
218 }
219
220 <?php
221
222 ////////////////////////
223 ///// EXPORT UTILS /////
224 ////////////////////////
225
226 if (isset($data))
227 {
228 ?>
229 $(function() {
230 // auto-invoke callback on page loading completion
231 WIDGET_CALLBACKS[<?php echo $widget->getID(); ?>](
232 // exported assume, there should be only one widget displayed
233 $('.appointments-times-chart'),
234 // JSON-encode the passed chart data
235 <?php echo json_encode($data); ?>,
236 // JSON-encode the widget configuration
237 <?php echo json_encode($widget->getOptions()); ?>
238 );
239 });
240 <?php
241 }
242 ?>
243 })(jQuery);
244
245 </script>
246