@eox/chart
Advanced tools
Comparing version 2.0.0-alpha1 to 2.0.0-alpha2
@@ -17,7 +17,28 @@ import { createChart } from "../../src/interface"; | ||
features: [ | ||
["ndvi", "ndwi", "savi", "evi", "nddi"], | ||
["lai", "otci", "fapar"], | ||
[ | ||
"s1_rvi", | ||
"s2_ndvi", | ||
"s2_ndwi", | ||
"s2_mndwi", | ||
"s2_nddi", | ||
"s2_ndmi", | ||
"s2_nbsi", | ||
"s2_evi", | ||
"s2_savi", | ||
"spei", | ||
"pni", | ||
"spi", | ||
], | ||
["s2_vci"], | ||
[ | ||
"modis_ndvi", | ||
"modis_ndwi", | ||
"modis_savi", | ||
"modis_evi", | ||
"modis_nddi", | ||
], | ||
["s3_ndvi", "s3_otci", "s2_lai", "s2_fapar"], | ||
], | ||
active: ["nddi", "ndvi", "ndwi"], | ||
timeAggregation: "week", | ||
active: ["modis_ndvi", "modis_ndwi", "modis_savi"], | ||
// timeAggregation: { week: 1 }, | ||
timeInterval: { | ||
@@ -24,0 +45,0 @@ months: 3, |
@@ -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,t){typeof exports=="object"&&typeof module<"u"?t(exports):typeof define=="function"&&define.amd?define(["exports"],t):(n=typeof globalThis<"u"?globalThis:n||self,t(n.Interface={}))})(this,function(n){"use strict";var u=Object.defineProperty;var f=(n,t,o)=>t in n?u(n,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):n[t]=o;var c=(n,t,o)=>(f(n,typeof t!="symbol"?t+"":t,o),o);const t=new MessageChannel,o=t.port1;class l{constructor(e){c(this,"iframe");this.iframe=e}setData(e){o.postMessage({type:"setData",body:{data:e}})}setSignalsData(e){o.postMessage({type:"setSignalsData",body:{data:e}})}setSignalsEndpoint(e){o.postMessage({type:"setSignalsEndpoint",body:{options:e}})}setSignalsGeometry(e){o.postMessage({type:"setSignalsGeometry",body:{geometry:e}})}setOptions(e){o.postMessage({type:"setOptions",body:{options:e}})}getFoo(){return new Promise(e=>{const s=Date.now();o.onmessage=r=>{r.data.ts===s&&e(r.data.body)},o.postMessage({ts:s,type:"getFoo",body:"hello world"})})}}const p=a=>a?new Promise(e=>{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"),a==null||a.appendChild(s);let r=!1;s.onload=()=>{var d;r||((d=s.contentWindow)==null||d.postMessage("init","*",[t.port2]),r=!0,e(new l(s)))}}):(console.error("no div selected"),null);n.createChart=p,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})}); |
{ | ||
"name": "@eox/chart", | ||
"version": "2.0.0-alpha1", | ||
"version": "2.0.0-alpha2", | ||
"dependencies": { | ||
@@ -5,0 +5,0 @@ "chart.js": "^4.2.1", |
@@ -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,t){typeof exports=="object"&&typeof module<"u"?t(exports):typeof define=="function"&&define.amd?define(["exports"],t):(n=typeof globalThis<"u"?globalThis:n||self,t(n.Interface={}))})(this,function(n){"use strict";var u=Object.defineProperty;var f=(n,t,o)=>t in n?u(n,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):n[t]=o;var c=(n,t,o)=>(f(n,typeof t!="symbol"?t+"":t,o),o);const t=new MessageChannel,o=t.port1;class l{constructor(e){c(this,"iframe");this.iframe=e}setData(e){o.postMessage({type:"setData",body:{data:e}})}setSignalsData(e){o.postMessage({type:"setSignalsData",body:{data:e}})}setSignalsEndpoint(e){o.postMessage({type:"setSignalsEndpoint",body:{options:e}})}setSignalsGeometry(e){o.postMessage({type:"setSignalsGeometry",body:{geometry:e}})}setOptions(e){o.postMessage({type:"setOptions",body:{options:e}})}getFoo(){return new Promise(e=>{const s=Date.now();o.onmessage=r=>{r.data.ts===s&&e(r.data.body)},o.postMessage({ts:s,type:"getFoo",body:"hello world"})})}}const p=a=>a?new Promise(e=>{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"),a==null||a.appendChild(s);let r=!1;s.onload=()=>{var d;r||((d=s.contentWindow)==null||d.postMessage("init","*",[t.port2]),r=!0,e(new l(s)))}}):(console.error("no div selected"),null);n.createChart=p,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})}); |
@@ -19,6 +19,11 @@ import { DateTime } from "luxon"; | ||
this.options = options; | ||
this.generateSelectionOptions(); | ||
this.generateTimeSelectionOptions(); | ||
this.generateTimeAggregationOptions(); | ||
const spinner = document.createElement("span"); | ||
spinner.id = "loadingIndicator"; | ||
spinner.className = "loader hidden"; | ||
this.element.appendChild(spinner); | ||
} | ||
private generateSelectionOptions() { | ||
private generateTimeSelectionOptions() { | ||
const options = [ | ||
@@ -59,3 +64,40 @@ { text: "3 months back", value: "months3" }, | ||
}); | ||
} | ||
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 "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"; | ||
@@ -62,0 +104,0 @@ this.element.appendChild(spinner); |
@@ -27,2 +27,5 @@ const channel = new MessageChannel(); | ||
} | ||
setSignalsGeometry(geometry: object) { | ||
port1.postMessage({ type: "setSignalsGeometry", body: { geometry } }); | ||
} | ||
setOptions(options: object) { | ||
@@ -29,0 +32,0 @@ port1.postMessage({ type: "setOptions", body: { options } }); |
@@ -16,2 +16,4 @@ import Chart, { ChartDataset } from "chart.js/auto"; | ||
let sdmInstance: SignalsDataManager | null = null; | ||
let application: MessagePort; | ||
@@ -43,2 +45,5 @@ | ||
break; | ||
case "setSignalsGeometry": | ||
setSignalsGeometry(event.data.body.options); | ||
break; | ||
case "setSignalsData": | ||
@@ -76,5 +81,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); | ||
sdmInstance.setActiveFields(options.active); | ||
}; | ||
const setSignalsGeometry = (geometry: object) => { | ||
if (sdmInstance) { | ||
sdmInstance.setGeometry(geometry); | ||
} | ||
}; |
@@ -50,2 +50,3 @@ import Chart, { | ||
endTime?: string; | ||
timeAggregation?: object; | ||
} | ||
@@ -57,2 +58,3 @@ | ||
endTime: DateTime; | ||
timeAggregation: object; | ||
options: SDMOptions; | ||
@@ -74,2 +76,5 @@ chartOptions: ChartOptions; | ||
} | ||
if (this.options.timeAggregation) { | ||
this.timeAggregation = this.options.timeAggregation; | ||
} | ||
this.dataStorage = {}; | ||
@@ -97,2 +102,9 @@ // Initialize data storage | ||
legend: { | ||
labels: { | ||
/* | ||
usePointStyle: true, | ||
pointStyle: "line", | ||
*/ | ||
sort: (a, b) => a.text.localeCompare(b.text), | ||
}, | ||
position: "right", | ||
@@ -113,2 +125,15 @@ onClick: (_, legendItem) => { | ||
} | ||
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"; | ||
} | ||
@@ -149,9 +174,11 @@ private fetchSignals(groupIndex: number, start?: DateTime, end?: DateTime) { | ||
}, | ||
retries: 5, | ||
retries: 1, | ||
}).then(function (res) { | ||
return res.json(); | ||
}); | ||
this.checkLoadingStatus(); | ||
} | ||
private updateChart() { | ||
this.checkLoadingStatus(); | ||
this.chart.options = this.chartOptions; | ||
@@ -185,2 +212,58 @@ const datasets: ChartDataset[] = []; | ||
}); | ||
let actualDataAdded = false; | ||
let signalData = <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], | ||
}; | ||
actualDataAdded = true; | ||
} | ||
return ds; | ||
}); | ||
if (actualDataAdded && this.timeAggregation) { | ||
console.log("applying aggregation"); | ||
console.log(signalData); | ||
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; | ||
while ( | ||
currDataIdx < signalData.length && | ||
signalData[currDataIdx].x < currDate | ||
) { | ||
currDataIdx++; | ||
} | ||
const x1 = currDataIdx; | ||
while ( | ||
currDataIdx < signalData.length && | ||
signalData[currDataIdx].x < currDate.plus(this.timeAggregation) | ||
) { | ||
dataSum += signalData[currDataIdx].y; | ||
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) { | ||
// TODO: can we save a time interval here? | ||
aggrData.push({ | ||
x: currDate, | ||
y: dataSum / count, | ||
}); | ||
} | ||
currDate = currDate.plus(this.timeAggregation); | ||
} | ||
signalData = aggrData; | ||
} | ||
datasets.push({ | ||
@@ -191,14 +274,3 @@ // type: "lineWithErrorBars", | ||
// 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], | ||
}; | ||
} | ||
return ds; | ||
}), | ||
data: signalData, | ||
hidden: !this.activeFields.includes(key), | ||
@@ -256,7 +328,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] = { | ||
@@ -272,2 +349,10 @@ request, | ||
setGeometry(geometry: object) { | ||
// Clear all currently saved data | ||
this.dataStorage = {}; | ||
this.options.geometry = geometry; | ||
this.retrieveMissingData(); | ||
this.updateChart(); | ||
} | ||
setActiveFields(activeFields: string[]) { | ||
@@ -287,2 +372,14 @@ this.activeFields = activeFields; | ||
} | ||
setTimeAggregation( | ||
aggregation: { | ||
day?: number; | ||
week?: number; | ||
month?: number; | ||
year?: number; | ||
} | null | ||
) { | ||
this.timeAggregation = aggregation; | ||
this.updateChart(); | ||
} | ||
/* | ||
@@ -289,0 +386,0 @@ setAggregation(aggregation: string) {} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
330514
2524