diff --git a/packages/@ourworldindata/grapher/src/chart/ChartManager.ts b/packages/@ourworldindata/grapher/src/chart/ChartManager.ts index 6e0b13718a..da091b95d0 100644 --- a/packages/@ourworldindata/grapher/src/chart/ChartManager.ts +++ b/packages/@ourworldindata/grapher/src/chart/ChartManager.ts @@ -99,8 +99,4 @@ export interface ChartManager { detailsOrderedByReference?: string[] detailsMarkerInSvg?: DetailsMarker - - isTimelineAnimationActive?: boolean - animationStartTime?: number - animationEndTime?: number } diff --git a/packages/@ourworldindata/grapher/src/core/Grapher.tsx b/packages/@ourworldindata/grapher/src/core/Grapher.tsx index 28bdc29919..43ebec007d 100644 --- a/packages/@ourworldindata/grapher/src/core/Grapher.tsx +++ b/packages/@ourworldindata/grapher/src/core/Grapher.tsx @@ -853,7 +853,8 @@ export class Grapher @observable.ref isPlaying = false @observable.ref isTimelineAnimationActive = false // true if the timeline animation is either playing or paused but not finished - @observable.ref animationStartTime: Time | undefined = undefined + @observable.ref animationStartTime?: Time + @observable.ref areHandlesOnSameTimeBeforeAnimation?: boolean @observable.ref isEntitySelectorModalOrDrawerOpen = false @@ -1148,12 +1149,12 @@ export class Grapher } @computed get startHandleTimeBound(): TimeBound { - if (this.onlySingleTimeSelectionPossible) return this.endHandleTimeBound + if (this.isSingleTimeSelectionActive) return this.endHandleTimeBound return this.timelineHandleTimeBounds[0] } set startHandleTimeBound(newValue: TimeBound) { - if (this.onlySingleTimeSelectionPossible) + if (this.isSingleTimeSelectionActive) this.timelineHandleTimeBounds = [newValue, newValue] else this.timelineHandleTimeBounds = [ @@ -1163,7 +1164,7 @@ export class Grapher } set endHandleTimeBound(newValue: TimeBound) { - if (this.onlySingleTimeSelectionPossible) + if (this.isSingleTimeSelectionActive) this.timelineHandleTimeBounds = [newValue, newValue] else this.timelineHandleTimeBounds = [ @@ -1192,11 +1193,16 @@ export class Grapher return findClosestTime(this.times, this.endHandleTimeBound) } - @computed private get onlySingleTimeSelectionPossible(): boolean { - // scatter plots should not be animated as time scatter - if (this.isPlaying && this.isScatter && !this.isRelativeMode) - return true + @computed get isSingleTimeScatterAnimationActive(): boolean { + return ( + this.isTimelineAnimationActive && + this.isScatter && + !this.isRelativeMode && + !!this.areHandlesOnSameTimeBeforeAnimation + ) + } + @computed private get onlySingleTimeSelectionPossible(): boolean { return ( this.isDiscreteBar || this.isStackedDiscreteBar || @@ -1205,6 +1211,13 @@ export class Grapher ) } + @computed private get isSingleTimeSelectionActive(): boolean { + return ( + this.onlySingleTimeSelectionPossible || + this.isSingleTimeScatterAnimationActive + ) + } + @computed get shouldLinkToOwid(): boolean { if ( this.isEmbeddedInAnOwidPage || diff --git a/packages/@ourworldindata/grapher/src/scatterCharts/ScatterPlotChart.tsx b/packages/@ourworldindata/grapher/src/scatterCharts/ScatterPlotChart.tsx index 292ab961d7..bdd1ad66f6 100644 --- a/packages/@ourworldindata/grapher/src/scatterCharts/ScatterPlotChart.tsx +++ b/packages/@ourworldindata/grapher/src/scatterCharts/ScatterPlotChart.tsx @@ -1231,11 +1231,10 @@ export class ScatterPlotChart axis.label = this.currentVerticalAxisLabel if ( - this.manager.isTimelineAnimationActive && - this.domainsForAnimation.y && - !this.manager.isRelativeMode + this.manager.isSingleTimeScatterAnimationActive && + this.domainsForAnimation.y ) { - axis.domain = this.domainsForAnimation.y + axis.updateDomainPreservingUserSettings(this.domainsForAnimation.y) } else if (manager.isRelativeMode) { axis.domain = yDomainDefault // Overwrite author's min/max } else { @@ -1297,11 +1296,10 @@ export class ScatterPlotChart axis.label = this.currentHorizontalAxisLabel if ( - this.manager.isTimelineAnimationActive && - this.domainsForAnimation.x && - !this.manager.isRelativeMode + this.manager.isSingleTimeScatterAnimationActive && + this.domainsForAnimation.x ) { - axis.domain = this.domainsForAnimation.x + axis.updateDomainPreservingUserSettings(this.domainsForAnimation.x) } else if (manager.isRelativeMode) { axis.domain = xDomainDefault // Overwrite author's min/max } else { diff --git a/packages/@ourworldindata/grapher/src/scatterCharts/ScatterPlotChartConstants.ts b/packages/@ourworldindata/grapher/src/scatterCharts/ScatterPlotChartConstants.ts index ea4e5015a2..c9c78d5f1f 100644 --- a/packages/@ourworldindata/grapher/src/scatterCharts/ScatterPlotChartConstants.ts +++ b/packages/@ourworldindata/grapher/src/scatterCharts/ScatterPlotChartConstants.ts @@ -37,6 +37,9 @@ export interface ScatterPlotManager extends ChartManager { hasTimeline?: boolean hideScatterLabels?: boolean isModalOpen?: boolean + isSingleTimeScatterAnimationActive?: boolean + animationStartTime?: number + animationEndTime?: number } export interface ScatterSeries extends ChartSeries { diff --git a/packages/@ourworldindata/grapher/src/timeline/TimelineController.ts b/packages/@ourworldindata/grapher/src/timeline/TimelineController.ts index d7dda3c4c9..d7f493408b 100644 --- a/packages/@ourworldindata/grapher/src/timeline/TimelineController.ts +++ b/packages/@ourworldindata/grapher/src/timeline/TimelineController.ts @@ -15,6 +15,7 @@ export interface TimelineManager { times: Time[] startHandleTimeBound: TimeBound endHandleTimeBound: TimeBound + areHandlesOnSameTimeBeforeAnimation?: boolean msPerTick?: number onPlay?: () => void } @@ -145,6 +146,7 @@ export class TimelineController { this.manager.isPlaying = false this.manager.isTimelineAnimationActive = false this.manager.animationStartTime = undefined + this.manager.areHandlesOnSameTimeBeforeAnimation = undefined } private pause(): void { @@ -157,6 +159,9 @@ export class TimelineController { async togglePlay(): Promise { if (!this.manager.isTimelineAnimationActive) { + this.manager.areHandlesOnSameTimeBeforeAnimation = + this.manager.startHandleTimeBound === + this.manager.endHandleTimeBound this.manager.animationStartTime = this.isAtEnd() ? findClosestTime(this.timesAsc, this.beginning)! : this.startTime