Refactor carousel code so more of it is in the Carousel class
Load the script as a module
This commit is contained in:
parent
bb655bcf30
commit
ad9f83ed39
2 changed files with 124 additions and 94 deletions
|
@ -2,10 +2,109 @@
|
|||
|
||||
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 {
|
||||
|
@ -171,104 +270,35 @@ class PhotoParametersTable {
|
|||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", (event) => {
|
||||
let allCarousels = Array.from(document.querySelectorAll("figure.carousel")).sort((a, b) => {
|
||||
const aRect = a.getBoundingClientRect();
|
||||
const bRect = a.getBoundingClientRect();
|
||||
return aRect.top - bRect.top;
|
||||
});
|
||||
|
||||
if (allCarousels.length === 0) {
|
||||
const carouselElements = document.querySelectorAll("figure.carousel");
|
||||
if (carouselElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let photoParams = null;
|
||||
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) {
|
||||
photoParams = new PhotoParametersTable(photoParamsTableElement);
|
||||
photoParametersTable = new PhotoParametersTable(photoParamsTableElement);
|
||||
}
|
||||
|
||||
allCarousels.forEach(carouselElement => {
|
||||
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; }
|
||||
}
|
||||
|
||||
let captionElement = carouselElement.querySelector("figcaption");
|
||||
|
||||
let carouselRect = carouselElement.getBoundingClientRect();
|
||||
let carouselRectHorizontalCenter = carouselRect.width / 2.0;
|
||||
|
||||
let carouselItems = Array.from(carouselElement.querySelectorAll("ul > li")).map(item => {
|
||||
let itemRect = item.getClientRects()[0];
|
||||
let relativeX = itemRect.x - carouselRect.x;
|
||||
return new CarouselItem(item, relativeX);
|
||||
});
|
||||
|
||||
let previousScrollLeft = null;
|
||||
let isScrollingLeft = true;
|
||||
|
||||
carouselElement.querySelector("ul").addEventListener("scroll", event => {
|
||||
const target = event.target;
|
||||
const scrollLeft = target.scrollLeft;
|
||||
|
||||
if (previousScrollLeft === null) {
|
||||
carouselRect = target.getBoundingClientRect();
|
||||
carouselRectHorizontalCenter = carouselRect.width / 2.0;
|
||||
}
|
||||
|
||||
if (previousScrollLeft !== null) {
|
||||
isScrollingLeft = scrollLeft > previousScrollLeft;
|
||||
}
|
||||
previousScrollLeft = scrollLeft;
|
||||
|
||||
carouselItems.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))) {
|
||||
if (captionElement) {
|
||||
captionElement.innerHTML = item.title;
|
||||
}
|
||||
|
||||
photoParams.setMakeModel(item.make, item.model);
|
||||
photoParams.setLocation(item.latitude, item.longitude);
|
||||
photoParams.setMegapixels(item.megapixels);
|
||||
photoParams.setSize(item.width, item.height);
|
||||
photoParams.setISO(item.iso);
|
||||
photoParams.setFocalLength(item.focalLength);
|
||||
photoParams.setFNumber(item.fNumber);
|
||||
photoParams.setExposureTime(item.exposureTime);
|
||||
}
|
||||
});
|
||||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -73,9 +73,9 @@
|
|||
|
||||
{{ define "scripts" }}
|
||||
{{- $photos := partial "photos/list.html" . -}}
|
||||
{{ if gt (len $photos) 1 }}
|
||||
{{ if gt (len $photos) 1 -}}
|
||||
{{- with resources.Get "scripts/photos/carousel.js" | fingerprint "md5" -}}
|
||||
<script src="{{ .RelPermalink }}"></script>
|
||||
<script type="module" src="{{ .RelPermalink }}"></script>
|
||||
{{- end -}}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
{{ end }}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue