refactor: make scroller use rows

cache
Varun Patil 2022-10-15 10:41:49 -07:00
parent b31146097e
commit d4a487ffc9
3 changed files with 55 additions and 64 deletions

View File

@ -22,7 +22,7 @@
<div v-for="tick of visibleTicks" :key="tick.dayId" <div v-for="tick of visibleTicks" :key="tick.dayId"
class="tick" class="tick"
:class="{ 'dash': !tick.text }" :class="{ 'dash': !tick.text }"
:style="{ top: tick.topC + 'px' }"> :style="{ top: tick.top + 'px' }">
<span v-if="tick.text">{{ tick.text }}</span> <span v-if="tick.text">{{ tick.text }}</span>
</div> </div>
@ -31,7 +31,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Mixins, Prop } from 'vue-property-decorator'; import { Component, Mixins, Prop } from 'vue-property-decorator';
import { IDay, IHeadRow, ITick } from '../types'; import { IDay, IHeadRow, IRow, IRowType, ITick } from '../types';
import GlobalMixin from '../mixins/GlobalMixin'; import GlobalMixin from '../mixins/GlobalMixin';
import ScrollIcon from 'vue-material-design-icons/UnfoldMoreHorizontal.vue'; import ScrollIcon from 'vue-material-design-icons/UnfoldMoreHorizontal.vue';
@ -43,14 +43,10 @@ import * as utils from "../services/Utils";
}, },
}) })
export default class ScrollerManager extends Mixins(GlobalMixin) { export default class ScrollerManager extends Mixins(GlobalMixin) {
/** Days from Timeline */ /** Rows from Timeline */
@Prop() days!: IDay[]; @Prop() rows!: IRow[];
/** Heads from Timeline */
@Prop() heads!: { [dayid: number]: IHeadRow };
/** Total height */ /** Total height */
@Prop() height!: number; @Prop() height!: number;
/** Height of a row */
@Prop() rowHeight!: number;
/** Actual recycler component */ /** Actual recycler component */
@Prop() recycler!: any; @Prop() recycler!: any;
/** Recycler before slot component */ /** Recycler before slot component */
@ -107,32 +103,31 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
} }
/** Re-create tick data in the next frame */ /** Re-create tick data in the next frame */
public async reflow(orderOnly = false) { public async reflow() {
if (this.reflowRequest) { if (this.reflowRequest) {
return; return;
} }
this.reflowRequest = true; this.reflowRequest = true;
await this.$nextTick(); await this.$nextTick();
this.reflowNow(orderOnly); this.reflowNow();
this.reflowRequest = false; this.reflowRequest = false;
} }
/** Re-create tick data */ /** Re-create tick data */
private reflowNow(orderOnly = false) { private reflowNow() {
if (!orderOnly) { // Recreate ticks data
this.recreate(); this.recreate();
}
// Get height of recycler
this.recyclerHeight = this.recycler.$refs.wrapper.clientHeight; this.recyclerHeight = this.recycler.$refs.wrapper.clientHeight;
// Static extra height at top // Static extra height at top (before slot)
const rb = this.recyclerBefore as Element; const extraY = this.recyclerBefore?.clientHeight || 0;
const extraHeight = rb?.clientHeight || 0;
// Compute tick positions // Compute tick positions
for (const tick of this.ticks) { for (const tick of this.ticks) {
tick.topC = (extraHeight + tick.topS + tick.top * this.rowHeight) * this.height / this.recyclerHeight; tick.top = (extraY + tick.y) * (this.height / this.recyclerHeight);
} }
// Do another pass to figure out which points are visible // Do another pass to figure out which points are visible
@ -143,13 +138,13 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
let prevShow = -9999; let prevShow = -9999;
for (const [idx, tick] of this.ticks.entries()) { for (const [idx, tick] of this.ticks.entries()) {
// You can't see these anyway, why bother? // You can't see these anyway, why bother?
if (tick.topC < minGap || tick.topC > this.height - minGap) { if (tick.top < minGap || tick.top > this.height - minGap) {
tick.s = false; tick.s = false;
continue; continue;
} }
// Will overlap with the previous tick. Skip anyway. // Will overlap with the previous tick. Skip anyway.
if (tick.topC - prevShow < minGap) { if (tick.top - prevShow < minGap) {
tick.s = false; tick.s = false;
continue; continue;
} }
@ -157,7 +152,7 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
// This is a labelled tick then show it anyway for the sake of best effort // This is a labelled tick then show it anyway for the sake of best effort
if (tick.text) { if (tick.text) {
tick.s = true; tick.s = true;
prevShow = tick.topC; prevShow = tick.top;
continue; continue;
} }
@ -173,8 +168,8 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
if (i < this.ticks.length) { if (i < this.ticks.length) {
// A labelled tick was found // A labelled tick was found
const nextLabelledTick = this.ticks[i]; const nextLabelledTick = this.ticks[i];
if (tick.topC + minGap > nextLabelledTick.topC && if (tick.top + minGap > nextLabelledTick.top &&
nextLabelledTick.topC < this.height - minGap) { // make sure this will be shown nextLabelledTick.top < this.height - minGap) { // make sure this will be shown
tick.s = false; tick.s = false;
continue; continue;
} }
@ -182,7 +177,7 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
// Show this tick // Show this tick
tick.s = true; tick.s = true;
prevShow = tick.topC; prevShow = tick.top;
} }
} }
@ -192,48 +187,45 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
this.ticks = []; this.ticks = [];
// Ticks // Ticks
let currTopRow = 0; let y = 0;
let currTopStatic = 0;
let prevYear = 9999; let prevYear = 9999;
let prevMonth = 0; let prevMonth = 0;
const thisYear = new Date().getFullYear(); const thisYear = new Date().getFullYear();
// Get a new tick // Get a new tick
const getTick = (day: IDay, text?: string | number): ITick => { const getTick = (dayId: number, text?: string | number): ITick => {
return { return {
dayId: day.dayid, dayId,
top: currTopRow, y: y,
topS: currTopStatic, text,
topC: 0, top: 0,
text: text, s: false,
}; };
} }
// Itearte over days // Itearte over rows
for (const day of this.days) { for (const row of this.rows) {
if (day.count === 0) { if (row.type === IRowType.HEAD) {
continue; if (Object.values(this.TagDayID).includes(row.dayId)) {
} // Blank tick
this.ticks.push(getTick(row.dayId));
} else {
// Make date string
const dateTaken = utils.dayIdToDate(row.dayId);
if (Object.values(this.TagDayID).includes(day.dayid)) { // Create tick if month changed
// Blank dash ticks only const dtYear = dateTaken.getUTCFullYear();
this.ticks.push(getTick(day)); const dtMonth = dateTaken.getUTCMonth()
} else { if (Number.isInteger(row.dayId) && (dtMonth !== prevMonth || dtYear !== prevYear)) {
// Make date string const text = (dtYear === prevYear || dtYear === thisYear) ? undefined : dtYear;
const dateTaken = utils.dayIdToDate(day.dayid); this.ticks.push(getTick(row.dayId, text));
}
// Create tick if month changed prevMonth = dtMonth;
const dtYear = dateTaken.getUTCFullYear(); prevYear = dtYear;
const dtMonth = dateTaken.getUTCMonth()
if (Number.isInteger(day.dayid) && (dtMonth !== prevMonth || dtYear !== prevYear)) {
this.ticks.push(getTick(day, (dtYear === prevYear || dtYear === thisYear) ? undefined : dtYear));
} }
prevMonth = dtMonth;
prevYear = dtYear;
} }
currTopStatic += this.heads[day.dayid].size; y += row.size;
currTopRow += day.rows.size;
} }
} }
@ -242,8 +234,10 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
this.hoverCursorY = y; this.hoverCursorY = y;
// Get index of previous tick // Get index of previous tick
let idx = this.ticks.findIndex(t => t.topC > y); let idx = this.ticks.findIndex(t => t.top >= y);
if (idx >= 1) { if (idx === 0) {
// use this tick
} else if (idx >= 1) {
idx = idx - 1; idx = idx - 1;
} else if (idx === -1 && this.ticks.length > 0) { } else if (idx === -1 && this.ticks.length > 0) {
idx = this.ticks.length - 1; idx = this.ticks.length - 1;

View File

@ -76,9 +76,8 @@
<!-- Managers --> <!-- Managers -->
<ScrollerManager ref="scrollerManager" <ScrollerManager ref="scrollerManager"
:days="days" :heads="heads" :rows="list"
:height="scrollerHeight" :height="scrollerHeight"
:rowHeight="rowHeight"
:recycler="$refs.recycler" :recycler="$refs.recycler"
:recyclerBefore="$refs.recyclerBefore" /> :recyclerBefore="$refs.recyclerBefore" />
@ -92,7 +91,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Watch, Mixins } from 'vue-property-decorator'; import { Component, Watch, Mixins } from 'vue-property-decorator';
import { IDay, IFolder, IHeadRow, IPhoto, IRow, IRowType, ITick } from "../types"; import { IDay, IFolder, IHeadRow, IPhoto, IRow, IRowType } from "../types";
import { generateUrl } from '@nextcloud/router' import { generateUrl } from '@nextcloud/router'
import { showError } from '@nextcloud/dialogs' import { showError } from '@nextcloud/dialogs'
import { getCanonicalLocale } from '@nextcloud/l10n'; import { getCanonicalLocale } from '@nextcloud/l10n';
@ -285,7 +284,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
this.list.filter(r => r.type !== IRowType.HEAD).forEach(row => { this.list.filter(r => r.type !== IRowType.HEAD).forEach(row => {
row.size = this.rowHeight; row.size = this.rowHeight;
}); });
this.scrollerManager.reflow(true); this.scrollerManager.reflow();
} }
/** /**

View File

@ -109,12 +109,10 @@ export enum IRowType {
export type ITick = { export type ITick = {
/** Day ID */ /** Day ID */
dayId: number; dayId: number;
/** Number of ROWS above this (dynamic) */ /** Display top position */
top: number; top: number;
/** Extra static distance from top (for headers) */ /** Y coordinate on recycler */
topS: number; y: number;
/** Actual Y position calculated (C) */
topC: number;
/** Text if any (e.g. year) */ /** Text if any (e.g. year) */
text?: string | number; text?: string | number;
/** Whether this tick should be shown */ /** Whether this tick should be shown */