erynwells.me/assets/scripts/photos/carousel.js
2023-04-06 08:45:35 -07:00

304 lines
9.4 KiB
JavaScript

// Eryn Wells <eryn@erynwells.me>
class Carousel {
carousel = null;
#items = null;
#caption = null;
constructor(element) {
this.carousel = element;
this.#caption = element.querySelector("figcaption");
}
get items() {
if (this.#items === null) {
const boundingRect = this.carousel.getBoundingClientRect();
this.#items = Array.from(this.carousel.querySelectorAll("ul > li")).map(item => {
let itemRect = item.getClientRects()[0];
let relativeX = itemRect.x - boundingRect.x;
return new CarouselItem(item, relativeX);
});
}
return this.#items;
}
get scrollContainer() {
return this.carousel.querySelector("ul");
}
setCaption(caption) {
if (!this.#caption) {
return;
}
this.#caption.innerHTML = caption;
}
scrollTo(index) {
this.scrollContainer.scrollTo(this.items[index].relativeX, 0);
}
setUpScrollEventListener(photoParametersTable) {
let previousScrollLeft = null;
let isScrollingLeft = true;
this.scrollContainer.addEventListener("scroll", event => {
const target = event.target;
const scrollLeft = target.scrollLeft;
const carouselRect = target.getBoundingClientRect();
const carouselRectHorizontalCenter = carouselRect.width / 2.0;
if (previousScrollLeft !== null) {
isScrollingLeft = scrollLeft > previousScrollLeft;
}
previousScrollLeft = scrollLeft;
this.items.forEach(item => {
const itemRelativeXCoordinate = isScrollingLeft ? item.relativeX - scrollLeft : item.relativeMaxX - scrollLeft;
const itemWasLeftOfContainerCenter = item.isLeftOfContainerCenter;
const itemIsLeftOfContainerCenter = itemRelativeXCoordinate < carouselRectHorizontalCenter;
item.isLeftOfContainerCenter = itemIsLeftOfContainerCenter;
if ( (isScrollingLeft && (!itemWasLeftOfContainerCenter && itemIsLeftOfContainerCenter))
|| (!isScrollingLeft && (itemWasLeftOfContainerCenter && !itemIsLeftOfContainerCenter))) {
this.setCaption(item.title);
photoParametersTable.setMakeModel(item.make, item.model);
photoParametersTable.setLocation(item.latitude, item.longitude);
photoParametersTable.setMegapixels(item.megapixels);
photoParametersTable.setSize(item.width, item.height);
photoParametersTable.setISO(item.iso);
photoParametersTable.setFocalLength(item.focalLength);
photoParametersTable.setFNumber(item.fNumber);
photoParametersTable.setExposureTime(item.exposureTime);
}
});
});
}
}
class CarouselItem {
element = null;
relativeX = 0;
isLeftOfContainerCenter = false;
constructor(element, relativeX) {
this.element = element;
this.relativeX = relativeX
}
get relativeMaxX() {
const rect = this.element.getBoundingClientRect();
return this.relativeX + rect.width;
}
get title() { return this.element.dataset.title; }
get latitude() { return this.element.dataset.latitude; }
get longitude() { return this.element.dataset.longitude; }
get megapixels() { return this.element.dataset.megapixels; }
get width() { return this.element.dataset.width; }
get height() { return this.element.dataset.height; }
get make() { return this.element.dataset.make; }
get model() { return this.element.dataset.model; }
get iso() { return this.element.dataset.iso; }
get focalLength() { return this.element.dataset.focalLength; }
get fNumber() { return this.element.dataset.fNumber; }
get exposureTime() { return this.element.dataset.exposureTime; }
}
class PhotoParametersTable {
tableElement;
#makeModelElement;
#latitudeElement;
#longitudeElement;
#megapixelsElement;
#widthElement;
#heightElement;
#isoElement;
#focalLengthElement;
#fNumberElement;
#exposureTimeElement;
constructor(element) {
this.tableElement = element;
}
setMakeModel(make, model) {
if (!this.#makeModelElement) {
this.#makeModelElement = this.#getElementWithQuerySelector("td.make-model");
}
if (!this.#makeModelElement) {
return;
}
let makeModel = "";
if (make && model) {
return `${make} ${model}`;
} else if (make) {
return make;
} else if (model) {
return model;
} else {
return "";
}
this.#makeModelElement.innerHTML = makeModel;
}
setLocation(latitude, longitude) {
let latitudeElement = this.#latitudeElement;
if (!latitudeElement) {
latitudeElement = this.#getElementWithQuerySelector("td.location > data.latitude");
this.#latitudeElement = latitudeElement;
}
let longitudeElement = this.#longitudeElement;
if (!longitudeElement) {
longitudeElement = this.#getElementWithQuerySelector("td.location > data.longitude");
this.#longitudeElement = longitudeElement;
}
if (!latitudeElement || !longitudeElement) {
return;
}
latitudeElement.innerHTML = latitude;
longitudeElement.innerHTML = longitude;
}
setMegapixels(megapixels) {
let megapixelsElement = this.#megapixelsElement;
if (!megapixelsElement) {
megapixelsElement = this.#getElementWithQuerySelector("td.size > data.megapixels");
this.#megapixelsElement = megapixelsElement;
}
if (!megapixelsElement) {
return;
}
megapixelsElement.innerHTML = megapixels;
}
setSize(width, height) {
let widthElement = this.#widthElement;
if (!widthElement) {
widthElement = this.#getElementWithQuerySelector("td.size > data.width");
this.#widthElement = widthElement;
}
let heightElement = this.#heightElement;
if (heightElement) {
heightElement = this.#getElementWithQuerySelector("td.size > data.height");
this.#heightElement = heightElement;
}
if (!widthElement || !heightElement) {
return;
}
widthElement.innerHTML = width;
heightElement.innerHTML = height;
}
setISO(iso) {
let isoElement = this.#isoElement;
if (!isoElement) {
isoElement = this.#getElementWithQuerySelector("td.iso");
this.#isoElement = isoElement;
}
if (!isoElement) {
return;
}
isoElement.innerHTML = `ISO ${iso}`;
}
setFocalLength(focalLength) {
let focalLengthElement = this.#focalLengthElement;
if (!focalLengthElement) {
focalLengthElement = this.#getElementWithQuerySelector("td.focal-length");
this.#focalLengthElement = focalLengthElement;
}
if (!focalLengthElement) {
return;
}
focalLengthElement.innerHTML = `${focalLength} mm`;
}
setFNumber(f) {
let fNumberElement = this.#fNumberElement;
if (!fNumberElement) {
fNumberElement = this.#getElementWithQuerySelector("td.f-number");
this.#fNumberElement = fNumberElement;
}
if (!fNumberElement) {
return;
}
fNumberElement.innerHTML = `ƒ${f}`;
}
setExposureTime(exposureTime) {
let exposureTimeElement = this.#exposureTimeElement;
if (!exposureTimeElement) {
exposureTimeElement = this.#getElementWithQuerySelector("td.exposure-time");
this.#exposureTimeElement = exposureTimeElement;
}
if (!exposureTimeElement) {
return;
}
exposureTimeElement.innerHTML = `${exposureTime} s`;
}
#getElementWithQuerySelector(query) {
const element = this.tableElement.querySelector(query);
if (!element) {
return null;
}
return element;
}
}
document.addEventListener("DOMContentLoaded", (event) => {
const carouselElements = document.querySelectorAll("figure.carousel");
if (carouselElements.length === 0) {
return;
}
const allCarousels = Array.from(carouselElements).sort((a, b) => {
const aRect = a.getBoundingClientRect();
const bRect = a.getBoundingClientRect();
return aRect.top - bRect.top;
}).map(elem => new Carousel(elem));
let photoParametersTable = null;
const photoParamsTableElement = document.querySelector(".photo-params table");
if (photoParamsTableElement) {
photoParametersTable = new PhotoParametersTable(photoParamsTableElement);
}
allCarousels.forEach(carousel => {
carousel.setUpScrollEventListener(photoParametersTable);
});
const url = new URL(window.location);
let photoGetParameter = url.searchParams.get("photo");
if (photoGetParameter) {
try {
photoGetParameter = parseInt(photoGetParameter);
allCarousels[0].scrollTo(photoGetParameter);
} catch (e) {
console.error("Unable to parse 'photo' GET parameter as integer:", e);
}
}
});