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 / customers / chart.php
vikappointments / admin / layouts / statistics / widgets / appointments / customers Last commit date
chart.php 5 days ago index.html 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 JText::script('VAP_N_PEOPLE');
26 JText::script('VAP_N_PEOPLE_1');
27
28 ?>
29
30 <div class="canvas-align-bottom appointments-customers-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_CUSTOMERS_CHARTS === 'undefined') {
42 var APPOINTMENTS_CUSTOMERS_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 /**
80 * Create callback used to format the values displayed
81 * with the tooltips of the hovered points, according
82 * to the saved configuration.
83 *
84 * @param mixed item The item to display.
85 * @param mixed data The chart data.
86 *
87 * @return string The formatted value.
88 */
89 const formatPointTooltip = (item, data) => {
90 var label = '';
91
92 var count = parseInt(item.value);
93 var langk = 'VAP_N_PEOPLE';
94
95 // format label by fetching singular/plural form
96 if (count == 1) {
97 label = Joomla.JText._(langk + '_1');
98 } else {
99 label = Joomla.JText._(langk).replace(/%d/, count);
100 }
101
102 return ' ' + label;
103 }
104
105 // in case the chart already exists and the config type doesn't match, unset the cached chart, because
106 // we have to manually recreate it, as the chart type have been changed from line to bar or viceversa
107 if (APPOINTMENTS_CUSTOMERS_CHARTS.hasOwnProperty(id) && APPOINTMENTS_CUSTOMERS_CHARTS[id].config.type != config.chart) {
108 APPOINTMENTS_CUSTOMERS_CHARTS[id].destroy();
109 delete APPOINTMENTS_CUSTOMERS_CHARTS[id];
110 }
111
112 // prepare chart data
113 var chartData = {
114 labels: Object.keys(data),
115 datasets: [],
116 };
117
118 if (config.chart == 'bar') {
119 chartData.datasets.push({
120 // the label string that appears when hovering the mouse above the lines intersection points
121 label: "Dataset",
122 // the background color drawn behind the line (99 = 60% opacity)
123 backgroundColor: "#" + config.color + "99",
124 // the fill color of the line
125 borderColor: "#" + config.color,
126 // the line dataset
127 data: Object.values(data),
128 });
129 } else {
130 chartData.datasets.push({
131 // the label string that appears when hovering the mouse above the lines intersection points
132 label: "Dataset",
133 // the background color drawn behind the line (33 = 20% opacity)
134 backgroundColor: "#" + config.color + "33",
135 // the fill color of the line
136 borderColor: "#" + config.color,
137 // the fill color of the points
138 pointBackgroundColor: "#" + config.color,
139 // the border color of the points
140 pointBorderColor: "#fff",
141 // the radius of the points (in pixel)
142 pointRadius: 4,
143 // the fill color of the points when hovered
144 pointHoverBackgroundColor: "#fff",
145 // the border color of the points when hovered
146 pointHoverBorderColor: "#" + config.color,
147 // the radius of the points (in pixel) when hovered
148 pointHoverRadius: 5,
149 // the line dataset
150 data: Object.values(data),
151 });
152 }
153
154 // init chart from scratch if NULL
155 if (!APPOINTMENTS_CUSTOMERS_CHARTS.hasOwnProperty(id)) {
156 // prepare chart configuration
157 var options = {
158 // turn off legend
159 legend: {
160 display: false,
161 },
162 // axes handling
163 scales: {
164 // Y Axis properties
165 yAxes: [{
166 // make sure the chart starts at 0
167 ticks: {
168 beginAtZero: true,
169 },
170 }],
171 },
172 // tooltip handling
173 tooltips: {
174 // tooltip callbacks are used to customize default texts
175 callbacks: {
176 // format the tooltip text displayed when hovering a point
177 label: formatPointTooltip,
178 // change label colors because, by default, the legend background is blank
179 labelColor: (tooltipItem, chart) => {
180 // get tooltip item meta data
181 var meta = chart.data.datasets[tooltipItem.datasetIndex];
182
183 return {
184 // use white border
185 borderColor: 'rgb(0,0,0)',
186 // use same item background color
187 backgroundColor: meta.borderColor,
188 };
189 },
190 },
191 },
192 animation: {
193 // unset duration in case we are exporting the chart
194 duration: <?php echo isset($data) ? 0 : 1000; ?>,
195 },
196 };
197
198 // get 2D canvas for LINE chart
199 var canvas = $(widget).find('canvas')[0];
200 var ctx = canvas.getContext('2d');
201
202 // init chart from scratch if undefined
203 APPOINTMENTS_CUSTOMERS_CHARTS[id] = new Chart(ctx, {
204 type: config.chart,
205 data: chartData,
206 options: options,
207 });
208 }
209 // otherwise update labels and values
210 else {
211 // update chart data
212 APPOINTMENTS_CUSTOMERS_CHARTS[id].data = chartData;
213
214 // update format callbacks
215 APPOINTMENTS_CUSTOMERS_CHARTS[id].options.tooltips.callbacks.label = formatPointTooltip;
216
217 // refresh chart
218 APPOINTMENTS_CUSTOMERS_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 $('.appointments-customers-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