Skip to content

Commit

Permalink
Cleanup / refactor CalanderRange
Browse files Browse the repository at this point in the history
  • Loading branch information
mayfield committed Nov 6, 2024
1 parent 5e34a0a commit 87cdf3d
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 72 deletions.
68 changes: 37 additions & 31 deletions src/common/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -2418,6 +2418,7 @@ sauce.ns('date', function() {
return time - offt;
}


function isMonthRange(start, end) {
// Start should be 00:00:00 of the start day (inclusive)
// End should be 00:00:00 of the day after (exclusive)
Expand All @@ -2432,6 +2433,7 @@ sauce.ns('date', function() {
e.getFullYear() === eom.getFullYear());
}


function isYearRange(start, end) {
// Start should be 00:00:00 of the start day (inclusive)
// End should be 00:00:00 of the day after (exclusive)
Expand All @@ -2442,12 +2444,17 @@ sauce.ns('date', function() {
e.getFullYear() - s.getFullYear() === 1);
}


class CalendarRange {

static isValidMetric(metric) {
return ['weeks', 'months', 'years'].includes(metric);
}

constructor(endDateSeed, period, metric) {
constructor(endDateSeed, period, metric, _cloning) {
if (_cloning) {
return;
}
if (endDateSeed != null && !(endDateSeed instanceof Date)) {
throw new TypeError('Date object required');
}
Expand All @@ -2457,36 +2464,49 @@ sauce.ns('date', function() {
if (period == null) {
throw new TypeError('period is invalid');
}
this.frozen = false;
this.period = period;
this.metric = metric;
this.setEndSeed(endDateSeed || tomorrow());
}

clone() {
const instance = new this.constructor(this.end, this.period, this.metric);
clone({frozen}={}) {
const instance = new this.constructor(null, null, null, /*cloning*/ true);
instance.start = new Date(this.start);
instance.end = new Date(this.end);
instance._update();
instance.period = this.period;
instance.metric = this.metric;
if (frozen) {
instance.frozen = true;
Object.freeze(instance);
}
return instance;
}

setPeriod(period) {
if (this.frozen) {
throw new TypeError("frozen");
}
if (typeof period !== 'number') {
throw new TypeError("Invalid period");
}
this.period = period;
this._update();
}

setMetric(metric) {
if (this.frozen) {
throw new TypeError("frozen");
}
if (!this.constructor.isValidMetric(metric)) {
throw new TypeError("Invalid metric");
}
this.metric = metric;
this._update();
}

setPeriodAggregateDays(days, precision=2) {
if (this.frozen) {
throw new TypeError("frozen");
}
let period;
if (this.metric === 'weeks') {
period = days / 7;
Expand All @@ -2499,6 +2519,9 @@ sauce.ns('date', function() {
}

shift(amount) {
if (this.frozen) {
throw new TypeError("frozen");
}
// Date.set*() funcs will floor float arguments, so round them first...
if (this.metric === 'weeks') {
const shift = Math.round(amount * this.period * 7);
Expand All @@ -2515,15 +2538,16 @@ sauce.ns('date', function() {
} else {
throw new TypeError('Invalid metric');
}
this._update();
}

getDays(options={}) {
const end = options.clipped ? this.clippedEnd : this.end;
return Math.round((end - this.start) / 86400 / 1000);
getDays() {
return Math.round((this.end - this.start) / 86400 / 1000);
}

setEndSeed(endSeed) {
if (this.frozen) {
throw new TypeError("frozen");
}
const end = toLocaleDayDate(endSeed);
if (isNaN(end)) {
throw new TypeError('invalid end-seed date value');
Expand Down Expand Up @@ -2554,10 +2578,12 @@ sauce.ns('date', function() {
}
this.start = start;
this.end = end;
this._update();
}

setStartSeed(startSeed) {
if (this.frozen) {
throw new TypeError("frozen");
}
const start = toLocaleDayDate(startSeed);
let end;
if (this.metric === 'weeks') {
Expand All @@ -2578,26 +2604,6 @@ sauce.ns('date', function() {
}
this.start = start;
this.end = end;
this._update();
}

_update() {
const start = new Date(this.start);
const end = new Date(this.end);
// XXX test usign tomorrow for compareison vs Date.now(), I think for some TZ or offbyone days tomorrow is better, but verify
const maxEnd = tomorrow();
this.clippedEnd = end > maxEnd ? maxEnd : end;
this.days = this.getDays();
this.clippedDays = this.getDays({clipped: true});
this.snapshot = {
start,
end,
clippedEnd: this.clippedEnd,
period: this.period,
metric: this.metric,
days: this.days,
clippedDays: this.clippedDays,
};
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/site/performance/charts.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ export class ActivityTimeRangeChart extends SauceChart {
const d = new Date(data.value);
if (days < 370) {
if (data.showToday) {
return this.view.LM('today'); // XXX [XXX to the XXX, why? 2024 fall]
return this.view.LM('today');
} else if (data.showYear) {
return [H.date(d, {style: 'month'}) + ' ', d.getFullYear()];
} else if (data.showMonth) {
Expand Down Expand Up @@ -751,7 +751,7 @@ export class ActivityTimeRangeChartView extends ChartView {
_onBeforeZoom() {
this._zoomContext = {
athlete: this.pageView.athlete,
range: this.pageView.getRangeSnapshot(),
range: this.pageView.range,
};
}
}
2 changes: 1 addition & 1 deletion src/site/performance/peaks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export class PeaksTableView extends views.ResizablePerfView {
this.filters = {};
this.hasMore = false;
this.pageSize = 100;
this.range = pageView.getRangeSnapshot();
this.range = pageView.range.clone({frozen: true});
this.athlete = pageView.athlete;
this.controlsView = new PeaksControlsView({panelView: this});
this.listenTo(pageView, 'before-update-activities',
Expand Down
68 changes: 30 additions & 38 deletions src/site/performance/views.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,7 @@ export class DetailsView extends PerfView {
}

async onLoadRecentClick(ev) {
const range = this.pageView.getRangeSnapshot();
const range = this.pageView.range;
const start = +range.start;
const end = +range.end;
const activities = await sauce.hist.getActivitiesForAthlete(this.pageView.athlete.id,
Expand Down Expand Up @@ -1317,7 +1317,7 @@ export class ActivityTablePanelView extends ResizablePerfView {

async updateAuxTableActivities() {
const auxRange = this.getPrefs('auxRange') || this.$('select[name="aux-range"]').val();
const range = this.pageView.getRangeClone();
const range = this.pageView.range.clone();
if (auxRange === 'custom') {
range.start = this.getPrefs('auxRangeStart') || undefined;
range.end = this.getPrefs('auxRangeEnd') || undefined;
Expand Down Expand Up @@ -1517,7 +1517,7 @@ export class MainView extends PerfView {
}

renderAttrs() {
const range = this.pageView.getRangeSnapshot();
const range = this.pageView.range;
return {range: [range.period, range.metric].join()};
}

Expand Down Expand Up @@ -1733,7 +1733,7 @@ export class MainView extends PerfView {
const isStart = el.classList.contains('start');
const cal = document.createElement('input');
cal.type = 'date';
const range = this.pageView.getRangeSnapshot();
const range = this.pageView.range;
if (isStart) {
cal.valueAsNumber = +range.start;
cal.max = D.dayBefore(range.end).toISOString().split('T')[0];
Expand Down Expand Up @@ -1773,7 +1773,7 @@ export class MainView extends PerfView {
}

updateRangeButtons(range, oldest) {
range = range || this.pageView.getRangeSnapshot();
range = range || this.pageView.range;
oldest = oldest || this.pageView.oldest;
const $start = this.$('header .range.start');
const $end = this.$('header .range.end');
Expand Down Expand Up @@ -1839,7 +1839,7 @@ export class PageView extends PerfView {
this.summaryView = new SummaryView({pageView: this});
this.mainView = new MainView({pageView: this});
this.detailsView = new DetailsView({pageView: this});
router.setFilters(this.athlete, this._range, {replace: true, all: this.allRange});
router.setFilters(this.athlete, this.range, {replace: true, all: this.allRange});
router.on('route:onNav', this.onRouterNav.bind(this));
router.on('route:onNavAll', this.onRouterNav.bind(this));
await super.init(options);
Expand All @@ -1851,9 +1851,9 @@ export class PageView extends PerfView {
this.allRange = f.all || (f.all === undefined && defaults.all);
if (this.allRange) {
const [period, metric] = this.getAllRange();
this._range = new D.CalendarRange(null, period, metric);
this.range = new D.CalendarRange(null, period, metric);
} else {
this._range = new D.CalendarRange(f.suggestedEnd,
this.range = new D.CalendarRange(f.suggestedEnd,
f.period || defaults.period || 4,
f.metric || defaults.metric || 'weeks');
}
Expand All @@ -1869,19 +1869,18 @@ export class PageView extends PerfView {
}

renderAttrs() {
const range = this.getRangeSnapshot();
return {
athletes: Array.from(this.athletes.values()),
athleteId: this.athlete && this.athlete.id,
range: [range.period, range.metric].join(),
range: [this.range.period, this.range.metric].join(),
};
}

async render() {
this.syncButtons.clear(); // Must not reuse on re-render() for DOM events.
const syncBtnPromise = this.athlete && this.getSyncButton(this.athlete.id);
await super.render();
const range = this._range.snapshot;
const range = this.range.clone({frozen: true});
const actsPromise = this.athlete && this._getActivities(range);
if (!this.athlete) {
return;
Expand Down Expand Up @@ -1945,9 +1944,9 @@ export class PageView extends PerfView {
// we need to treat updated activities from about 42 days before our range
// start as an update to our activities, because it's very possible the
// ATL/CTL seed values will be forward propagated into our activity range.
if (this._range && this._range.start && this._range.end) {
const rangeStart = +this._range.start - (42 * 86400 * 1000);
if (done.oldest <= this._range.end && done.newest >= rangeStart) {
if (this.range && this.range.start && this.range.end) {
const rangeStart = +this.range.start - (42 * 86400 * 1000);
if (done.oldest <= this.range.end && done.newest >= rangeStart) {
await this.schedUpdateActivities();
await this.refreshNewestAndOldest();
}
Expand Down Expand Up @@ -1988,7 +1987,7 @@ export class PageView extends PerfView {
const [period, metric] = this.getAllRange();
this._setRangePeriod(period, metric, {all: true});
}
this.router.setFilters(this.athlete, this._range, {all: this.allRange});
this.router.setFilters(this.athlete, this.range, {all: this.allRange});
await this.schedUpdateActivities();
}

Expand Down Expand Up @@ -2026,61 +2025,53 @@ export class PageView extends PerfView {
// This keeps the range from floating past the present when we go
// from a big range to a smaller one.
this.allRange = !!options.all;
this._range.setPeriod(period);
this._range.setMetric(metric);
this.range.setPeriod(period);
this.range.setMetric(metric);
const tomorrow = D.tomorrow();
this._range.setEndSeed(this._range.end > tomorrow ? tomorrow : this._range.end);
this.range.setEndSeed(this.range.end > tomorrow ? tomorrow : this.range.end);
this.savePrefs({defaultRange: {period, metric, all: options.all}}); // bg okay
}

getRangeSnapshot() {
return this._range.snapshot;
}

getRangeClone() {
return this._range.clone();
}

async setRangePeriod(period, metric, options={}) {
this._setRangePeriod(period, metric, options);
this.router.setFilters(this.athlete, this._range, options);
this.router.setFilters(this.athlete, this.range, options);
await this.schedUpdateActivities();
}

async setRangeCustomStartEnd(start, end) {
debugger;
if (start != null) {
this._range.start = new Date(start);
this.range.start = new Date(start);
}
if (end != null) {
this._range.end = new Date(end);
this.range.end = new Date(end);
}
this._range.setPeriodAggregateDays((this._range.end - this._range.start) / DAY);
this.router.setFilters(this.athlete, this._range);
this.range.setPeriodAggregateDays((this.range.end - this.range.start) / DAY);
this.router.setFilters(this.athlete, this.range);
await this.schedUpdateActivities();
}

shiftRange(offset) {
if (offset === Infinity) {
this._range.setEndSeed(D.tomorrow());
this.range.setEndSeed(D.tomorrow());
} else if (offset === -Infinity) {
this._range.setStartSeed(this.oldest);
this.range.setStartSeed(this.oldest);
} else {
this._range.shift(offset);
this.range.shift(offset);
}
this.router.setFilters(this.athlete, this._range);
this.router.setFilters(this.athlete, this.range);
return this.schedUpdateActivities();
}

async _schedUpdateActivities() {
const range = this._range.snapshot;
const range = this.range.clone({frozen: true});
this.trigger('before-update-activities', {athlete: this.athlete, range});
this._updateActivities(await this._getActivities(range));
}

async _getActivities(range) {
const start = +range.start;
const end = +range.clippedEnd;
const end = +range.end;
const activities = await sauce.hist.getActivitiesForAthlete(this.athlete.id,
{start, end, includeTrainingLoadSeed: true, excludeUpper: true});
return {activities, range};
Expand All @@ -2092,7 +2083,8 @@ export class PageView extends PerfView {
if (activities.length) {
({atl, ctl} = activities[0].trainingLoadSeed);
}
const daily = data.activitiesByDay(activities, range.start, range.clippedEnd, atl, ctl);
const end = Math.min(range.end, D.tomorrow());
const daily = data.activitiesByDay(activities, range.start, end, atl, ctl);
let metricData;
if (range.metric === 'weeks') {
metricData = data.aggregateActivitiesByWeek(daily, {isoWeekStart: true});
Expand Down

0 comments on commit 87cdf3d

Please sign in to comment.