UNPKG

@senx/discovery-widgets

Version:

Discovery Widgets Elements

459 lines (458 loc) 17.6 kB
/* * 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, '&#123;') .replace(/}/g, '&#125;') .replace(/,/g, '&#44;') .replace(/>/g, '&#62;') .replace(/</g, '&#60;') .replace(/"/g, '&#34;') .replace(/'/g, '&#39;'); } 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}`; } static roundValue(v, decimals) { // round to a number of decimals. used for tooltips, axis... not for the actual values. if (typeof v === 'number') { return Math.round((v + Number.EPSILON) * Math.pow(10, decimals)) / Math.pow(10, decimals); } return v; } } 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