Refactor timeline reflow

pull/37/head
Varun Patil 2022-09-12 11:23:27 -07:00
parent 9e898d5bb5
commit aa10e0f175
1 changed files with 74 additions and 74 deletions

View File

@ -165,7 +165,7 @@ export default {
/** Resizing timer */ /** Resizing timer */
resizeTimer: null, resizeTimer: null,
/** View size reflow timer */ /** View size reflow timer */
viewSizeChangeTimer: null, reflowTimelineTimer: null,
/** Is mobile layout */ /** Is mobile layout */
isMobile: false, isMobile: false,
@ -256,75 +256,7 @@ export default {
this.list.filter(r => !r.head).forEach(row => { this.list.filter(r => !r.head).forEach(row => {
row.size = this.rowHeight; row.size = this.rowHeight;
}); });
this.handleViewSizeChange(); this.reflowTimeline();
},
/** Handle change in rows and view size */
handleViewSizeChange() {
if (this.viewSizeChangeTimer) {
return;
}
this.viewSizeChangeTimer = setTimeout(() => {
this.viewSizeChangeTimer = null;
this.reflowTimeline();
this.viewHeight = this.$refs.recycler.$refs.wrapper.clientHeight;
// Compute timeline tick positions
for (const tick of this.timelineTicks) {
tick.topC = Math.floor((tick.topS + tick.top * this.rowHeight) * this.timelineHeight / this.viewHeight);
}
// Do another pass to figure out which timeline points are visible
// This is not as bad as it looks, it's actually 12*O(n)
// because there are only 12 months in a year
const minGap = parseFloat(getComputedStyle(this.$refs.cursorSt).fontSize) + (this.isMobile ? 5 : 2);
let prevShow = -9999;
for (const [idx, tick] of this.timelineTicks.entries()) {
// You can't see these anyway, why bother?
if (tick.topC < minGap || tick.topC > this.timelineHeight - minGap) {
tick.s = false;
continue;
}
// Will overlap with the previous tick. Skip anyway.
if (tick.topC - prevShow < minGap) {
tick.s = false;
continue;
}
// This is a labelled tick then show it anyway for the sake of best effort
if (tick.text) {
tick.s = true;
prevShow = tick.topC;
continue;
}
// Lookahead for next labelled tick
// If showing this tick would overlap the next one, don't show this one
let i = idx + 1;
while(i < this.timelineTicks.length) {
if (this.timelineTicks[i].text) {
break;
}
i++;
}
if (i < this.timelineTicks.length) {
// A labelled tick was found
const nextLabelledTick = this.timelineTicks[i];
if (tick.topC + minGap > nextLabelledTick.topC &&
nextLabelledTick.topC < this.timelineHeight - minGap) { // make sure this will be shown
tick.s = false;
continue;
}
}
// Show this tick
tick.s = true;
prevShow = tick.topC;
}
}, 0);
}, },
/** /**
@ -531,7 +463,7 @@ export default {
} }
// Fix view height variable // Fix view height variable
this.handleViewSizeChange(); this.reflowTimeline();
this.loading = false; this.loading = false;
}, },
@ -563,8 +495,20 @@ export default {
} }
}, },
/** Create timeline tick data */ /** Re-create timeline tick data in the next frame */
reflowTimeline() { reflowTimeline() {
if (this.reflowTimelineTimer) {
return;
}
this.reflowTimelineTimer = setTimeout(() => {
this.reflowTimelineTimer = null;
this.reflowTimelineNow();
}, 0);
},
/** Re-create timeline tick data */
reflowTimelineNow() {
// Clear timeline // Clear timeline
this.timelineTicks = []; this.timelineTicks = [];
@ -611,6 +555,62 @@ export default {
currTopStatic += this.heads[day.dayid].size; currTopStatic += this.heads[day.dayid].size;
currTopRow += day.rows.size; currTopRow += day.rows.size;
} }
this.viewHeight = this.$refs.recycler.$refs.wrapper.clientHeight;
// Compute timeline tick positions
for (const tick of this.timelineTicks) {
tick.topC = Math.floor((tick.topS + tick.top * this.rowHeight) * this.timelineHeight / this.viewHeight);
}
// Do another pass to figure out which timeline points are visible
// This is not as bad as it looks, it's actually 12*O(n)
// because there are only 12 months in a year
const minGap = parseFloat(getComputedStyle(this.$refs.cursorSt).fontSize) + (this.isMobile ? 5 : 2);
let prevShow = -9999;
for (const [idx, tick] of this.timelineTicks.entries()) {
// You can't see these anyway, why bother?
if (tick.topC < minGap || tick.topC > this.timelineHeight - minGap) {
tick.s = false;
continue;
}
// Will overlap with the previous tick. Skip anyway.
if (tick.topC - prevShow < minGap) {
tick.s = false;
continue;
}
// This is a labelled tick then show it anyway for the sake of best effort
if (tick.text) {
tick.s = true;
prevShow = tick.topC;
continue;
}
// Lookahead for next labelled tick
// If showing this tick would overlap the next one, don't show this one
let i = idx + 1;
while(i < this.timelineTicks.length) {
if (this.timelineTicks[i].text) {
break;
}
i++;
}
if (i < this.timelineTicks.length) {
// A labelled tick was found
const nextLabelledTick = this.timelineTicks[i];
if (tick.topC + minGap > nextLabelledTick.topC &&
nextLabelledTick.topC < this.timelineHeight - minGap) { // make sure this will be shown
tick.s = false;
continue;
}
}
// Show this tick
tick.s = true;
prevShow = tick.topC;
}
}, },
/** /**
@ -702,7 +702,7 @@ export default {
// because one row is always removed in that case // because one row is always removed in that case
// So just reflow the timeline here // So just reflow the timeline here
if (addedRow || spliceCount > 0) { if (addedRow || spliceCount > 0) {
this.handleViewSizeChange(); this.reflowTimeline();
} }
}, },
@ -942,7 +942,7 @@ export default {
}); });
// Reflow timeline // Reflow timeline
this.handleViewSizeChange(); this.reflowTimeline();
}, },
}, },
} }