Initial web components
This commit is contained in:
parent
bfaa701f18
commit
5f80f9e816
6 changed files with 407 additions and 1 deletions
176
lib/timeseries.js
Normal file
176
lib/timeseries.js
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
export class Timeseries {
|
||||
constructor(id, endDate, days = 7, slots = 24) {
|
||||
this.id = id;
|
||||
this.endDate = endDate;
|
||||
this.startDate = this.getStartDate(endDate, days);
|
||||
this.days = this.getDays();
|
||||
this.slots = slots;
|
||||
}
|
||||
|
||||
getStartDate(endDate, days) {
|
||||
const startDate = new Date();
|
||||
startDate.setDate(startDate.getDate() - days);
|
||||
startDate.setHours(0, 0, 0);
|
||||
return startDate;
|
||||
}
|
||||
|
||||
getDays() {
|
||||
return Math.ceil((this.endDate - this.startDate) / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
|
||||
prepareSlots(defaultValue = 0) {
|
||||
const timeSlots = [];
|
||||
for (let i = 0; i < this.days; i++) {
|
||||
const daySlot = [];
|
||||
for (let ii = 0; ii < this.slots; ii++) {
|
||||
daySlot.push(defaultValue);
|
||||
}
|
||||
timeSlots.push(daySlot);
|
||||
}
|
||||
return timeSlots;
|
||||
}
|
||||
|
||||
getDayLabels() {
|
||||
const weekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||
const labels = [];
|
||||
const day = new Date(this.startDate.getTime());
|
||||
for (let i = 0; i < this.days; i++) {
|
||||
labels.push(`${day.getDate()} ${weekDays[day.getDay()]}`);
|
||||
day.setHours(day.getHours() + 24);
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
|
||||
getSlotLabels() {
|
||||
const labels = [];
|
||||
const day = new Date(this.startDate.getTime());
|
||||
const pad = (time) => {
|
||||
let val = `${time}`;
|
||||
if (val.length === 1) {
|
||||
val = `0${time}`;
|
||||
}
|
||||
return val;
|
||||
};
|
||||
|
||||
day.setHours(0, 0, 0);
|
||||
for (let i = 0; i < this.slots; i++) {
|
||||
const from = day.getHours();
|
||||
day.setHours(day.getHours() + (24 / this.slots));
|
||||
let to = day.getHours();
|
||||
if (to === 0) {
|
||||
to = 24;
|
||||
}
|
||||
if (this.slots === 24) {
|
||||
labels.push(`${pad(from)}`);
|
||||
} else {
|
||||
labels.push(`${pad(from)}-${pad(to)}`);
|
||||
}
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
|
||||
parseValue(val) {
|
||||
if (typeof val === 'boolean') {
|
||||
if (val) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return parseFloat(val);
|
||||
}
|
||||
|
||||
flattenData(data, fromDay = 0, fromHour = 0) {
|
||||
const flattened = [];
|
||||
data.forEach((dayData, dayIdx) => {
|
||||
if (dayIdx < fromDay) {
|
||||
return;
|
||||
}
|
||||
dayData.forEach((point, hourIdx) => {
|
||||
if (dayIdx === fromDay && hourIdx <= fromHour) {
|
||||
return;
|
||||
}
|
||||
flattened.push(point);
|
||||
});
|
||||
});
|
||||
|
||||
return flattened;
|
||||
}
|
||||
|
||||
mapData(data, options) {
|
||||
const slots = this.prepareSlots(null);
|
||||
data.forEach((point) => {
|
||||
const pointDate = new Date(point.timestamp);
|
||||
const pointValue = this.parseValue(point.value);
|
||||
const daySlot = Math.floor((pointDate - this.startDate) / (1000 * 60 * 60 * 24));
|
||||
const timeSlot = Math.floor(pointDate.getHours() / (24 / this.slots));
|
||||
if (slots[daySlot][timeSlot] === null) {
|
||||
slots[daySlot][timeSlot] = 0;
|
||||
}
|
||||
if (options.accumulate) {
|
||||
slots[daySlot][timeSlot] += pointValue;
|
||||
} else {
|
||||
slots[daySlot][timeSlot] = Math.max(pointValue, slots[daySlot][timeSlot]);
|
||||
}
|
||||
});
|
||||
|
||||
// Deal with slots without data
|
||||
let prevVal = 0;
|
||||
slots.forEach((dayData, dayIdx) => {
|
||||
let prevValIdx = 0;
|
||||
const dayVals = dayData;
|
||||
dayVals.forEach((val, idx) => {
|
||||
if (val !== null) {
|
||||
prevVal = val;
|
||||
prevValIdx = idx;
|
||||
return;
|
||||
}
|
||||
if (options.interpolate) {
|
||||
const flattened = this.flattenData(slots, dayIdx, idx);
|
||||
for (let nextSlot = 0; nextSlot < flattened.length; nextSlot++) {
|
||||
if (flattened[nextSlot] === null) {
|
||||
continue;
|
||||
}
|
||||
const nextVal = flattened[nextSlot];
|
||||
if (nextVal === prevVal) {
|
||||
dayVals[idx] = prevVal;
|
||||
return;
|
||||
}
|
||||
let difference = 0;
|
||||
if (nextVal > prevVal) {
|
||||
difference = nextVal - prevVal;
|
||||
} else {
|
||||
difference = prevVal - nextVal;
|
||||
}
|
||||
const distance = nextSlot;
|
||||
let totalDistance = (nextSlot + idx) - prevValIdx;
|
||||
if (totalDistance < 1) {
|
||||
totalDistance = 1;
|
||||
}
|
||||
dayVals[idx] = Math.max(((difference / totalDistance) * distance) + nextVal, 0);
|
||||
return;
|
||||
}
|
||||
dayVals[idx] = 0;
|
||||
return;
|
||||
}
|
||||
if (options.usePreviousValue) {
|
||||
dayVals[idx] = prevVal;
|
||||
return;
|
||||
}
|
||||
dayVals[idx] = 0;
|
||||
});
|
||||
});
|
||||
return slots;
|
||||
}
|
||||
|
||||
getUrl() {
|
||||
return `http://openmct.cbrp3.c-base.org/telemetry/${this.id}?start=${this.startDate.getTime()}&end=${this.endDate.getTime()}`;
|
||||
}
|
||||
|
||||
getData(options) {
|
||||
return fetch(this.getUrl())
|
||||
.then(data => data.json())
|
||||
.then(data => this.mapData(data, options));
|
||||
}
|
||||
}
|
||||
|
||||
export default Timeseries;
|
||||
Loading…
Add table
Add a link
Reference in a new issue