mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-06-02 04:39:28 +00:00
138 lines
4.3 KiB
JavaScript
138 lines
4.3 KiB
JavaScript
// TODO(chris): load events that are longer than the interval without doubling it
|
|
|
|
export function useEventLoader(rangeInterval, getPromiseFunc) {
|
|
let loading_id = 0;
|
|
const events = Vue.ref([]);
|
|
const loadingEvents = Vue.ref([]);
|
|
const allEvents = Vue.computed(() => events.value.concat(loadingEvents.value));
|
|
const lv = Vue.ref(null);
|
|
const eventsLoaded = [];
|
|
|
|
const mergePromiseArr = (n, o) => {
|
|
if (Array.isArray(n))
|
|
return o.concat(n);
|
|
return o.push(n), o;
|
|
};
|
|
|
|
const markEventsLoaded = (start, end) => {
|
|
let result = [];
|
|
if (!eventsLoaded.length) {
|
|
// empty: add new chunk
|
|
eventsLoaded.push(start.ts, end.ts);
|
|
} else {
|
|
if (eventsLoaded[eventsLoaded.length-1] + 1 == start.ts) {
|
|
// add to the end of last chunk
|
|
eventsLoaded[eventsLoaded.length-1] = end.ts;
|
|
} else if (eventsLoaded[eventsLoaded.length-1] < start.ts) {
|
|
// add new chunk after the last chunk
|
|
eventsLoaded.push(start.ts, end.ts);
|
|
} else if (eventsLoaded[0] == end.ts + 1) {
|
|
// add to the start of first chunk
|
|
eventsLoaded[0] = start.ts;
|
|
} else if (eventsLoaded[0] > end.ts) {
|
|
eventsLoaded.unshift(start.ts, end.ts);
|
|
} else {
|
|
let index = eventsLoaded.findIndex(e => e >= start.ts);
|
|
|
|
if (index % 2) {
|
|
// starts inside an existing chunk
|
|
if (eventsLoaded[index] >= end.ts)
|
|
return []; // Already loaded
|
|
|
|
let indexIsLast = (index == eventsLoaded.length - 1);
|
|
|
|
if (indexIsLast || eventsLoaded[index + 1] > end.ts) {
|
|
// extend an existing chunk
|
|
// and merge with the next if necessary
|
|
let nStart = eventsLoaded[index] + 1;
|
|
start = start.plus(nStart - start.ts);
|
|
if (!indexIsLast && eventsLoaded[index + 1] == end.ts + 1)
|
|
eventsLoaded.splice(index, 2);
|
|
else
|
|
eventsLoaded[index] = end.ts;
|
|
} else {
|
|
// merge exising chunks
|
|
// and load the rest if necessary
|
|
if (eventsLoaded[index + 2] < end.ts) {
|
|
let rStart = eventsLoaded[index + 2] + 1;
|
|
result = mergePromiseArr(markEventsLoaded(start.plus(rStart - start.ts), end), result);
|
|
}
|
|
|
|
let nStart = eventsLoaded[index] + 1;
|
|
start = start.plus(nStart - start.ts);
|
|
let nEnd = eventsLoaded[index + 1] - 1;
|
|
end = end.plus(nEnd - end.ts);
|
|
eventsLoaded.splice(index, 2);
|
|
}
|
|
} else {
|
|
// starts between two chunks or before the first
|
|
if (!index) {
|
|
// extend the first chunk
|
|
// and load the rest if necessary
|
|
if (eventsLoaded[1] < end.ts) {
|
|
let rStart = eventsLoaded[1] + 1;
|
|
result = mergePromiseArr(markEventsLoaded(start.plus(rStart - start.ts), end), result);
|
|
}
|
|
let nEnd = eventsLoaded[0] - 1;
|
|
end = end.plus(nEnd - end.ts);
|
|
eventsLoaded[0] = start.ts;
|
|
} else if (eventsLoaded[index] == start.ts) {
|
|
// starts at the same position as an existing chunk
|
|
if (eventsLoaded[index + 1] >= end.ts)
|
|
return []; // Already loaded
|
|
// load the rest
|
|
let rStart = eventsLoaded[index + 1] + 1;
|
|
result = mergePromiseArr(markEventsLoaded(start.plus(rStart - start.ts), end), result);
|
|
} else {
|
|
// extend an existing chunk
|
|
// and load the rest if necessary
|
|
if (eventsLoaded[index + 1] < end.ts) {
|
|
let rStart = eventsLoaded[index + 1] + 1;
|
|
result = mergePromiseArr(markEventsLoaded(start.plus(rStart - start.ts), end), result);
|
|
}
|
|
let nEnd = eventsLoaded[index] - 1;
|
|
end = end.plus(nEnd - end.ts);
|
|
eventsLoaded[index] = start.ts;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (start.ts >= end.ts)
|
|
return result;
|
|
|
|
loadingEvents.value.push({
|
|
loading_id: loading_id++,
|
|
type: "loading",
|
|
isostart: start.toISODate() + 'T' + start.toISOTime(),
|
|
isoend: end.toISODate() + 'T' + end.toISOTime()
|
|
});
|
|
|
|
return mergePromiseArr(getPromiseFunc(start, end), result);
|
|
};
|
|
|
|
Vue.watchEffect(() => {
|
|
const range = Vue.toValue(rangeInterval);
|
|
if (!(range instanceof luxon.Interval))
|
|
return;
|
|
const promises = markEventsLoaded(range.start, range.end);
|
|
Promise
|
|
.allSettled(promises)
|
|
.then(results => {
|
|
results.forEach(res => {
|
|
if (
|
|
res.status === 'fulfilled'
|
|
&& res.value.meta.status === "success"
|
|
) {
|
|
if (res.value.meta.lv)
|
|
lv.value = res.value.meta.lv;
|
|
|
|
events.value = events.value.concat(res.value.data);
|
|
loadingEvents.value = [];
|
|
}
|
|
})
|
|
});
|
|
})
|
|
|
|
return { events: allEvents, lv }
|
|
} |