@senx/discovery-widgets
Version:
Discovery Widgets Elements
454 lines (453 loc) • 17.3 kB
JavaScript
/*
* Copyright 2022-2025 SenX S.A.S.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Logger } from "./logger";
import { JsonLib } from "./jsonLib";
import dayjs from "dayjs";
import duration from "dayjs/plugin/duration";
import moment from "moment/min/moment-with-locales";
import { tz } from "moment-timezone";
import { v4 } from "uuid";
dayjs.extend(duration);
export class GTSLib {
static getMinMax(values) {
let minVal = Number.MAX_SAFE_INTEGER;
let maxVal = Number.MIN_SAFE_INTEGER;
for (let v = 0; v < (values !== null && values !== void 0 ? values : []).length; v++) {
const val = values[v];
if (val > maxVal)
maxVal = val;
if (val < minVal)
minVal = val;
}
return { minVal, maxVal };
}
static getBounds(values) {
let minVal = Number.MAX_SAFE_INTEGER;
let maxVal = Number.MIN_SAFE_INTEGER;
let minTS = Number.MAX_SAFE_INTEGER;
let maxTS = Number.MIN_SAFE_INTEGER;
const rawVals = [];
for (let v = 0; v < (values !== null && values !== void 0 ? values : []).length; v++) {
const tuple = values[v];
const ts = tuple[0];
const val = tuple[tuple.length - 1];
if (ts > maxTS)
maxTS = ts;
if (ts < minTS)
minTS = ts;
if (val > maxVal)
maxVal = val;
if (val < minVal)
minVal = val;
rawVals.push(val);
}
return { minVal, maxVal, minTS, maxTS, rawVals };
}
static cleanArray(actual) {
return actual.filter((i) => !!i);
}
static isArray(value) {
return value && typeof value === 'object' && value instanceof Array && typeof value.length === 'number'
&& typeof value.splice === 'function' && !(Object.prototype.propertyIsEnumerable.call(value, 'length'));
}
static formatElapsedTime(elapsed) {
if (elapsed < 1000) {
return elapsed.toFixed(3) + ' ns';
}
if (elapsed < 1000000) {
return (elapsed / 1000).toFixed(3) + ' μs';
}
if (elapsed < 1000000000) {
return (elapsed / 1000000).toFixed(3) + ' ms';
}
if (elapsed < 1000000000000) {
return (elapsed / 1000000000).toFixed(3) + ' s ';
}
// Max exec time for nice output: 999.999 minutes (should be OK, timeout should happen before that).
return (elapsed / 60000000000).toFixed(3) + ' m ';
}
static isValidResponse(data) {
var _a, _b;
let response;
try {
response = new JsonLib().parse(data);
}
catch (e) {
(_a = this.LOG) === null || _a === void 0 ? void 0 : _a.error(['isValidResponse'], 'Response non JSON compliant', data, e);
return false;
}
if (!GTSLib.isArray(response)) {
(_b = this.LOG) === null || _b === void 0 ? void 0 : _b.error(['isValidResponse'], 'Response isn\'t an Array', response);
return false;
}
return true;
}
static isEmbeddedImage(item) {
return !(typeof item !== 'string' || !/^data:image/.test(item));
}
static isEmbeddedImageObject(item) {
return !((item === null) || (item.image === null) ||
(item.caption === null) || !GTSLib.isEmbeddedImage(item.image));
}
static isPositionArray(item) {
var _a;
if (!item || !item.positions) {
return false;
}
if (GTSLib.isPositionsArrayWithValues(item) || GTSLib.isPositionsArrayWithTwoValues(item)) {
return true;
}
((_a = item.positions) !== null && _a !== void 0 ? _a : []).forEach((p) => {
if (p.length < 2 || p.length > 3) {
return false;
}
for (const j in p) {
// noinspection JSUnfilteredForInLoop
if (typeof p[j] !== 'number') {
return false;
}
}
});
return true;
}
static isPositionsArrayWithValues(item) {
var _a;
if ((item === null) || (item.positions === null)) {
return false;
}
((_a = item.positions) !== null && _a !== void 0 ? _a : []).forEach((p) => {
if (p.length !== 3) {
return false;
}
for (const j in p) {
// noinspection JSUnfilteredForInLoop
if (typeof p[j] !== 'number') {
return false;
}
}
});
return true;
}
static isPositionsArrayWithTwoValues(item) {
var _a;
if ((item === null) || (item.positions === null)) {
return false;
}
((_a = item.positions) !== null && _a !== void 0 ? _a : []).forEach((p) => {
if (p.length !== 4) {
return false;
}
for (const j in p) {
// noinspection JSUnfilteredForInLoop
if (typeof p[j] !== 'number') {
return false;
}
}
});
return true;
}
static gtsFromJSON(json, id) {
return { gts: { c: json.c, l: json.l, a: json.a, v: json.v, id } };
}
static gtsFromJSONList(jsonList, prefixId) {
const gtsList = [];
let id;
(jsonList !== null && jsonList !== void 0 ? jsonList : []).forEach((item, i) => {
let gts = item;
if (item.gts) {
gts = item.gts;
}
if ((prefixId !== undefined) && (prefixId !== '')) {
id = `${prefixId}-${i}`;
}
else {
id = i;
}
if (GTSLib.isArray(gts)) {
gtsList.push(GTSLib.gtsFromJSONList(gts, id));
}
if (GTSLib.isGts(gts)) {
gtsList.push(GTSLib.gtsFromJSON(gts, id));
}
if (GTSLib.isEmbeddedImage(gts)) {
gtsList.push({ image: gts, caption: 'Image', id });
}
if (GTSLib.isEmbeddedImageObject(gts)) {
gtsList.push({ image: gts.image, caption: gts.caption, id });
}
});
return {
content: gtsList || [],
};
}
static flatDeep(arr1) {
if (!GTSLib.isArray(arr1)) {
arr1 = [arr1];
}
return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(GTSLib.flatDeep(val)) : acc.concat(val), []);
}
static flattenGtsIdArray(a, r) {
const res = [];
if (GTSLib.isGts(a)) {
a = [a];
}
(a !== null && a !== void 0 ? a : []).forEach((d) => {
if (GTSLib.isArray(d)) {
const walk = GTSLib.flattenGtsIdArray(d, r);
res.push(walk.res);
r = walk.r;
}
else if (this.isGts(d)) {
d.id = r;
res.push(d);
r++;
}
else {
res.push(d);
}
});
return { res, r };
}
static sanitizeNames(input) {
return (input || '').replace(/{/g, '{')
.replace(/}/g, '}')
.replace(/,/g, ',')
.replace(/>/g, '>')
.replace(/</g, '<')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
static serializeGtsMetadata(gts) {
const serializedLabels = [];
const serializedAttributes = [];
if (gts.l) {
Object.keys(gts.l).forEach((key) => {
serializedLabels.push(this.sanitizeNames(`${key}=${gts.l[key]}`));
});
}
if (gts.a) {
Object.keys(gts.a).forEach((key) => {
serializedAttributes.push(this.sanitizeNames(`${key}=${gts.a[key]}`));
});
}
return `${this.sanitizeNames(gts.c)}{${serializedLabels.join(',')}${serializedAttributes.length > 0 ? ',' : ''}${serializedAttributes.join(',')}}`;
}
static isGts(item) {
return !!item && (item.c === '' || !!item.c) && !!item.v && GTSLib.isArray(item.v);
}
static isGtsToPlot(gts) {
var _a;
if (!GTSLib.isGts(gts)) {
return false;
}
if (gts.v.length === 0)
return true;
// We look at the first non-null value, if it's a String or Boolean it's an annotation GTS,
// if it's a number it's a GTS to plot
return ((_a = gts.v) !== null && _a !== void 0 ? _a : []).some((v) => {
// noinspection JSPotentiallyInvalidConstructorUsage
return typeof v[v.length - 1] === 'number' || !!v[v.length - 1].constructor.prototype.toFixed;
});
}
static isGtsToPlotOnMap(gts) {
var _a;
if (!GTSLib.isGts(gts) || gts.v.length === 0) {
return false;
}
return ((_a = gts.v) !== null && _a !== void 0 ? _a : []).some((v) => v.length >= 3);
}
static isGtsToAnnotate(gts) {
var _a;
if (!GTSLib.isGts(gts) || gts.v.length === 0) {
return false;
}
// We look at the first non-null value, if it's a String or Boolean it's an annotation GTS,
// if it's a number it's a GTS to plot
return ((_a = gts.v) !== null && _a !== void 0 ? _a : []).some((v) => {
if (v[v.length - 1] !== null) {
// noinspection JSPotentiallyInvalidConstructorUsage
return typeof (v[v.length - 1]) !== 'number' &&
(!!v[v.length - 1].constructor && v[v.length - 1].constructor.name !== 'Big') &&
v[v.length - 1].constructor.prototype.toFixed === undefined;
}
});
}
static gtsSort(gts) {
if (gts.isSorted) {
return;
}
gts.v = gts.v.sort((a, b) => a[0] - b[0]);
gts.isSorted = true;
}
static addIdToGTS(data) {
if (GTSLib.isArray(data)) {
return data.map((d) => GTSLib.addIdToGTS(d));
}
else {
if (GTSLib.isGts(data)) {
data.uid = v4();
}
}
}
static getData(data) {
var _a, _b, _c, _d;
if (typeof data === 'string') {
if (data.startsWith('[') || data.startsWith('{')) {
return GTSLib.getData(new JsonLib().parse(data));
}
else {
return { data: new JsonLib().parse(`[${data}]`) };
}
}
else if (data && ((!!data.data || data.data === '' || data.data === 0) || data.events)) {
if ('' !== data.data) {
data.data = (_a = data.data) !== null && _a !== void 0 ? _a : [];
}
if (!GTSLib.isArray(data.data)) {
data.data = [data.data];
}
return data;
}
else if (GTSLib.isArray(data) && data.length > 0 && (((_b = data[0]) === null || _b === void 0 ? void 0 : _b.data) !== undefined || ((_c = data[0]) === null || _c === void 0 ? void 0 : _c.events))) {
data[0].data = (_d = data[0].data) !== null && _d !== void 0 ? _d : [];
return data[0];
}
else if (GTSLib.isArray(data)) {
return { data: data };
}
else {
return { data: new JsonLib().parse(`[${data}]`) };
}
}
static getDivider(timeUnit) {
let timestampDivider = 1000; // default for µs timeunit
if (timeUnit === 'ms') {
timestampDivider = 1;
}
if (timeUnit === 'ns') {
timestampDivider = 1000000;
}
return timestampDivider;
}
static toISOString(timestamp, divider, timeZone, timeFormat) {
const locale = window.navigator.userLanguage || window.navigator.language;
moment.updateLocale(locale.split('-')[0], {});
timeZone = timeZone === 'AUTO' ? tz.guess() : timeZone;
if (timeZone !== 'UTC') {
return tz(timestamp / divider, timeZone).format(timeFormat !== null && timeFormat !== void 0 ? timeFormat : 'YYYY-MM-DDTHH:mm:ss.SSS');
}
else {
return moment.utc(timestamp / divider).format(timeFormat !== null && timeFormat !== void 0 ? timeFormat : 'YYYY-MM-DDTHH:mm:ss.SSS');
}
}
static toTimestamp(date, divider, timeZone, format) {
timeZone = timeZone === 'AUTO' ? tz.guess() : timeZone;
if (timeZone !== 'UTC') {
if (format) {
return tz(date, format, timeZone).utc().valueOf() * divider;
}
else {
return tz(date, timeZone).utc().valueOf() * divider;
}
}
else {
return moment.utc(date).valueOf() * divider;
}
}
/**
* Will hard-shift a timestamp so that, if rendered in current timezone, it will look as it is instead
* into the desired timezone.
*/
static utcToZonedTime(utcTime, divider = 1, timeZone = 'UTC') {
timeZone = timeZone === 'AUTO' ? tz.guess() : timeZone;
const ourTimezone = tz.guess();
const ourOffsetInMillis = tz(moment.utc(utcTime / divider), ourTimezone).utcOffset() * 60000;
const givenTimezoneOffsetInMillis = tz(moment.utc(utcTime / divider), timeZone || 'UTC').utcOffset() * 60000;
return utcTime / divider + givenTimezoneOffsetInMillis - ourOffsetInMillis;
}
/**
* Will revert what utcToZonedTime had done.
*/
static zonedTimeToUtc(zonedTime, divider, timeZone = 'UTC') {
timeZone = timeZone === 'AUTO' ? tz.guess() : timeZone || 'UTC';
const ourTimezone = tz.guess();
const ourOffsetInMillis = tz(moment.utc(zonedTime / divider), ourTimezone).utcOffset() * 60000;
const givenTimezoneOffsetInMillis = tz(moment.utc(zonedTime / divider), timeZone || 'UTC').utcOffset() * 60000;
return zonedTime / divider - givenTimezoneOffsetInMillis + ourOffsetInMillis;
}
static toDuration(time, divider) {
let distance = time / divider;
const hours = Math.floor(distance / 3600000);
distance -= hours * 3600000;
const minutes = Math.floor(distance / 60000);
distance -= minutes * 60000;
const seconds = Math.floor(distance / 1000);
distance -= seconds * 60000;
const ms = distance / 1000.0;
return `${hours}h ${('0' + minutes).slice(-2)}m ${('0' + seconds).slice(-2)}s ${('0' + ms).slice(-2)}ms`;
}
static getName(name) {
if (/^[0-9]+%%%%.*/.test(name)) {
return name.replace(/[0-9]+%%%%/, '');
}
return name;
}
static setName(id, s) {
return `${id}%%%%${s}`;
}
}
GTSLib.LOG = new Logger(GTSLib);
GTSLib.formatLabel = (data) => {
const serializedGTS = data.split('{');
let display = `<span class="gtsInfo"><span class='gts-classname'>${serializedGTS[0]}</span>`;
if (serializedGTS.length > 1) {
display += '<span class=\'gts-separator\'>{</span>';
const labels = serializedGTS[1].substring(0, serializedGTS[1].length - 1).split(',');
if (labels.length > 0) {
labels.forEach((l, i) => {
const label = l.split('=');
if (l.length > 1) {
display += `<span><span class='gts-labelname'>${label[0]}</span>
<span class='gts-separator'>=</span><span class='gts-labelvalue'>${label.slice(1).join('')}</span>`;
if (i !== labels.length - 1) {
display += '<span>, </span>';
}
}
});
}
display += '<span class=\'gts-separator\'>}</span>';
}
if (serializedGTS.length > 2) {
display += '<span class=\'gts-separator\'>{</span>';
const labels = serializedGTS[2].substring(0, serializedGTS[2].length - 1).split(',');
if (labels.length > 0) {
labels.forEach((l, i) => {
const label = l.split('=');
if (l.length > 1) {
display += `<span><span class='gts-attrname'>${label[0]}</span>
<span class='gts-separator'>=</span><span class='gts-attrvalue'>${label.slice(1).join('')}</span>`;
if (i !== labels.length - 1) {
display += '<span>, </span>';
}
}
});
}
display += '<span class=\'gts-separator\'>}</span>';
}
display += '</span>';
return display;
};
//# sourceMappingURL=gts.lib.js.map