chartjs-adapter-date-std
Version:
Chart.js adapter using browser standard Intl API for time functionalities
406 lines (403 loc) • 15.8 kB
JavaScript
/*!
* chartjs-adapter-date-std v0.1.13
* https://github.com/gcollin/chartjs-adapter-date-std/blob/master/README.md
* (c) 2023 chartjs-adapter-date-std Contributors
* Released under the MIT license
*/
(function (factory) {
typeof define === 'function' && define.amd ? define(factory) :
factory();
}((function () { 'use strict';
exports.__esModule = true;
exports.StdDateAdapter = void 0;
var chart_js_1 = require("chart.js");
/*
* An adaptor for the chartjs library enabling usage of time series without dependencies to any 3rd party libraries.
* Based on the work of: https://github.com/mnlipp/jgrapes-webconsole/blob/master/org.jgrapes.webconsole.provider.chartjs/resources/org/jgrapes/webconsole/provider/chartjs/chart.js/adapters/chartjs-adapter-simple.js
* Simple time axes adapter for chart.js.
*
* * Handles Date and numeric data (as from Date.toTime()) only.
*
* * Parsing simply calls the constructor of Date.
*
* * Supported displayFormats are "datetime", "milliseconds", ...
* (i.e. key is passed through). Formatting is done with
* Intl.DateTimeFormat. Locale may be changed between calls to
* update.
*
* * "weeks" and "quarters" is not supported by Intl.DateTimeFormat,
* the date is output instead.
*
* * The helper functions (add, diff, etc.) have not really been tested.
*
* * Superficial testing gives better performance results than moment
* when using firefox as runtime.
*/
var StdDateAdapter = /** @class */ (function () {
function StdDateAdapter(locale) {
var _a;
this.formatLabels = ["datetime", "millisecond",
"second", "minute", "hour", "day", "week", "month", "quarter", "year"];
this.FORMATS = {};
this.intlFormats = {
'datetime': {
year: "numeric", month: "short", day: "numeric",
'hour': "numeric", minute: "numeric", second: "numeric"
},
'millisecond': {
hour: "numeric", minute: "numeric", second: "numeric",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
fractionalSecondDigits: 3
},
'second': { hour: "numeric", minute: "numeric", second: "numeric" },
'minute': { hour: "numeric", minute: "numeric" },
'hour': { hour: 'numeric' },
'day': { day: 'numeric', month: 'short' },
'week': { day: 'numeric', month: 'short', year: 'numeric' },
'month': { month: 'short', year: 'numeric' },
'year': { year: 'numeric' }
};
this.formatters = {};
this.configuredLocale = "";
this.updateLocale(locale || ((_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.window) === null || _a === void 0 ? void 0 : _a.navigator.language) || "en-US");
for (var _i = 0, _b = this.formatLabels; _i < _b.length; _i++) {
var label = _b[_i];
(this.FORMATS)[label] = label;
}
}
/**
* Creates an object from this StdAdaptorClass that can be used in Object.assign (...).
* Needed for Chart.js
*/
StdDateAdapter.chartJsStandardAdapter = function () {
console.log("Registering GraphJs Standard Date Adaptor");
return {
_id: "StdDataAdapter",
delegate: new StdDateAdapter(),
override: function (members) {
return this.delegate.override(members);
},
init: function (chartOptions) {
return this.delegate.init(chartOptions);
},
formats: function () {
return this.delegate.formats();
},
parse: function (value, fmt) {
return this.delegate.parse(value, fmt);
},
format: function (time, fmt) {
return this.delegate.format(time, fmt);
},
add: function (time, amount, unit) {
return this.delegate.add(time, amount, unit);
},
diff: function (max, min, unit) {
return this.delegate.diff(max, min, unit);
},
startOf: function (time, unit, weekday) {
return this.delegate.startOf(time, unit, weekday);
},
endOf: function (time, unit) {
return this.delegate.endOf(time, unit);
}
};
};
StdDateAdapter.prototype.updateLocale = function (locale) {
if (locale && locale != this.configuredLocale) {
for (var _i = 0, _a = this.formatLabels; _i < _a.length; _i++) {
var label = _a[_i];
this.formatters[label] = new Intl.DateTimeFormat(locale, (this.intlFormats)[label]);
}
this.configuredLocale = locale;
}
};
StdDateAdapter.prototype.override = function (members) {
//throw new Error("Method not implemented.");
};
StdDateAdapter.prototype.init = function (chartOptions) {
//throw new Error("Method not implemented.");
};
StdDateAdapter.prototype.toInteger = function (dirtyNumber) {
if (dirtyNumber === null || dirtyNumber === true || dirtyNumber === false) {
return NaN;
}
var number = Number(dirtyNumber);
if (isNaN(number)) {
return number;
}
return number < 0 ? Math.ceil(number) : Math.floor(number);
};
StdDateAdapter.prototype.toDate = function (value) {
if (value == null) {
return null;
}
if (value instanceof Date) {
return value;
}
if (typeof value === 'number') {
return new Date(value);
}
else if (typeof value === 'string') {
var number = Date.parse(value);
if (isNaN(number)) {
// Check if it's a trimester
var val = value.toUpperCase().trim();
var trimester = -1;
// Brut force stuff
var trimesterPos = val.indexOf("Q1");
if (trimesterPos != -1)
trimester = 1;
else {
trimesterPos = val.indexOf("Q2");
if (trimesterPos != -1)
trimester = 2;
else {
trimesterPos = val.indexOf("Q3");
if (trimesterPos != -1)
trimester = 3;
else {
trimesterPos = val.indexOf("Q4");
if (trimesterPos != -1)
trimester = 4;
else
return null;
}
}
}
var year = NaN;
var yearIndex = val.substring(trimesterPos).lastIndexOf(" ");
if (yearIndex != -1)
year = Number.parseInt(val.substring(trimesterPos + yearIndex));
if (isNaN(year))
year = new Date().getFullYear();
// console.log ("Trimester = "+trimester.toString()+" value = "+((trimester-1)*3+1));
return new Date(year, ((trimester - 1) * 3 + 1));
}
else {
return new Date(number);
}
}
return null;
};
StdDateAdapter.prototype.addMonths = function (date, amount) {
var newDate = new Date(date.getTime());
newDate.setMonth(date.getMonth() + amount);
if (newDate.getMonth() != (date.getMonth() + amount) % 12) {
newDate.setDate(0);
}
return newDate.getTime();
};
StdDateAdapter.prototype.diffInMonths = function (max, min) {
var diff = (max.getFullYear() - min.getFullYear()) * 12;
diff += max.getMonth() - min.getMonth();
// Make sure that we have full months
if (this.addMonths(min, diff) > max.getTime()) {
diff -= 1;
}
return diff;
};
StdDateAdapter.prototype.formats = function () {
return this.FORMATS;
};
StdDateAdapter.prototype.parse = function (value, fmt) {
var _a;
// console.log("parsing ", value);
var ret = (_a = this.toDate(value)) === null || _a === void 0 ? void 0 : _a.getTime();
if (ret == null)
return null;
else
return ret;
};
StdDateAdapter.prototype.format = function (time, fmt) {
if (fmt === 'quarter') {
// Special case
var curDate = new Date(time);
// console.log ("Format quarter of ", curDate);
return "Q" + Math.floor(curDate.getMonth() / 3 + 1).toString() + " - " + curDate.getFullYear().toString();
}
if (!this.formatLabels.includes(fmt)) {
return "Unknown";
}
return (this.formatters)[fmt].format(time);
};
StdDateAdapter.prototype.add = function (time, amount, unit) {
amount = this.toInteger(amount);
if (isNaN(amount)) {
return amount;
}
var date = this.toDate(time);
if ((!amount) || (date == null)) {
return NaN;
}
switch (unit) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'week': amount *= 7;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'day': amount *= 24;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'hour': amount *= 60;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'minute': amount *= 60;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'second': amount *= 1000;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'millisecond': break;
case 'year': return this.addMonths(date, amount * 12);
case 'quarter': return this.addMonths(date, amount * 3);
case 'month': return this.addMonths(date, amount);
default: return time;
}
return time + amount;
};
StdDateAdapter.prototype.diff = function (max, min, unit) {
var maxDate = this.toDate(max);
var minDate = this.toDate(min);
if ((maxDate == null) || (minDate == null))
return NaN;
var diff = maxDate.getTime() - minDate.getTime();
switch (unit) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'week': diff /= 7;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'day': diff /= 24;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'hour': diff /= 60;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'minute': diff /= 60;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'second': diff /= 1000;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-fallthrough
case 'millisecond': break;
case 'month': return this.diffInMonths(maxDate, minDate);
case 'quarter': return this.diffInMonths(maxDate, minDate) / 3;
case 'year': return this.diffInMonths(maxDate, minDate) / 12;
default: return 0;
}
if (diff < 0) {
return Math.ceil(diff);
}
return Math.floor(diff);
};
StdDateAdapter.prototype.startOf = function (time, unit, weekday) {
var date = this.toDate(time);
if (date == null)
return NaN;
switch (unit) {
case 'second':
date.setMilliseconds(0);
break;
case 'minute':
date.setSeconds(0, 0);
break;
case 'hour':
date.setMinutes(0, 0, 0);
break;
case 'quarter':
{
var cur = date.getMonth();
date.setMonth(cur - (cur % 3));
}
break;
case 'month':
date.setDate(1);
break;
case 'day':
date.setHours(0, 0, 0, 0);
break;
case 'isoWeek':
case 'week': {
// Monday --> 0
var cur = (date.getDay() + 6) % 7;
date.setDate(date.getDate() - cur);
date.setHours(0, 0, 0, 0);
break;
}
case 'year': {
var newDate = new Date(0);
newDate.setFullYear(date.getFullYear(), 0, 1);
newDate.setHours(0, 0, 0, 0);
return newDate.getTime();
}
default: return date.getTime();
}
return date.getTime();
};
StdDateAdapter.prototype.endOf = function (time, unit) {
var date = this.toDate(time);
if (date == null)
return NaN;
switch (unit) {
case 'second':
date.setMilliseconds(999);
break;
case 'minute':
date.setSeconds(59, 999);
break;
case 'hour':
date.setMinutes(59, 59, 999);
break;
case 'day':
date.setHours(23, 59, 59, 999);
break;
case 'isoWeek':
case 'week': {
// Monday --> 0
var cur = (date.getDay() + 6) % 7;
date.setDate(date.getDate() + 6 - cur);
date.setHours(23, 59, 59, 999);
break;
}
case 'month': {
var month = date.getMonth();
date.setFullYear(date.getFullYear(), month + 1, 0);
date.setHours(23, 59, 59, 999);
break;
}
case 'quarter': {
var curMonth = date.getMonth();
date.setMonth(curMonth - (curMonth % 3) + 3, 0);
date.setHours(23, 59, 59, 999);
break;
}
case 'year': {
var year = date.getFullYear();
date.setFullYear(year + 1, 0, 0);
date.setHours(23, 59, 59, 999);
break;
}
default: return time;
}
return date.getTime();
};
return StdDateAdapter;
}());
exports.StdDateAdapter = StdDateAdapter;
// Automatically register the adapter
chart_js_1._adapters._date.override(StdDateAdapter.chartJsStandardAdapter());
})));