UNPKG

@senx/discovery-widgets

Version:

Discovery Widgets Elements

897 lines (896 loc) 33.4 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 { h } from "@stencil/core"; import { DataModel } from "../../model/types"; import { Param } from "../../model/param"; import * as echarts from "echarts"; import { Logger } from "../../utils/logger"; import { GTSLib } from "../../utils/gts.lib"; import { Utils } from "../../utils/utils"; import { ColorLib } from "../../utils/color-lib"; import { v4 } from "uuid"; export class DiscoveryHeatmap { constructor() { this.options = new Param(); this.debug = false; this.language = 'warpscript'; this.vars = '{}'; this.parsing = false; this.rendering = false; this.defOptions = Object.assign(Object.assign({}, new Param()), { timeMode: 'date' }); this.divider = 1000; this.innerWidth = 0; this.innerHeight = 0; this.innerVars = {}; } varsUpdate(newValue, oldValue) { var _a; let vars = this.vars; if (!!this.vars && typeof this.vars === 'string') { vars = JSON.parse(this.vars); } if (!Utils.deepEqual(vars, this.innerVars)) { this.innerVars = Utils.clone(vars); } (_a = this.LOG) === null || _a === void 0 ? void 0 : _a.debug(['varsUpdate'], { vars: this.vars, newValue, oldValue }); } updateType(newValue, oldValue) { if (newValue !== oldValue) { this.chartOpts = this.convert(GTSLib.getData(this.result)); setTimeout(() => { this.myChart.setOption(this.chartOpts || {}, true, false); this.myChart.resize({ height: this.height }); this.setOpts(true); }); } } updateRes() { this.chartOpts = this.convert(GTSLib.getData(this.result)); setTimeout(() => { this.myChart.setOption(this.chartOpts || {}, true, false); this.myChart.resize({ height: this.height }); this.setOpts(true); }); } optionsUpdate(newValue, oldValue) { var _a, _b; (_a = this.LOG) === null || _a === void 0 ? void 0 : _a.debug(['optionsUpdate'], newValue, oldValue); let opts = newValue; if (!!newValue && typeof newValue === 'string') { opts = JSON.parse(newValue); } if (!Utils.deepEqual(opts, this.innerOptions)) { this.innerOptions = Utils.clone(opts); if (this.myChart) { this.chartOpts = this.convert(this.result || new DataModel()); setTimeout(() => { this.myChart.setOption(this.chartOpts || {}, true, false); this.myChart.resize({ height: this.height }); this.setOpts(true); }); } (_b = this.LOG) === null || _b === void 0 ? void 0 : _b.debug(['optionsUpdate 2'], { options: this.innerOptions, newValue, oldValue }, this.chartOpts); } } async resize() { const dims = Utils.getContentBounds(this.el.parentElement); const width = dims.w - 4; const height = dims.h; if (this.myChart && (this.innerWidth !== width || this.innerHeight !== dims.h)) { this.innerWidth = width; this.innerHeight = this.innerHeight !== dims.h ? height - this.el.parentElement.offsetTop : this.innerHeight; this.myChart.resize({ width: this.innerWidth, height: this.innerHeight, silent: true }); } return Promise.resolve(); } async show(regexp) { this.myChart.dispatchAction({ type: 'legendSelect', batch: this.myChart.getOption().series.filter(s => new RegExp(regexp).test(GTSLib.getName(s.name))), }); return Promise.resolve(); } async hide(regexp) { this.myChart.dispatchAction({ type: 'legendUnSelect', batch: this.myChart.getOption().series.filter(s => new RegExp(regexp).test(GTSLib.getName(s.name))), }); return Promise.resolve(); } async hideById(id) { if (this.myChart) { this.myChart.dispatchAction({ type: 'legendUnSelect', batch: this.myChart.getOption().series .filter((s, i) => new RegExp(id.toString()).test((s.id || i).toString())), }); } return Promise.resolve(); } async showById(id) { if (this.myChart) { this.myChart.dispatchAction({ type: 'legendSelect', batch: this.myChart.getOption().series .filter((s, i) => new RegExp(id.toString()).test((s.id || i).toString())), }); } return Promise.resolve(); } // noinspection JSUnusedGlobalSymbols componentWillLoad() { var _a; this.parsing = true; this.LOG = new Logger(DiscoveryHeatmap, this.debug); if (typeof this.options === 'string') { this.innerOptions = JSON.parse(this.options); } else { this.innerOptions = this.options; } this.result = GTSLib.getData(this.result); this.divider = GTSLib.getDivider(this.innerOptions.timeUnit || 'us'); this.chartOpts = this.convert(this.result || new DataModel()); this.setOpts(); (_a = this.LOG) === null || _a === void 0 ? void 0 : _a.debug(['componentWillLoad'], { type: this.type, options: this.innerOptions, chartOpts: this.chartOpts, }); } setOpts(notMerge = false) { var _a; if (!!this.vars && typeof this.vars === 'string') { this.innerVars = JSON.parse(this.vars); } else if (this.vars) { this.innerVars = this.vars; } if ((((_a = this.chartOpts) === null || _a === void 0 ? void 0 : _a.series) || []).length === 0) { this.chartOpts.title = { show: true, textStyle: { color: Utils.getLabelColor(this.el), fontSize: 20 }, text: this.innerOptions.noDataLabel || '', left: 'center', top: 'center', }; this.chartOpts.xAxis = { show: false }; this.chartOpts.yAxis = { show: false }; this.chartOpts.tooltip = { show: false }; } else { this.chartOpts.title = Object.assign(Object.assign({}, this.chartOpts.title || {}), { show: false }); } setTimeout(() => { if (this.myChart) { this.myChart.setOption(this.chartOpts || {}, notMerge, true); } }); } convert(data) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; let options = Utils.mergeDeep(this.defOptions, this.innerOptions || {}); options = Utils.mergeDeep(options || {}, data.globalParams); this.innerOptions = Object.assign({}, options); let series = []; let min = 0; let max = 0; let gtsList; if (GTSLib.isArray(data.data)) { data.data = GTSLib.flatDeep(data.data); (_a = this.LOG) === null || _a === void 0 ? void 0 : _a.debug(['convert', 'isArray']); if (data.data.length > 0 && GTSLib.isGts(data.data[0])) { (_b = this.LOG) === null || _b === void 0 ? void 0 : _b.debug(['convert', 'isArray 2']); gtsList = GTSLib.flattenGtsIdArray(data.data, 0).res; } else { (_c = this.LOG) === null || _c === void 0 ? void 0 : _c.debug(['convert', 'isArray 3']); gtsList = data.data; } } else { (_d = this.LOG) === null || _d === void 0 ? void 0 : _d.debug(['convert', 'not array']); gtsList = [data.data]; } (_e = this.LOG) === null || _e === void 0 ? void 0 : _e.debug(['convert'], { options: this.innerOptions, gtsList }); const isGtsToPlot = gtsList.some(g => GTSLib.isGtsToPlot(g)); const isGtsToAnnotate = gtsList.some(g => GTSLib.isGtsToAnnotate(g)); const isCustomData = gtsList.some(g => !!g.rows && !!g.columns); let res; if (isGtsToPlot) { res = this.convertGtsToPlot(gtsList, data.params); } else if (isGtsToAnnotate) { res = this.convertGtsToAnnotate(gtsList, data.params); } else if (isCustomData) { this.innerOptions.timeMode = 'custom'; res = this.convertCustomData(gtsList); } if (res) { series = res.series; min = res.min; max = res.max; } (_f = this.LOG) === null || _f === void 0 ? void 0 : _f.debug(['convert', 'series'], { series }); const hSeries = series.length > 0 ? [{ type: 'heatmap', data: series, progressive: 10000, animation: false, }] : []; const opts = Object.assign({ grid: { left: 10, top: 10, bottom: 10, right: 10, containLabel: true, }, tooltip: { trigger: 'item', axisPointer: { type: 'shadow', }, backgroundColor: Utils.getCSSColor(this.el, '--warp-view-tooltip-bg-color', 'white'), hideDelay: this.innerOptions.tooltipDelay || 100, formatter: (params) => { var _a; return `<div style="font-size:14px;color:#666;font-weight:400;line-height:1;">${((_a = this.innerOptions.timeMode) !== null && _a !== void 0 ? _a : 'date') === 'date' ? GTSLib.toISOString(GTSLib.toTimestamp(params.value[0], this.divider, this.innerOptions.timeZone), this.divider, this.innerOptions.timeZone, this.innerOptions.fullDateDisplay ? this.innerOptions.timeFormat : undefined).replace('T', ' ').replace('Z', '') : params.value[0]}</div> ${params.marker} <span style="font-size:14px;color:#666;font-weight:400;margin-left:2px">${GTSLib.getName(params.value[1])}</span> <span style="float:right;margin-left:20px;font-size:14px;color:#666;font-weight:900"> ${params.value[2]}</span>`; }, }, toolbox: { show: this.innerOptions.showControls, feature: { saveAsImage: { type: 'png', excludeComponents: ['toolbox'] }, }, }, legend: { bottom: 10, left: 'center', show: false }, visualMap: { show: false, min, max, inRange: { color: ColorLib.getHeatMap(this.innerOptions.scheme) }, }, series: hSeries, xAxis: { show: !this.innerOptions.hideXAxis, type: 'category', splitArea: { show: true }, axisLine: { lineStyle: { color: Utils.getGridColor(this.el), }, }, axisLabel: { hideOverlap: true, color: Utils.getLabelColor(this.el), formatter: value => this.innerOptions.timeMode === 'date' ? GTSLib.toISOString(GTSLib.zonedTimeToUtc(parseInt(value, 10), 1, this.innerOptions.timeZone), 1, this.innerOptions.timeZone, this.innerOptions.timeFormat) .replace('T', '\n').replace(/\+[0-9]{2}:[0-9]{2}$/gi, '') : value, }, axisTick: { lineStyle: { color: Utils.getGridColor(this.el), }, }, }, yAxis: { type: 'category', splitArea: { show: true }, } }, ((_h = (_g = this.innerOptions) === null || _g === void 0 ? void 0 : _g.extra) === null || _h === void 0 ? void 0 : _h.chartOpts) || {}); ((_j = this.innerOptions.actions) !== null && _j !== void 0 ? _j : []).forEach((action) => { var _a, _b; if (action.macro) { opts.toolbox.feature['my' + v4().replaceAll('-', '')] = { title: (_a = action.title) !== null && _a !== void 0 ? _a : '', show: true, icon: (_b = action.icon) !== null && _b !== void 0 ? _b : Utils.DEFICON, onclick: () => Utils.execAction(action.macro, this), }; } }); return opts; } async export(type = 'png') { return Promise.resolve(this.myChart ? this.myChart.getDataURL({ type, excludeComponents: ['toolbox'], }) : undefined); } // noinspection JSUnusedGlobalSymbols componentDidLoad() { setTimeout(() => { this.parsing = false; this.rendering = true; let initial = false; this.myChart = echarts.init(this.graph, null, { width: this.width, height: this.height ? this.height - 10 : undefined, }); this.myChart.on('rendered', () => { this.rendering = false; if (initial) { setTimeout(() => this.draw.emit()); initial = false; } }); this.myChart.on('mouseover', (event) => { this.dataPointOver.emit({ date: event.value[0], name: GTSLib.getName(event.seriesName), value: event.value[1], meta: {}, }); }); this.el.addEventListener('mouseout', () => this.dataPointOver.emit({})); this.myChart.on('click', (event) => { this.dataPointSelected.emit({ date: event.value[0], name: GTSLib.getName(event.seriesName), value: event.value[1], meta: {}, }); }); this.myChart.setOption(this.chartOpts || {}, true, false); initial = true; }); } convertGtsToPlot(gtsList, params) { let series = []; let min = Number.MAX_VALUE; let max = Number.MIN_VALUE; const gtsCount = gtsList.length; for (let i = 0; i < gtsCount; i++) { const gts = gtsList[i]; if (GTSLib.isGtsToPlot(gts) && !!gts.v) { for (const v of (gts.v || [])) { const val = v[v.length - 1]; if (val < min) { min = val; } if (val > max) { max = val; } series.push([ (this.innerOptions.timeMode || 'date') === 'date' ? GTSLib.utcToZonedTime(v[0], this.divider, this.innerOptions.timeZone) : v[0], ((params || [])[i] || { key: undefined }).key || GTSLib.serializeGtsMetadata(gts), val, ]); } } } series = series.sort((a, b) => a[0] - b[0]); return { series, min, max }; } convertGtsToAnnotate(gtsList, params) { let series = []; const min = 0; const max = 1; const gtsCount = gtsList.length; for (let i = 0; i < gtsCount; i++) { const gts = gtsList[i]; if (GTSLib.isGtsToAnnotate(gts) && !!gts.v) { for (const v of (gts.v || [])) { let val = v[v.length - 1]; if (typeof val === 'boolean') { val = val ? 1 : 0; } else { val = 1; } series.push([ (this.innerOptions.timeMode || 'date') === 'date' ? GTSLib.utcToZonedTime(v[0], this.divider, this.innerOptions.timeZone) : v[0], ((params || [])[i] || { key: undefined }).key || GTSLib.serializeGtsMetadata(gts), val, ]); } } } series = series.sort((a, b) => a[0] - b[0]); return { series, min, max }; } convertCustomData(gtsList) { let series = []; let min = 0; let max = 1; const gtsCount = gtsList.length; for (let i = 0; i < gtsCount; i++) { const gts = gtsList[i]; if (!!gts.rows && !!gts.columns) { gts.rows.forEach((r) => { const l = r.length; for (let j = 1; j < l; j++) { const val = r[j]; if (val < min) { min = val; } if (val > max) { max = val; } series.push([gts.columns[j - 1], r[0], val]); } }); } } series = series.sort((a, b) => a[0] - b[0]); return { series, min, max }; } render() { return h("div", { key: 'be6c3eb1d5b2dbc4ff7fd78a5992cfd6c155f24e', class: "heatmap-wrapper" }, this.parsing ? h("discovery-spinner", null, "Parsing data...") : '', this.rendering ? h("discovery-spinner", null, "Rendering data...") : '', h("div", { key: 'a87f8b591f5cbb724d49ed63ab9177f92f1de2b6', ref: (el) => this.graph = el })); } static get is() { return "discovery-heatmap"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["discovery-heatmap.scss"] }; } static get styleUrls() { return { "$": ["discovery-heatmap.css"] }; } static get properties() { return { "result": { "type": "string", "mutable": false, "complexType": { "original": "DataModel | string", "resolved": "DataModel | string", "references": { "DataModel": { "location": "import", "path": "../../model/types", "id": "src/model/types.ts::DataModel" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "result", "reflect": false }, "type": { "type": "string", "mutable": false, "complexType": { "original": "ChartType", "resolved": "string", "references": { "ChartType": { "location": "import", "path": "../../model/types", "id": "src/model/types.ts::ChartType" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "type", "reflect": false }, "options": { "type": "string", "mutable": false, "complexType": { "original": "Param | string", "resolved": "Param | string", "references": { "Param": { "location": "import", "path": "../../model/param", "id": "src/model/param.ts::Param" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "options", "reflect": false, "defaultValue": "new Param()" }, "width": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "width", "reflect": false }, "height": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "height", "reflect": false }, "debug": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "debug", "reflect": false, "defaultValue": "false" }, "unit": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "unit", "reflect": false }, "url": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "url", "reflect": false }, "language": { "type": "string", "mutable": false, "complexType": { "original": "'warpscript' | 'flows'", "resolved": "\"flows\" | \"warpscript\"", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "language", "reflect": false, "defaultValue": "'warpscript'" }, "vars": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "vars", "reflect": false, "defaultValue": "'{}'" } }; } static get states() { return { "parsing": {}, "rendering": {}, "innerOptions": {} }; } static get events() { return [{ "method": "draw", "name": "draw", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "" }, "complexType": { "original": "void", "resolved": "void", "references": {} } }, { "method": "dataPointOver", "name": "dataPointOver", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "dataPointSelected", "name": "dataPointSelected", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "discoveryEvent", "name": "discoveryEvent", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "" }, "complexType": { "original": "DiscoveryEvent", "resolved": "DiscoveryEvent", "references": { "DiscoveryEvent": { "location": "import", "path": "../../model/types", "id": "src/model/types.ts::DiscoveryEvent" } } } }, { "method": "execError", "name": "execError", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }]; } static get methods() { return { "resize": { "complexType": { "signature": "() => Promise<void>", "parameters": [], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<void>" }, "docs": { "text": "", "tags": [] } }, "show": { "complexType": { "signature": "(regexp: string) => Promise<void>", "parameters": [{ "name": "regexp", "type": "string", "docs": "" }], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<void>" }, "docs": { "text": "", "tags": [] } }, "hide": { "complexType": { "signature": "(regexp: string) => Promise<void>", "parameters": [{ "name": "regexp", "type": "string", "docs": "" }], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<void>" }, "docs": { "text": "", "tags": [] } }, "hideById": { "complexType": { "signature": "(id: number | string) => Promise<void>", "parameters": [{ "name": "id", "type": "string | number", "docs": "" }], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<void>" }, "docs": { "text": "", "tags": [] } }, "showById": { "complexType": { "signature": "(id: number | string) => Promise<void>", "parameters": [{ "name": "id", "type": "string | number", "docs": "" }], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<void>" }, "docs": { "text": "", "tags": [] } }, "export": { "complexType": { "signature": "(type?: \"png\" | \"svg\") => Promise<string>", "parameters": [{ "name": "type", "type": "\"svg\" | \"png\"", "docs": "" }], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<string>" }, "docs": { "text": "", "tags": [] } } }; } static get elementRef() { return "el"; } static get watchers() { return [{ "propName": "vars", "methodName": "varsUpdate" }, { "propName": "type", "methodName": "updateType" }, { "propName": "result", "methodName": "updateRes" }, { "propName": "options", "methodName": "optionsUpdate" }]; } } //# sourceMappingURL=discovery-heatmap.js.map