Skip to content

Commit

Permalink
fix(sbb-clock): treat a specific date consistently (#2838)
Browse files Browse the repository at this point in the history
Co-authored-by: Jeremias Peier <jeremias.peier@sbb.ch>
  • Loading branch information
TomMenga and jeripeierSBB committed Jun 27, 2024
1 parent 857dc08 commit 4ffa4bc
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ snapshots["sbb-clock renders with fixed time DOM"] =
`<sbb-clock
data-initialized=""
now="12:30:00"
style="--sbb-clock-hours-animation-start-angle: 15deg; --sbb-clock-hours-animation-duration: 41400s; --sbb-clock-seconds-animation-start-angle: 0deg; --sbb-clock-seconds-animation-duration: 60s; --sbb-clock-animation-play-state: running;"
style="--sbb-clock-animation-play-state: paused; --sbb-clock-hours-animation-start-angle: 15deg; --sbb-clock-hours-animation-duration: 41400s; --sbb-clock-seconds-animation-start-angle: 0deg; --sbb-clock-seconds-animation-duration: 60s;"
>
</sbb-clock>
`;
Expand Down
180 changes: 91 additions & 89 deletions src/elements/clock/clock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,28 @@ export class SbbClockElement extends LitElement {
/** Move the minutes hand every minute. */
private _handMovement?: ReturnType<typeof setInterval>;

protected override willUpdate(changedProperties: PropertyValues<this>): void {
protected override async willUpdate(changedProperties: PropertyValues<this>): Promise<void> {
super.willUpdate(changedProperties);

if (!isServer && changedProperties.has('now')) {
if (this.now) {
this._removeSecondsAnimationStyles();
this._removeHoursAnimationStyles();
this._stopClock();
} else {
this._startClock();
}
await this._startOrConfigureClock();
}
}

protected override async firstUpdated(changedProperties: PropertyValues<this>): Promise<void> {
super.firstUpdated(changedProperties);

if (!isServer) {
document.addEventListener('visibilitychange', this._handlePageVisibilityChange, false);
await this._startOrConfigureClock();
}
}

public override disconnectedCallback(): void {
super.disconnectedCallback();
this._removeEventListeners();
}

private _handlePageVisibilityChange = async (): Promise<void> => {
if (document.visibilityState === 'hidden') {
await this._stopClock();
Expand All @@ -108,40 +116,51 @@ export class SbbClockElement extends LitElement {
}
};

private _addEventListeners(): void {
document.addEventListener('visibilitychange', this._handlePageVisibilityChange, false);
private async _startOrConfigureClock(): Promise<void> {
if (this.now) {
await this._stopClock();
this._resetSecondsHandAnimation();
this._setHandsStartingPosition();
} else {
await this._startClock();
}
}

private _removeEventListeners(): void {
document?.removeEventListener('visibilitychange', this._handlePageVisibilityChange);
this._clockHandHours?.removeEventListener('animationend', this._moveHoursHandFn);
this._clockHandSeconds?.removeEventListener('animationend', this._moveMinutesHandFn);
clearInterval(this._handMovement);
}
/** Starts the clock by defining the hands starting position then starting the animations. */
private async _startClock(): Promise<void> {
this._clockHandHours?.addEventListener(
'animationend',
this._moveHoursHandFn,
ADD_EVENT_LISTENER_OPTIONS,
);
this._clockHandSeconds?.addEventListener(
'animationend',
this._moveMinutesHandFn,
ADD_EVENT_LISTENER_OPTIONS,
);

private _removeHoursAnimationStyles(): void {
this._clockHandHours?.classList.remove('sbb-clock__hand-hours--initial-hour');
this.style.removeProperty('--sbb-clock-hours-animation-start-angle');
this.style.removeProperty('--sbb-clock-hours-animation-duration');
}
await new Promise(() =>
setTimeout(() => {
this._setHandsStartingPosition();

private _removeSecondsAnimationStyles(): void {
this._clockHandSeconds?.classList.remove('sbb-clock__hand-seconds--initial-minute');
this._clockHandMinutes?.classList.remove('sbb-clock__hand-minutes--no-transition');
this.style.removeProperty('--sbb-clock-seconds-animation-start-angle');
this.style.removeProperty('--sbb-clock-seconds-animation-duration');
this.style?.setProperty('--sbb-clock-animation-play-state', 'running');
}, INITIAL_TIMEOUT_DURATION),
);
}

/** Given the current date, calculates the hh/mm/ss values and the hh/mm/ss left to the next midnight. */
private _assignCurrentTime(): void {
const date = this.now ? null : new Date();
const [hours, minutes, seconds] = date
? [date.getHours(), date.getMinutes(), date.getSeconds()]
: this.now!.split(':').map((p) => +p);
/** Stops the clock by removing all the animations. */
private async _stopClock(): Promise<void> {
clearInterval(this._handMovement);

this._hours = hours % 12;
this._minutes = minutes;
this._seconds = seconds;
this._removeSecondsAnimationStyles();
this._removeHoursAnimationStyles();

this._clockHandHours?.removeEventListener('animationend', this._moveHoursHandFn);
this._clockHandSeconds?.removeEventListener('animationend', this._moveMinutesHandFn);

this._clockHandMinutes?.classList.add('sbb-clock__hand-minutes--no-transition');

this.style?.setProperty('--sbb-clock-animation-play-state', 'paused');
}

/** Set the starting position for the three hands on the clock face. */
Expand Down Expand Up @@ -185,11 +204,22 @@ export class SbbClockElement extends LitElement {

this._clockHandSeconds?.classList.add('sbb-clock__hand-seconds--initial-minute');
this._clockHandHours?.classList.add('sbb-clock__hand-hours--initial-hour');
this.style?.setProperty('--sbb-clock-animation-play-state', 'running');

this.toggleAttribute('data-initialized', true);
}

/** Given the current date, calculates the hh/mm/ss values and the hh/mm/ss left to the next midnight. */
private _assignCurrentTime(): void {
const date = this.now ? null : new Date();
const [hours, minutes, seconds] = date
? [date.getHours(), date.getMinutes(), date.getSeconds()]
: this.now!.split(':').map((p) => +p);

this._hours = hours % 12;
this._minutes = minutes;
this._seconds = seconds;
}

/** Set the starting position for the minutes hand. */
private _setMinutesHand(): void {
this._clockHandMinutes?.style.setProperty(
Expand Down Expand Up @@ -230,67 +260,39 @@ export class SbbClockElement extends LitElement {
this._setMinutesHand();
}

/** Stops the clock by removing all the animations. */
private async _stopClock(): Promise<void> {
clearInterval(this._handMovement);

if (this.now) {
this._setHandsStartingPosition();

// Wait a tick to before animation is added. Otherwise, the animation gets not completely
// removed which can lead to a mispositioned seconds hand.
await new Promise((resolve) => setTimeout(resolve));

this._clockHandSeconds?.classList.add('sbb-clock__hand-seconds--initial-minute');
this._clockHandHours?.classList.add('sbb-clock__hand-hours--initial-hour');
} else {
this._removeSecondsAnimationStyles();
this._removeHoursAnimationStyles();
/**
* Removing animation by overriding with empty string,
* then triggering a reflow and re add original animation by removing override.
* @private
*/
private _resetSecondsHandAnimation(): void {
if (!this._clockHandSeconds) {
return;
}
this._clockHandSeconds.style.animation = '';
// Hack to trigger reflow
this._clockHandSeconds.offsetHeight;
this._clockHandSeconds.style.removeProperty('animation');
}

private _removeEventListeners(): void {
document?.removeEventListener('visibilitychange', this._handlePageVisibilityChange);
this._clockHandHours?.removeEventListener('animationend', this._moveHoursHandFn);
this._clockHandSeconds?.removeEventListener('animationend', this._moveMinutesHandFn);

this._clockHandMinutes?.classList.add('sbb-clock__hand-minutes--no-transition');

this.style?.setProperty('--sbb-clock-animation-play-state', 'paused');
}

/** Starts the clock by defining the hands starting position then starting the animations. */
private async _startClock(): Promise<void> {
this._clockHandHours?.addEventListener(
'animationend',
this._moveHoursHandFn,
ADD_EVENT_LISTENER_OPTIONS,
);
this._clockHandSeconds?.addEventListener(
'animationend',
this._moveMinutesHandFn,
ADD_EVENT_LISTENER_OPTIONS,
);

await new Promise(() =>
setTimeout(() => this._setHandsStartingPosition(), INITIAL_TIMEOUT_DURATION),
);
clearInterval(this._handMovement);
}

protected override async firstUpdated(changedProperties: PropertyValues<this>): Promise<void> {
super.firstUpdated(changedProperties);

if (!isServer) {
this._addEventListeners();

if (this.now) {
await this._stopClock();
} else {
await this._startClock();
}
}
private _removeHoursAnimationStyles(): void {
this._clockHandHours?.classList.remove('sbb-clock__hand-hours--initial-hour');
this.style.removeProperty('--sbb-clock-hours-animation-start-angle');
this.style.removeProperty('--sbb-clock-hours-animation-duration');
}

public override disconnectedCallback(): void {
super.disconnectedCallback();
this._removeEventListeners();
private _removeSecondsAnimationStyles(): void {
this._clockHandSeconds?.classList.remove('sbb-clock__hand-seconds--initial-minute');
this._clockHandMinutes?.classList.remove('sbb-clock__hand-minutes--no-transition');
this.style.removeProperty('--sbb-clock-seconds-animation-start-angle');
this.style.removeProperty('--sbb-clock-seconds-animation-duration');
}

protected override render(): TemplateResult {
Expand Down

0 comments on commit 4ffa4bc

Please sign in to comment.