Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@eox/chart

Package Overview
Dependencies
Maintainers
5
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@eox/chart - npm Package Compare versions

Comparing version 2.0.0-alpha1 to 2.0.0-alpha10

dist/assets/main-ec32ac01.js

2

dist/interface.umd.js

@@ -1,1 +0,1 @@

(function(n,e){typeof exports=="object"&&typeof module<"u"?e(exports):typeof define=="function"&&define.amd?define(["exports"],e):(n=typeof globalThis<"u"?globalThis:n||self,e(n.Interface={}))})(this,function(n){"use strict";var u=Object.defineProperty;var f=(n,e,o)=>e in n?u(n,e,{enumerable:!0,configurable:!0,writable:!0,value:o}):n[e]=o;var c=(n,e,o)=>(f(n,typeof e!="symbol"?e+"":e,o),o);const e=new MessageChannel,o=e.port1;class l{constructor(t){c(this,"iframe");this.iframe=t}setData(t){o.postMessage({type:"setData",body:{data:t}})}setSignalsData(t){o.postMessage({type:"setSignalsData",body:{data:t}})}setSignalsEndpoint(t){o.postMessage({type:"setSignalsEndpoint",body:{options:t}})}setOptions(t){o.postMessage({type:"setOptions",body:{options:t}})}getFoo(){return new Promise(t=>{const s=Date.now();o.onmessage=a=>{a.data.ts===s&&t(a.data.body)},o.postMessage({ts:s,type:"getFoo",body:"hello world"})})}}const p=r=>r?new Promise(t=>{var i;const s=document.createElement("iframe");s.style.cssText="width: 100%; height: 100%; display: block; margin: 0; border: none;",s.setAttribute("src",(i=typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:document.currentScript&&document.currentScript.src||new URL("interface.umd.js",document.baseURI).href)!=null&&i.includes("localhost")?"http://localhost:5173/index.html":"https://www.unpkg.com/@eox/chart/dist/index.html"),s.setAttribute("id","EOxChart"),r==null||r.appendChild(s);let a=!1;s.onload=()=>{var d;a||((d=s.contentWindow)==null||d.postMessage("init","*",[e.port2]),a=!0,t(new l(s)))}}):(console.error("no div selected"),null);n.createChart=p,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})});
(function(n,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(n=typeof globalThis<"u"?globalThis:n||self,s(n.Interface={}))})(this,function(n){"use strict";var v=Object.defineProperty;var S=(n,s,o)=>s in n?v(n,s,{enumerable:!0,configurable:!0,writable:!0,value:o}):n[s]=o;var y=(n,s,o)=>(S(n,typeof s!="symbol"?s+"":s,o),o);const g={name:"@eox/chart",version:"2.0.0-alpha8",dependencies:{"chart.js":"^4.2.1","chartjs-adapter-luxon":"^1.3.1","chartjs-chart-error-bars":"^4.1.2"},devDependencies:{"@eox/eslint-config":"^1.0.0","@types/luxon":"^3.2.0","@typescript-eslint/eslint-plugin":"^5.50.0","@typescript-eslint/parser":"^5.50.0",cypress:"^12.6.0","cypress-vite":"^1.3.0","eslint-plugin-cypress":"^2.12.1","eslint-plugin-typescript":"^0.14.0",install:"^0.13.0",luxon:"^3.3.0",npm:"^9.6.3","p-retry":"^5.1.2","pre-commit":"^1.2.2","start-server-and-test":"^1.15.2",typescript:"^4.9.3",vite:"^4.0.0"},engines:{npm:">=8.0.0",node:">=18.0.0"},files:["dist","scripts","src","typings"],main:"./dist/interface.mjs",scripts:{start:"vite",build:"tsc && vite build --config vite.config.interface.ts && vite build --config vite.config.map.ts",watch:"node scripts/watch.mjs",preview:"vite preview",format:"prettier --write .",lint:"eslint --ext .js,.ts .","lint:fix":"eslint --ext .js,.ts . --fix",cypress:"start-server-and-test start 5173 'cypress open'",test:"start-server-and-test start 5173 'cypress run'"},"pre-commit":["format","lint:fix"]},d=new MessageChannel,i=d.port1;class b{constructor(e){y(this,"iframe");this.iframe=e}setData(e){i.postMessage({type:"setData",body:{data:e}})}setSignalsData(e){i.postMessage({type:"setSignalsData",body:{data:e}})}setSignalsEndpoint(e){i.postMessage({type:"setSignalsEndpoint",body:{options:e}})}setSignalsGeometry(e){i.postMessage({type:"setSignalsGeometry",body:{geometry:e}})}setOptions(e){i.postMessage({type:"setOptions",body:{options:e}})}getFoo(){return new Promise(e=>{const t=Date.now();i.onmessage=c=>{c.data.ts===t&&e(c.data.body)},i.postMessage({ts:t,type:"getFoo",body:"hello world"})})}}const w=r=>r?new Promise(e=>{var l,u;const t=document.createElement("iframe");if(t.style.cssText="width: 100%; height: 100%; display: block; margin: 0; border: none;",t.setAttribute("src",(l=typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:document.currentScript&&document.currentScript.src||new URL("interface.umd.js",document.baseURI).href)!=null&&l.includes("localhost")?"http://localhost:5173/index.html":"about:blank"),t.setAttribute("id","EOxChart"),r==null||r.appendChild(t),!((u=typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:document.currentScript&&document.currentScript.src||new URL("interface.umd.js",document.baseURI).href)!=null&&u.includes("localhost"))){const a=`https://www.unpkg.com/@eox/chart@${g.version}/dist`;fetch(`${a}/index.html`).then(p=>p.text()).then(p=>{var f,m,h;const x=p.replace("./assets/",`${a}/assets/`);(f=t.contentDocument)==null||f.open(),(m=t.contentDocument)==null||m.write(x),(h=t.contentDocument)==null||h.close()})}let c=!1;t.onload=()=>{var a;c||((a=t.contentWindow)==null||a.postMessage("init","*",[d.port2]),c=!0,e(new b(t)))}}):(console.error("no div selected"),null);n.createChart=w,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})});
{
"name": "@eox/chart",
"version": "2.0.0-alpha1",
"version": "2.0.0-alpha10",
"dependencies": {
"chart.js": "^4.2.1",
"chartjs-adapter-luxon": "^1.3.1",
"chartjs-chart-error-bars": "^4.1.1"
"chartjs-chart-error-bars": "^4.1.2"
},

@@ -31,2 +31,9 @@ "devDependencies": {

},
"files": [
"dist",
"scripts",
"src",
"typings"
],
"main": "./dist/interface.mjs",
"scripts": {

@@ -33,0 +40,0 @@ "start": "vite",

@@ -10,1 +10,9 @@ # Chart widget

```
## Contribute
```
npm version <new version>
npm run build
npm publish (requires OTP)
```
import { DateTime } from "luxon";
import SignalsDataManager from "./signalsDataManager";
import SignalsDataManager, { SDMOptions } from "./signalsDataManager";

@@ -9,2 +9,3 @@ export interface ChartControlOptions {}

sdm: SignalsDataManager;
sdmOptions: SDMOptions;
options?: ChartControlOptions;

@@ -15,2 +16,3 @@

sdm: SignalsDataManager,
sdmOptions: SDMOptions,
options?: ChartControlOptions

@@ -20,13 +22,118 @@ ) {

this.sdm = sdm;
this.sdm.on("ready", (info) => {
console.log(info);
});
this.options = options;
this.generateSelectionOptions();
this.sdmOptions = sdmOptions;
this.generateTimeAggregationOptions();
this.addNormalizeCheckbox();
this.addShowMinMax();
this.addCSVDownload();
this.generateTimeSelectionOptions();
const spinner = document.createElement("span");
spinner.id = "loadingIndicator";
spinner.className = "loader hidden";
this.element.appendChild(spinner);
}
private generateSelectionOptions() {
private createMessagesElements() {
const messages = document.createElement("div");
messages.id = "messages";
this.element.appendChild(messages);
}
private removeStartEndInputs() {
const start = document.getElementById("startInput");
const end = document.getElementById("endInput");
const button = document.getElementById("setTime");
if (start && end && button) {
start.remove();
end.remove();
button.remove();
}
}
private addStartEndInputs() {
const startEl = document.createElement("input");
startEl.id = "startInput";
startEl.size = 8;
startEl.value = this.sdm.startTime.toISODate();
const endEl = document.createElement("input");
endEl.id = "endInput";
endEl.size = 8;
endEl.value = this.sdm.endTime.toISODate();
this.element.appendChild(startEl);
this.element.appendChild(endEl);
var button = document.createElement("button");
button.id = "setTime";
button.textContent = "ok";
this.element.appendChild(button);
button.addEventListener("click", () => {
const startDate = DateTime.fromISO(startEl.value);
const endDate = DateTime.fromISO(endEl.value);
if (startDate.isValid && endDate.isValid) {
this.sdm.setTimeInterval(startDate, endDate);
this.removeStartEndInputs();
} else {
startEl.className = startDate.isValid ? "" : "parsingError";
endEl.className = endDate.isValid ? "" : "parsingError";
}
});
}
private addNormalizeCheckbox() {
var checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.id = "normalize";
checkbox.value = "normalize";
checkbox.checked = this.sdmOptions.normalize;
var label = document.createElement("label");
label.htmlFor = "normalize";
label.appendChild(document.createTextNode("normalize"));
this.element.appendChild(label);
this.element.appendChild(checkbox);
checkbox.addEventListener("change", () => {
this.sdm.setNormalize(checkbox.checked);
});
}
private addShowMinMax() {
var checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.id = "showMinMax";
checkbox.value = "showMinMax";
checkbox.checked = this.sdmOptions.showMinMax;
var label = document.createElement("label");
label.htmlFor = "showMinMax";
label.appendChild(document.createTextNode("show min/max"));
this.element.appendChild(label);
this.element.appendChild(checkbox);
checkbox.addEventListener("change", () => {
this.sdm.setShowMinMax(checkbox.checked);
});
}
private addCSVDownload() {
var button = document.createElement("button");
button.id = "csvDownload";
button.textContent = "download csv";
this.element.appendChild(button);
button.addEventListener("click", () => {
this.sdm.triggerCSVDownload();
});
}
private generateTimeSelectionOptions() {
const options = [
{ text: "3 months back", value: "months3" },
{ text: "6 months back", value: "months6" },
{ text: "1 year back", value: "year1" },
{ text: "2 years back", value: "year2" },
{ text: "3 years back", value: "year3" },
{ text: "3 months back", value: "month-3" },
{ text: "6 months back", value: "month-6" },
{ text: "1 year back", value: "year-1" },
{ text: "2 years back", value: "year-2" },
{ text: "3 years back", value: "year-3" },
{ text: "custom", value: "custom" },
];

@@ -43,21 +150,60 @@ const selectEl = document.createElement("select");

const currDate = DateTime.now();
switch ((evt.target as HTMLSelectElement).value) {
case "months3":
this.sdm.setTimeInterval(currDate.minus({ months: 3 }), currDate);
const [type, val] = (evt.target as HTMLSelectElement).value.split("-");
this.removeStartEndInputs();
switch (type) {
case "month":
this.sdm.setTimeInterval(
currDate.minus({ month: Number(val) }),
currDate
);
break;
case "months6":
this.sdm.setTimeInterval(currDate.minus({ months: 6 }), currDate);
case "year":
this.sdm.setTimeInterval(
currDate.minus({ year: Number(val) }),
currDate
);
break;
case "year1":
this.sdm.setTimeInterval(currDate.minus({ years: 1 }), currDate);
case "custom":
this.addStartEndInputs();
break;
case "year2":
this.sdm.setTimeInterval(currDate.minus({ years: 2 }), currDate);
}
});
}
private generateTimeAggregationOptions() {
const options = [
{ text: "no aggregation", value: "none" },
{ text: "1 week", value: "week-1" },
{ text: "2 weeks", value: "week-2" },
{ text: "1 month", value: "month-1" },
{ text: "3 months", value: "month-3" },
{ text: "6 months", value: "month-6" },
];
const selectEl = document.createElement("select");
options.forEach((entry) => {
const option = document.createElement("option");
option.text = entry.text;
option.value = entry.value;
selectEl.appendChild(option);
});
this.element.appendChild(selectEl);
selectEl.addEventListener("change", (evt) => {
const [type, val] = (evt.target as HTMLSelectElement).value.split("-");
switch (type) {
case "none":
this.sdm.setTimeAggregation(null);
break;
case "year3":
this.sdm.setTimeInterval(currDate.minus({ years: 3 }), currDate);
case "week":
this.sdm.setTimeAggregation({ week: Number(val) });
break;
case "month":
this.sdm.setTimeAggregation({ month: Number(val) });
break;
case "year":
this.sdm.setTimeAggregation({ year: Number(val) });
break;
}
});
const spinner = document.createElement("span");
spinner.id = "loadingIndicator";
spinner.className = "loader hidden";

@@ -64,0 +210,0 @@ this.element.appendChild(spinner);

@@ -0,1 +1,3 @@

import pkg from "../package.json";
const channel = new MessageChannel();

@@ -24,5 +26,9 @@ const port1 = channel.port1;

endTime?: string;
colors?: string[];
}) {
port1.postMessage({ type: "setSignalsEndpoint", body: { options } });
}
setSignalsGeometry(geometry: object) {
port1.postMessage({ type: "setSignalsGeometry", body: { geometry } });
}
setOptions(options: object) {

@@ -57,6 +63,19 @@ port1.postMessage({ type: "setOptions", body: { options } });

? "http://localhost:5173/index.html"
: "https://www.unpkg.com/@eox/chart/dist/index.html"
: "about:blank"
);
iframe.setAttribute("id", "EOxChart");
div?.appendChild(iframe);
if (!import.meta?.url?.includes("localhost")) {
const hostUrl = `https://www.unpkg.com/@eox/chart@${pkg.version}/dist`;
fetch(`${hostUrl}/index.html`)
.then((response) => {
return response.text();
})
.then((text) => {
const html = text.replace("./assets/", `${hostUrl}/assets/`);
iframe.contentDocument?.open();
iframe.contentDocument?.write(html);
iframe.contentDocument?.close();
});
}
let iframeLoaded = false;

@@ -63,0 +82,0 @@ iframe.onload = () => {

@@ -13,5 +13,30 @@ import Chart, { ChartDataset } from "chart.js/auto";

},
plugins: [
{
id: "selectionLineHighlight",
afterDraw: (chart) => {
if (chart && chart.tooltip) {
const active = chart.tooltip.getActiveElements();
if (active?.length) {
let x = active[0].element.x;
let yAxis = chart.scales.y;
let ctx = chart.ctx;
ctx.save();
ctx.beginPath();
ctx.moveTo(x, yAxis.top);
ctx.lineTo(x, yAxis.bottom);
ctx.lineWidth = 1;
ctx.strokeStyle = "rgba(0, 0, 255, 0.4)";
ctx.stroke();
ctx.restore();
}
}
},
},
],
}
);
let sdmInstance: SignalsDataManager | null = null;
let application: MessagePort;

@@ -43,2 +68,5 @@

break;
case "setSignalsGeometry":
setSignalsGeometry(event.data.body.options);
break;
case "setSignalsData":

@@ -76,5 +104,11 @@ eoxchart.data = {

}) => {
const sdm = new SignalsDataManager(eoxchart, options);
new ChartControls(document.getElementById("controls"), sdm);
sdm.setActiveFields(options.active);
sdmInstance = new SignalsDataManager(eoxchart, options);
new ChartControls(document.getElementById("controls"), sdmInstance, options);
sdmInstance.setActiveFields(options.active);
};
const setSignalsGeometry = (geometry: object) => {
if (sdmInstance) {
sdmInstance.setGeometry(geometry);
}
};
import Chart, {
ChartDataset /*, LinearScale, CategoryScale */,
ChartDataset,
LinearScale,
CategoryScale,
ChartOptions,

@@ -7,3 +9,3 @@ } from "chart.js/auto";

import { DateTime } from "luxon";
/*
import {

@@ -17,2 +19,4 @@ LineWithErrorBarsController,

import { EventEmitter } from "events";
Chart.register(

@@ -26,3 +30,3 @@ LineWithErrorBarsController,

CategoryScale
);*/
);

@@ -45,2 +49,7 @@ type status = "ready" | "loading" | "error";

interface yAxisObject {
id: "string";
containedSignals: string[];
}
export interface SDMOptions {

@@ -54,8 +63,15 @@ source: string;

endTime?: string;
timeAggregation?: object;
retries?: number;
normalize?: boolean;
showMinMax?: boolean;
colors?: string[];
additionalYAxis?: yAxisObject[];
}
class SignalsDataManager {
class SignalsDataManager extends EventEmitter {
chart: Chart;
startTime: DateTime;
endTime: DateTime;
timeAggregation: object;
options: SDMOptions;

@@ -66,4 +82,6 @@ chartOptions: ChartOptions;

activeFields: string[];
additionalYAxis: yAxisObject[] | null;
constructor(chart: Chart, options: SDMOptions) {
super();
this.chart = chart;

@@ -78,2 +96,15 @@ this.options = options;

}
if (this.options.timeAggregation) {
this.timeAggregation = this.options.timeAggregation;
}
this.options.retries = this.options.retries ? this.options.retries : 5;
this.options.normalize = this.options.normalize
? this.options.normalize
: false;
this.options.showMinMax = this.options.showMinMax
? this.options.showMinMax
: false;
this.additionalYAxis = this.options.additionalYAxis
? this.options.additionalYAxis
: null;
this.dataStorage = {};

@@ -94,9 +125,16 @@ // Initialize data storage

},
/*y: {
min: 0,
max: 0.5,
},*/
},
interaction: {
axis: "x",
mode: "nearest",
intersect: false,
},
plugins: {
legend: {
labels: {
usePointStyle: true,
pointStyle: "rect",
padding: 5,
sort: (a, b) => a.text.localeCompare(b.text),
},
position: "right",

@@ -114,6 +152,43 @@ onClick: (_, legendItem) => {

},
tooltip: {
callbacks: {
title: (tooltipItem) => {
const raw: any = tooltipItem[0]?.raw;
return raw.x.toISODate();
},
label: (tooltipItem) => {
const raw: any = tooltipItem.raw;
return `${tooltipItem.dataset.label}: ↔ ${raw.y.toPrecision(
3
)}; ↓ ${raw.yMin.toPrecision(3)}, ↑ ${raw.yMax.toPrecision(3)}`;
},
},
},
},
};
// Adding possible additional y axis scales
for (let index = 0; index < this.additionalYAxis.length; index++) {
const scale = this.additionalYAxis[index];
this.chartOptions.scales[scale.id] = {
type: "linear",
position: "right",
};
}
this.emit("ready", "someinfo");
}
private checkLoadingStatus() {
const spinner = document.getElementById("loadingIndicator");
let loading = false;
// TODO: Showing when error state happened
Object.keys(this.dataStorage).forEach((_, groupIdx) => {
Object.keys(this.dataStorage[groupIdx]).forEach((timeKey) => {
if (this.dataStorage[groupIdx][timeKey].status === "fetching") {
loading = true;
}
});
});
spinner.className = loading ? "loader" : "loader hidden";
}
private fetchSignals(groupIndex: number, start?: DateTime, end?: DateTime) {

@@ -152,13 +227,16 @@ const features = this.options.features[groupIndex]

);
throw new Error();
},
retries: 5,
retries: this.options.retries,
}).then(function (res) {
return res.json();
});
this.checkLoadingStatus();
}
private updateChart() {
this.checkLoadingStatus();
this.chart.options = this.chartOptions;
const datasets: ChartDataset[] = [];
this.options.features.flat().forEach((key) => {
this.options.features.flat().forEach((key, dsIndex) => {
// Find group

@@ -189,21 +267,145 @@ let groupIndex: number = -1;

});
datasets.push({
// type: "lineWithErrorBars",
let actualDataAdded = false;
let max = Number.MIN_VALUE;
let min = Number.MAX_VALUE;
let signalData = <any>data.map((datapoint) => {
let ds = {};
if (datapoint && datapoint.date !== "missing") {
const stats = datapoint.basicStats;
if (this.options.showMinMax) {
min = stats.min < min ? stats.min : min;
max = stats.max > max ? stats.max : max;
} else {
min = stats.mean < min ? stats.mean : min;
max = stats.mean > max ? stats.mean : max;
}
ds = {
x: DateTime.fromISO(datapoint.date).setZone("UTC"),
y: datapoint.basicStats.mean,
yMin: datapoint.basicStats.min,
yMax: datapoint.basicStats.max,
};
actualDataAdded = true;
}
return ds;
});
if (actualDataAdded && this.timeAggregation) {
// If we aggregate data we recalculate min max so we reset it
max = Number.MIN_VALUE;
min = Number.MAX_VALUE;
const aggrData = [];
let currDataIdx = 0;
let currDate = DateTime.fromObject({
year: this.startTime.year,
month: this.startTime.month,
day: this.startTime.day,
});
while (currDate < this.endTime) {
let dataSum = 0;
let minSum = 0;
let maxSum = 0;
while (
currDataIdx < signalData.length &&
(Object.keys(signalData[currDataIdx]).length === 0 ||
signalData[currDataIdx].x < currDate)
) {
currDataIdx++;
}
const x1 = currDataIdx;
while (
currDataIdx < signalData.length &&
(Object.keys(signalData[currDataIdx]).length === 0 ||
signalData[currDataIdx].x < currDate.plus(this.timeAggregation))
) {
const sd = signalData[currDataIdx];
dataSum += sd.y;
minSum += sd.yMin;
maxSum += sd.yMax;
currDataIdx++;
}
const x2 = currDataIdx;
const count = x2 - x1;
// If datapoints are within the interval we push the aggregation to the aggregated data
if (count > 0) {
const yMean = dataSum / count;
const yMinMean = minSum / count;
const yMaxMean = maxSum / count;
if (this.options.showMinMax) {
min = yMinMean < min ? yMinMean : min;
max = yMaxMean > max ? yMaxMean : max;
} else {
min = yMean < min ? yMean : min;
max = yMean > max ? yMean : max;
}
// TODO: can we save a time interval here?
aggrData.push({
x: currDate,
y: yMean,
yMin: yMinMean,
yMax: yMaxMean,
});
}
currDate = currDate.plus(this.timeAggregation);
}
signalData = aggrData;
}
if (actualDataAdded && this.options.normalize) {
signalData = signalData.map(
(dp: { x: DateTime; y: number; yMin: number; yMax: number }) => {
dp.y = (dp.y - min) / (max - min);
dp.yMin = (dp.yMin - min) / (max - min);
dp.yMax = (dp.yMax - min) / (max - min);
return dp;
}
);
}
let ds: ChartDataset = {
type: "line",
label: key,
// casting to any because an array of object should also be possible
data: <any>data.map((datapoint) => {
let ds = {};
if (datapoint && datapoint.date !== "missing") {
ds = {
x: DateTime.fromISO(datapoint.date).setZone("UTC"),
y: datapoint.basicStats.mean,
yMin: [datapoint.basicStats.min],
yMax: [datapoint.basicStats.max],
};
data: signalData,
hidden: !this.activeFields.includes(key),
};
if (this.options.showMinMax) {
ds = {
type: "lineWithErrorBars",
label: key,
data: signalData,
hidden: !this.activeFields.includes(key),
errorBarWhiskerLineWidth: 2,
errorBarColor: "#00000000",
};
}
if (this.options.colors && this.options.colors.length >= dsIndex) {
const color = this.options.colors[dsIndex];
ds.backgroundColor = color;
ds.borderColor = color;
if (this.options.showMinMax) {
ds = {
type: "lineWithErrorBars",
label: key,
data: signalData,
hidden: !this.activeFields.includes(key),
errorBarWhiskerLineWidth: 2,
errorBarColor: "#00000000",
errorBarWhiskerColor: color,
errorBarWhiskerSize: 10,
backgroundColor: color,
borderColor: color,
};
}
}
// Check if additional y axis should be used
if (this.additionalYAxis !== null) {
for (let index = 0; index < this.additionalYAxis.length; index++) {
const axis = this.additionalYAxis[index];
if (axis.containedSignals.includes(key)) {
ds.yAxisID = axis.id;
}
return ds;
}),
hidden: !this.activeFields.includes(key),
});
}
}
datasets.push(ds);
}

@@ -259,7 +461,12 @@ });

.minus({ second: 1 })
).then((data) => {
this.dataStorage[index][timeslot].data = data;
this.dataStorage[index][timeslot].status = "finished";
this.updateChart();
});
)
.then((data) => {
this.dataStorage[index][timeslot].data = data;
this.dataStorage[index][timeslot].status = "finished";
this.updateChart();
})
.catch(() => {
this.dataStorage[index][timeslot].status = "failed";
this.updateChart();
});
this.dataStorage[index][timeslot] = {

@@ -275,2 +482,97 @@ request,

triggerCSVDownload() {
const completeData: {
date: string;
basicStats?: { mean: number; min: number; max: number };
}[][] = [];
const headers: string[] = [];
const allSignals = this.activeFields;
allSignals.forEach((key, signalIdx) => {
// Find group
let groupIndex: number = -1;
this.options.features.forEach((group, idx) => {
if (group.includes(key)) {
groupIndex = idx;
}
});
if (groupIndex !== -1) {
let data: {
date: string;
basicStats?: { mean: number; min: number; max: number };
}[] = [];
Object.keys(this.dataStorage[groupIndex]).forEach((timekey) => {
const dsEntry = this.dataStorage[groupIndex][timekey];
if (dsEntry.status === "finished") {
if (
Object.keys(dsEntry.data).length !== 0 &&
Object.keys(dsEntry.data).includes(key)
) {
data.push(...dsEntry.data[key]);
}
}
});
if (data.length > 0) {
headers.push(allSignals[signalIdx]);
completeData.push(data);
}
}
});
// We need to try and bring the different timed datasets into "same timegrid" lets do some binning
const binnedData: {
[key: string]: {
[key: string]: {
mean: number;
max: number;
min: number;
};
};
} = {};
headers.forEach((datakey, idx) => {
completeData[idx].forEach((dp) => {
if (binnedData[dp.date]) {
binnedData[dp.date][datakey] = dp.basicStats;
} else {
binnedData[dp.date] = {};
binnedData[dp.date][datakey] = dp.basicStats;
}
});
});
// Now we try to construct the csv adding empty values when timestamp not available for a dataset
let csv = "time,";
const allHeaders = headers.map((val) => [val, `${val}_max`, `${val}_min`]);
csv += allHeaders.flat().join(",");
csv += "\n";
Object.keys(binnedData).forEach((dateKey) => {
const row: (string | number)[] = [dateKey];
headers.forEach((signalKey) => {
const stats = binnedData[dateKey][signalKey]
? binnedData[dateKey][signalKey]
: null;
if (stats != null) {
row.push(...[stats.mean, stats.max, stats.min]);
} else {
row.push(...["", "", ""]);
}
});
csv += row.join(",");
csv += "\n";
});
var hiddenElement = document.createElement("a");
hiddenElement.href = "data:text/csv;charset=utf-8," + encodeURI(csv);
hiddenElement.target = "_blank";
hiddenElement.download = "chart_data.csv";
hiddenElement.click();
}
setGeometry(geometry: object) {
// Clear all currently saved data
this.dataStorage = {};
// Initialize data storage
this.options.features.forEach((_, idx) => (this.dataStorage[idx] = {}));
this.options.geometry = geometry;
this.retrieveMissingData();
this.updateChart();
}
setActiveFields(activeFields: string[]) {

@@ -290,2 +592,24 @@ this.activeFields = activeFields;

}
setNormalize(normalize: boolean) {
this.options.normalize = normalize;
this.updateChart();
}
setShowMinMax(showMinMax: boolean) {
this.options.showMinMax = showMinMax;
this.updateChart();
}
setTimeAggregation(
aggregation: {
day?: number;
week?: number;
month?: number;
year?: number;
} | null
) {
this.timeAggregation = aggregation;
this.updateChart();
}
/*

@@ -292,0 +616,0 @@ setAggregation(aggregation: string) {}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc