photos/src/photos.ts
2026-05-31 09:56:07 +01:00

109 lines
2.7 KiB
TypeScript

import { ResponsiveImage } from './model/responsive-image';
import { createImage } from './helper/create-image';
export class Photos {
private readonly images: Array<HTMLImageElement>;
private _selectedId: number;
private timerId: NodeJS.Timeout = null;
private shouldNotChange = false;
public constructor(
images: Array<ResponsiveImage>,
private readonly landscapesContainer: HTMLElement,
private readonly portraitsContainer: HTMLElement,
private readonly pictureFrame: HTMLImageElement
) {
this.images = this.convertImages(images);
this.placeImages();
this.addEventListeners();
this.startAutoChange();
this.selectedId = 0;
}
private get selectedId(): number {
return this._selectedId;
}
private set selectedId(value: number) {
if (value < 0) {
value += this.images.length - 1;
}
this._selectedId = value % this.images.length;
this.loadToFrame(this.images[this.selectedId]);
this.images[this.selectedId].focus();
this.shouldNotChange = true;
}
private convertImages(images: Array<ResponsiveImage>) {
let portraits = 0; // evens
let landscapes = 1; // odds
const imgs = images.map((image, i) =>
createImage(
image,
'a photo',
Photos.isLandscape(image) ? (landscapes += 2) : (portraits += 2)
)
);
return imgs.sort((a, b) => a.tabIndex - b.tabIndex);
}
private placeImages() {
this.images.forEach(img => {
if (Photos.isLandscape(img)) {
img.classList.add('landscape');
this.landscapesContainer.appendChild(img);
} else {
img.classList.add('portrait');
this.portraitsContainer.appendChild(img);
}
});
}
private addEventListeners() {
window.document.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowLeft':
this.selectedId--;
break;
case 'ArrowRight':
this.selectedId++;
break;
case 'Tab':
if (this.timerId !== null) {
clearInterval(this.timerId);
this.timerId = null;
}
}
});
window.document.addEventListener(
'scroll',
() => (this.shouldNotChange = true)
);
this.images.forEach((image, i) =>
image.addEventListener('click', () => (this.selectedId = i))
);
}
private startAutoChange() {
this.timerId = setInterval(() => {
if (!this.shouldNotChange) {
this.selectedId++;
}
this.shouldNotChange = false;
}, 7000);
}
private loadToFrame(img: HTMLImageElement) {
this.pictureFrame.src = img.src;
}
private static isLandscape(
image: HTMLImageElement | ResponsiveImage
): boolean {
return image.width > image.height;
}
}