diff --git a/assets/scripts/photos/list.js b/assets/scripts/photos/list.js new file mode 100644 index 0000000..370e6d1 --- /dev/null +++ b/assets/scripts/photos/list.js @@ -0,0 +1,111 @@ +// Eryn Wells + +class Item { + static allItems = []; + + element; + + #mouseoverRegionOffsets; + #currentRegion = 0; + + constructor(element) { + this.element = element; + this.setUpEventHandlers(); + + element._item = this; + } + + get title() { + return this.element.getAttribute("title"); + } + + get numberOfImages() { + const numberOfImages = this.element.dataset.numberOfImages; + if (typeof numberOfImages === "undefined" || numberOfImages === null) { + return 1; + } + + try { + return parseInt(numberOfImages); + } catch (e) { + console.error("Unable to parse data-number-of-images attribute:", numberOfImages); + return 1; + } + } + + get mouseoverRegionOffsets() { + let offsets = this.#mouseoverRegionOffsets; + + if (!offsets) { + const numberOfImages = this.numberOfImages; + offsets = new Array(numberOfImages); + + const rect = this.element.getBoundingClientRect(); + const widthOfRegion = rect.width / numberOfImages; + for (let i = 0; i < numberOfImages; i++) { + offsets[i] = i * widthOfRegion; + } + + this.#mouseoverRegionOffsets = offsets; + } + + return offsets; + } + + setUpEventHandlers() { + if (this.numberOfImages <= 1) { + return; + } + + this.element.addEventListener("mousemove", event => { + const offsetX = event.offsetX; + + let indexOfRegion = -1; + for (let regionOffset of this.mouseoverRegionOffsets) { + if (regionOffset > offsetX) { + break; + } + indexOfRegion += 1; + } + + if (indexOfRegion !== this.#currentRegion) { + console.debug(`Mouse moved at ${offsetX}, ${event.offsetY} in cell for '${this.title}' in region ${indexOfRegion}`); + // TODO: Set image to images[indexOfRegion] + this.#currentRegion = indexOfRegion; + } + }); + + this.element.addEventListener("mouseout", event => { + console.debug(`Mouse left cell for '${this.title}'`); + // TODO: Reset to the first image. + }); + } + + addToIntersectionObserver(intersectionObserver) { + intersectionObserver.observe(this.element); + } + + handleIntersectionObservation(entry, observer) { + if (entry.isIntersecting) { + console.debug(`Cell for ${this.title} entered the viewport`); + } else { + console.debug(`Cell for ${this.title} left the viewport`); + } + } +} + +let intersectionObserver; + +document.addEventListener("DOMContentLoaded", event => { + intersectionObserver = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + entry.target._item.handleIntersectionObservation(entry, observer); + }); + }, { threshold: 0.5 }); + + Item.allItems = Array.from(document.querySelectorAll(".photos.list > a")).map(cell => { + const item = new Item(cell) + item.addToIntersectionObserver(intersectionObserver); + return item; + }); +}); diff --git a/layouts/photos/list.html b/layouts/photos/list.html index 9153577..f33bfdd 100644 --- a/layouts/photos/list.html +++ b/layouts/photos/list.html @@ -17,3 +17,9 @@ {{ define "footer" }} {{ partial "footer.html" . }} {{ end }} + +{{ define "scripts" }} +{{- with resources.Get "scripts/photos/list.js" | fingerprint "md5" -}} + +{{- end -}} +{{ end }}