@osimatic/helpers-js 1.2.8 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/chartjs.js ADDED
@@ -0,0 +1,309 @@
1
+ class Chartjs {
2
+ static init() {
3
+ if (typeof Chartjs.initialized == 'undefined' || Chartjs.initialized) {
4
+ return;
5
+ }
6
+
7
+ Chartjs.initialized = true;
8
+
9
+ const centerTextPlugin = {
10
+ id: 'centerText',
11
+ afterDraw(chart) {
12
+ if (typeof chart.config.options.centerText == 'undefined' || !chart.config.options.centerText.display) {
13
+ return;
14
+ }
15
+
16
+ const { ctx, chartArea: { width, height } } = chart;
17
+ ctx.save();
18
+ const total = chart.data.datasets[0].data.reduce((a,b) => a+b, 0);
19
+ const label = chart.config.options.centerText.label || '';
20
+ const fontSize = chart.config.options.centerText.fontSize || 16;
21
+ const textColor = chart.config.options.centerText.color || '#333';
22
+
23
+ ctx.font = `bold ${fontSize}px sans-serif`;
24
+ ctx.fillStyle = textColor;
25
+ ctx.textAlign = 'center';
26
+ ctx.textBaseline = 'middle';
27
+ ctx.fillText(`${total}`, width / 2, height / 2);
28
+ if (label) {
29
+ ctx.font = `12px sans-serif`;
30
+ ctx.fillText(label, width / 2, height / 2 + 20);
31
+ }
32
+ ctx.restore();
33
+ }
34
+ };
35
+
36
+ Chart.register(centerTextPlugin);
37
+ }
38
+
39
+ static createStackedChart(chartDiv, chartData, title=null, options={}) {
40
+ chartDiv.empty();
41
+ new Chart(chartDiv.get(0).getContext("2d"), $.extend(true, {}, {
42
+ type: "bar",
43
+ data: {
44
+ labels: chartData.labels,
45
+ datasets: chartData.datasets
46
+ },
47
+ options: {
48
+ responsive: true,
49
+ scales: {
50
+ x: {
51
+ stacked: true
52
+ },
53
+ y: {
54
+ stacked: true,
55
+ beginAtZero: true,
56
+ ticks: {
57
+ precision: 0
58
+ },
59
+ }
60
+ },
61
+ plugins: {
62
+ title: {
63
+ display: null !== title,
64
+ text: title || '',
65
+ font: { size: 14 },
66
+ color: "#333",
67
+ padding: { top: 10, bottom: 20 }
68
+ },
69
+ legend: {
70
+ position: "bottom",
71
+ labels: {
72
+ usePointStyle: true,
73
+ padding: 15
74
+ }
75
+ },
76
+ tooltip: {
77
+ callbacks: {
78
+ label: function(context) {
79
+ return `${context.dataset.label}: ${context.parsed.y}`;
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }, options));
86
+ }
87
+
88
+ static createBarChart(chartDiv, chartData, title=null, options={}) {
89
+ chartDiv.empty();
90
+ new Chart(chartDiv.get(0).getContext("2d"), $.extend(true, {}, {
91
+ type: "bar",
92
+ data: {
93
+ labels: chartData.labels,
94
+ datasets: chartData.datasets
95
+ },
96
+ options: {
97
+ responsive: false,
98
+ maintainAspectRatio: false,
99
+ aspectRatio: 2,
100
+ scales: {
101
+ x: {
102
+ grid: {
103
+ display: false
104
+ },
105
+ /*ticks: {
106
+ font: { size: 12 }
107
+ }*/
108
+ },
109
+ y: {
110
+ beginAtZero: true,
111
+ ticks: {
112
+ precision: 0
113
+ //stepSize: 10, font: { size: 12 }
114
+ },
115
+ grid: {
116
+ color: "#eee"
117
+ }
118
+ }
119
+ },
120
+ plugins: {
121
+ title: {
122
+ display: null !== title,
123
+ text: title || '',
124
+ font: { size: 14 },
125
+ color: "#333",
126
+ padding: { top: 10, bottom: 20 }
127
+ },
128
+ legend: {
129
+ display: chartData.datasets.length > 1,
130
+ position: "bottom",
131
+ },
132
+ tooltip: {
133
+ callbacks: {
134
+ label: context => context.dataset.label + ' : ' + context.parsed.y
135
+ //label: (context) => `${context.formattedValue} pointages`
136
+ }
137
+ }
138
+ },
139
+ animation: {
140
+ duration: 1200,
141
+ easing: "easeOutQuart"
142
+ }
143
+ }
144
+ }, options));
145
+ }
146
+
147
+ static createLineChart(chartDiv, chartData, title=null, options={}) {
148
+ Chartjs.init();
149
+
150
+ chartDiv.empty();
151
+ new Chart(chartDiv.get(0).getContext("2d"), $.extend(true, {}, {
152
+ type: "line",
153
+ data: {
154
+ labels: chartData.labels,
155
+ datasets: chartData.datasets
156
+ },
157
+ options: {
158
+ responsive: false,
159
+ maintainAspectRatio: false,
160
+ aspectRatio: 2,
161
+ scales: {
162
+ y: {
163
+ beginAtZero: true,
164
+ ticks: {
165
+ precision: 0
166
+ },
167
+ grid: {
168
+ color: "#eee"
169
+ }
170
+ },
171
+ x: {
172
+ grid: {
173
+ display: false
174
+ }
175
+ }
176
+ },
177
+ plugins: {
178
+ title: {
179
+ display: null !== title,
180
+ text: title || '',
181
+ font: { size: 14 },
182
+ color: "#333",
183
+ padding: { top: 10, bottom: 20 }
184
+ },
185
+ legend: {
186
+ display: chartData.datasets.length > 1,
187
+ position: "bottom",
188
+ },
189
+ tooltip: {
190
+ callbacks: {
191
+ label: context => context.dataset.label + ' : ' + context.parsed.y
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }, options));
197
+ }
198
+
199
+ static createDoughnutChart(chartDiv, chartData, title=null, options={}) {
200
+ Chartjs.init();
201
+
202
+ chartDiv.empty();
203
+ new Chart(chartDiv.get(0).getContext("2d"), $.extend(true, {}, {
204
+ type: "doughnut",
205
+ data: {
206
+ labels: chartData.labels,
207
+ datasets: [{
208
+ data: chartData.values,
209
+ backgroundColor: chartData.colors,
210
+ borderWidth: 0,
211
+ hoverOffset: 10
212
+ }]
213
+ },
214
+ options: {
215
+ cutout: "65%",
216
+ responsive: false,
217
+ maintainAspectRatio: false,
218
+ aspectRatio: 2,
219
+ plugins: {
220
+ title: {
221
+ display: null !== title,
222
+ text: title || ''
223
+ },
224
+ legend: {
225
+ position: "right",
226
+ labels: {
227
+ boxWidth: 12,
228
+ font: { size: 12 },
229
+ usePointStyle: true
230
+ }
231
+ },
232
+ tooltip: {
233
+ callbacks: {
234
+ label: function(context) {
235
+ const total = context.dataset.data.reduce((a,b)=>a+b,0);
236
+ const value = context.raw;
237
+ const percent = ((value / total) * 100).toFixed(1);
238
+ return `${context.label}: ${value} (${percent}%)`;
239
+ }
240
+ }
241
+ }
242
+ },
243
+ animation: {
244
+ animateRotate: true,
245
+ animateScale: true
246
+ },
247
+ centerText: {
248
+ display: false,
249
+ fontSize: 18,
250
+ color: "#000"
251
+ }
252
+ }
253
+ }, options));
254
+ }
255
+
256
+ static groupByPeriod(data, period, metrics) {
257
+ const grouped = {};
258
+
259
+ //data = Object.entries(dataObj).map(([date, values]) => ({ date, ...values }));
260
+
261
+ Object.entries(data).forEach(([date, values]) => {
262
+ //data.forEach(entry => {
263
+ const d = new Date(date);
264
+ let key;
265
+
266
+ if (period === 'week') {
267
+ const week = Math.ceil((d.getDate() - d.getDay() + 1) / 7);
268
+ key = `${d.getFullYear()}-S${week}`;
269
+ }
270
+ else if (period === 'month') {
271
+ key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
272
+ }
273
+ else {
274
+ key = date;
275
+ }
276
+
277
+ if (!grouped[key]) {
278
+ grouped[key] = {};
279
+ metrics.forEach(m => grouped[key][m] = []);
280
+ }
281
+
282
+ metrics.forEach(m => {
283
+ if (values[m] !== undefined) grouped[key][m].push(values[m]);
284
+ });
285
+ });
286
+
287
+ return Object.entries(grouped).map(([label, vals]) => {
288
+ const aggregated = {};
289
+ metrics.forEach(m => {
290
+ aggregated[m] = vals[m].reduce((a, b) => a + b, 0) / vals[m].length;
291
+ });
292
+ return { label, ...aggregated };
293
+ });
294
+ }
295
+
296
+ static getPeriodLabels(data, period, locale = 'fr-FR', timeZone = 'Europe/Paris') {
297
+ return DatePeriod.getPeriodLabels(Object.keys(data), period, locale, timeZone);
298
+ }
299
+
300
+ static getAutoGranularity(data) {
301
+ const dates = Object.keys(data);
302
+ const days = (new Date(dates[dates.length - 1]) - new Date(dates[0])) / (1000 * 60 * 60 * 24);
303
+ if (days > 90) return 'month';
304
+ if (days > 30) return 'week';
305
+ return 'day_of_month';
306
+ }
307
+ }
308
+
309
+ module.exports = { Chartjs };
package/date_time.js CHANGED
@@ -122,7 +122,7 @@ class DateTime {
122
122
  static getTimeDisplayWithNbDays(jsDate, jsPreviousDate, locale="fr-FR", timeZone="Europe/Paris") {
123
123
  let str = this.getTimeDisplay(jsDate, locale, timeZone);
124
124
  if (jsPreviousDate !== 0 && jsPreviousDate != null) {
125
- let nbDaysDiff = this.getNbDayBetweenTwo(jsPreviousDate, jsDate, false);
125
+ let nbDaysDiff = DatePeriod.getNbDayBetweenTwo(jsPreviousDate, jsDate, false);
126
126
  if (nbDaysDiff > 0) {
127
127
  str += ' (J+'+nbDaysDiff+')';
128
128
  }
@@ -277,6 +277,27 @@ class DateTime {
277
277
  return jsDateTime > today;
278
278
  }
279
279
 
280
+ static addDays(date, days) {
281
+ date.setUTCDate(date.getUTCDate() + days);
282
+ return date;
283
+ }
284
+
285
+ static addMonths(date, months) {
286
+ let d = date.getDate();
287
+ date.setMonth(date.getMonth() + +months);
288
+ if (date.getDate() !== d) {
289
+ date.setDate(0);
290
+ }
291
+ return date;
292
+ }
293
+
294
+ /** @deprecated use DatePeriod.getNbDayBetweenTwo instead */
295
+ static getNbDayBetweenTwo(jsDate1, jsDate2, asPeriod=false, timeZone="Europe/Paris") {
296
+ return DatePeriod.getNbDayBetweenTwo(jsDate1, jsDate2, asPeriod, timeZone);
297
+ }
298
+ }
299
+
300
+ class DatePeriod {
280
301
  static getNbDayBetweenTwo(jsDate1, jsDate2, asPeriod=false, timeZone="Europe/Paris") {
281
302
  //jsDate1.set
282
303
  if (jsDate1 == null || jsDate2 == null) {
@@ -299,18 +320,34 @@ class DateTime {
299
320
  return parseInt(Math.round((timestamp2-timestamp1)/86400));
300
321
  }
301
322
 
302
- static addDays(date, days) {
303
- date.setUTCDate(date.getUTCDate() + days);
304
- return date;
305
- }
323
+ static getPeriodLabels(data, period, locale = 'fr-FR', timeZone = 'Europe/Paris') {
324
+ if (!data || data.length === 0) {
325
+ return [];
326
+ }
306
327
 
307
- static addMonths(date, months) {
308
- let d = date.getDate();
309
- date.setMonth(date.getMonth() + +months);
310
- if (date.getDate() !== d) {
311
- date.setDate(0);
328
+ if (period === 'month') {
329
+ data.map(yearAndMonth => {
330
+ const [year, month] = yearAndMonth.split('-').map(Number);
331
+ return DateTime.getMonthNameByMonth(month, locale).capitalize()+' '+year;
332
+ });
312
333
  }
313
- return date;
334
+ if (period === 'week') {
335
+ return data.map(yearAndWeek => {
336
+ const [year, weekStr] = yearAndWeek.split('-S');
337
+ const week = parseInt(weekStr, 10);
338
+ return 'S'+week+' '+year;
339
+ });
340
+ }
341
+ if (period === 'day_of_week') {
342
+ return data.map(weekDay => DateTime.getDayNameByDayOfWeek(weekDay, locale).capitalize());
343
+ }
344
+ if (period === 'day_of_month') {
345
+ return data.map(sqlDate => SqlDate.getDateDigitalDisplay(sqlDate, locale, timeZone));
346
+ }
347
+ if (period === 'hour') {
348
+ return data.map(hour => String(hour).padStart(2, '0')+'h');
349
+ }
350
+ return data;
314
351
  }
315
352
  }
316
353
 
@@ -386,7 +423,7 @@ class TimestampUnix {
386
423
  }
387
424
 
388
425
  static getNbDayBetweenTwo(timestamp1, timestamp2, asPeriod=false, timeZone="Europe/Paris") {
389
- return DateTime.getNbDayBetweenTwo(this.parse(timestamp1), this.parse(timestamp2), asPeriod, timeZone);
426
+ return DatePeriod.getNbDayBetweenTwo(this.parse(timestamp1), this.parse(timestamp2), asPeriod, timeZone);
390
427
  }
391
428
 
392
429
  static isDateInThePast(timestamp) {
@@ -452,7 +489,7 @@ class SqlDate {
452
489
  return DateTime.isDateInTheFuture(SqlDateTime.parse(sqlDate + " 00:00:00"));
453
490
  }
454
491
  static getNbDayBetweenTwo(sqlDate1, sqlDate2, asPeriod=false) {
455
- return DateTime.getNbDayBetweenTwo(SqlDateTime.parse(sqlDate1 + " 00:00:00"), SqlDateTime.parse(sqlDate2 + " 00:00:00"), asPeriod);
492
+ return DatePeriod.getNbDayBetweenTwo(SqlDateTime.parse(sqlDate1 + " 00:00:00"), SqlDateTime.parse(sqlDate2 + " 00:00:00"), asPeriod);
456
493
  }
457
494
  }
458
495
 
@@ -585,9 +622,9 @@ class SqlDateTime {
585
622
  }
586
623
 
587
624
  static getNbDayBetweenTwo(sqlDateTime1, sqlDateTime2, asPeriod=false) {
588
- return DateTime.getNbDayBetweenTwo(this.parse(sqlDateTime1), this.parse(sqlDateTime2), asPeriod);
625
+ return DatePeriod.getNbDayBetweenTwo(this.parse(sqlDateTime1), this.parse(sqlDateTime2), asPeriod);
589
626
  }
590
627
 
591
628
  }
592
629
 
593
- module.exports = { DateTime, TimestampUnix, SqlDate, SqlTime, SqlDateTime };
630
+ module.exports = { DateTime, DatePeriod, TimestampUnix, SqlDate, SqlTime, SqlDateTime };
package/duration.js CHANGED
@@ -69,9 +69,8 @@ class Duration {
69
69
 
70
70
  // Minutes
71
71
  let strMinute = '';
72
- let nbMinutes = 0;
73
72
  if (withMinutes) {
74
- nbMinutes = this.getNbMinutesRemainingOfDurationInSeconds(durationInSeconds);
73
+ let nbMinutes = this.getNbMinutesRemainingOfDurationInSeconds(durationInSeconds);
75
74
  strMinute += ' ';
76
75
  //strMinute += sprintf('%02d', nbMinutes);
77
76
  strMinute += nbMinutes.toString().padStart(2, '0');
package/index.js CHANGED
@@ -12,7 +12,7 @@ const { HTTPRequest, Cookie, UrlAndQueryString } = require('./network');
12
12
  const { IBAN, BankCard } = require('./bank');
13
13
  const { AudioMedia, VideoMedia, UserMedia } = require('./media');
14
14
  const { PersonName, Email, TelephoneNumber } = require('./contact_details');
15
- const { DateTime, TimestampUnix, SqlDate, SqlTime, SqlDateTime } = require('./date_time');
15
+ const { DateTime, DatePeriod, TimestampUnix, SqlDate, SqlTime, SqlDateTime } = require('./date_time');
16
16
  const { Duration } = require('./duration');
17
17
  const { File, CSV, Img } = require('./file');
18
18
  const { FormHelper, EditValue } = require('./form_helper');
@@ -41,6 +41,7 @@ const { WebRTC } = require('./web_rtc');
41
41
  const { EventBus } = require('./event_bus');
42
42
 
43
43
  // exports surcouche lib externe
44
+ const { Chartjs } = require('./chartjs');
44
45
  const { GoogleCharts } = require('./google_charts');
45
46
  const { GoogleRecaptcha } = require('./google_recaptcha');
46
47
  const { GoogleMap } = require('./google_maps');
@@ -49,8 +50,8 @@ const { WebSocket } = require('./web_socket');
49
50
 
50
51
  module.exports = {
51
52
  Array, Object, Number, String,
52
- HTTPClient, HTTPRequest, Cookie, UrlAndQueryString, IBAN, BankCard, AudioMedia, VideoMedia, UserMedia, PersonName, Email, TelephoneNumber, DateTime, TimestampUnix, SqlDate, SqlTime, SqlDateTime, Duration, File, CSV, Img, FormHelper, Country, PostalAddress, GeographicCoordinates, HexColor, RgbColor, SocialNetwork, NumberFormatter
53
+ HTTPClient, HTTPRequest, Cookie, UrlAndQueryString, IBAN, BankCard, AudioMedia, VideoMedia, UserMedia, PersonName, Email, TelephoneNumber, DateTime, DatePeriod, TimestampUnix, SqlDate, SqlTime, SqlDateTime, Duration, File, CSV, Img, FormHelper, Country, PostalAddress, GeographicCoordinates, HexColor, RgbColor, SocialNetwork, NumberFormatter,
53
54
  Browser, DataTable, Pagination, Navigation, DetailsSubArray, SelectAll, MultipleActionInTable, MultipleActionInDivList, EditValue, FormDate, InputPeriod, ShoppingCart, FlashMessage, CountDown, ImportFromCsv, JwtToken, JwtSession, ApiTokenSession, ListBox, WebRTC, WebSocket, EventBus,
54
55
  sleep, refresh, chr, ord, trim, empty,
55
- GoogleCharts, GoogleRecaptcha, GoogleMap, OpenStreetMap
56
+ Chartjs, GoogleCharts, GoogleRecaptcha, GoogleMap, OpenStreetMap
56
57
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osimatic/helpers-js",
3
- "version": "1.2.8",
3
+ "version": "1.3.0",
4
4
  "main": "main.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"