From ffa5ff333eabffe07394fb21bc413d7d238ee651 Mon Sep 17 00:00:00 2001 From: Tim Keller Date: Tue, 24 Jun 2025 19:23:33 -0500 Subject: move all files to /static --- static/src/slides.js | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 static/src/slides.js (limited to 'static/src/slides.js') diff --git a/static/src/slides.js b/static/src/slides.js new file mode 100644 index 0000000..e4f6406 --- /dev/null +++ b/static/src/slides.js @@ -0,0 +1,137 @@ +const Flickity = require("flickity") +import "flickity/dist/flickity.min.css" +import apiConnector from "./connector.js" + +class Slides { + constructor(slidesContainer) { + /* previous selected index */ + this.selectedIndex = 0 + this.assetIndex = 0 + + this.slidesContainer = slidesContainer + + /* append 11 cells to carousel */ + const carousel = this.slidesContainer.querySelector("#slideshow-carousel") + const cellTemplate = this.slidesContainer.querySelector("#carousel-cell-template") + this.cells = [] + for (let i = 0; i < 11; i++) + carousel.appendChild(cellTemplate.content.cloneNode(true)) + + /* initialize slides */ + this.flickity = new Flickity(carousel, { + wrapAround: true, + prevNextButtons: false, + pageDots: false, + resize: true, + setGallerySize: false, + }) + + this.flickity.on("scroll", progress => { this.scroll(progress) }) + this.flickity.on("staticClick", (e, pointer, cellElement, cellIndex) => { this.staticClick(e, pointer, cellElement, cellIndex) }) + this.flickity.on("dragEnd", () => { this.seek() }) + this.initImages() + + /* initialize seek buttons */ + const seekPrevButton = this.slidesContainer.querySelector("#prev-slide") + const seekNextButton = this.slidesContainer.querySelector("#next-slide") + + seekPrevButton.addEventListener("click", () => { this.flickity.previous() ; this.seek() }) + seekNextButton.addEventListener("click", () => { this.flickity.next() ; this.seek() }) + + /* initialize seek callback */ + apiConnector.seekCallbacks.push(c => { this.seekCallback() }) + + /* initialize top controls */ + const assetDownloadButton = this.slidesContainer.querySelector("#download") + + assetDownloadButton.addEventListener("click", () => { apiConnector.assetDownload(apiConnector.currentAsset) }) + } + + seek() { + // this is just like calculating movement in lazycachelist.py + // gets the min of the absolute values and returns signed value + const increment = [ + this.flickity.selectedIndex - this.selectedIndex, // no list wrap + this.flickity.selectedIndex - this.flickity.cells.length, // wrap backwards (0 -> -1) + this.flickity.cells.length - this.selectedIndex, // wrap forwards (-1 -> 0) + ].reduce((key, v) => Math.abs(v) < Math.abs(key) ? v : key) + this.selectedIndex = this.flickity.selectedIndex + this.assetIndex += increment + apiConnector.seek(increment) + } + + seekCallback() { + let i + if (this.assetIndex !== apiConnector.assetIndex) { + this.assetIndex = apiConnector.assetIndex + i = apiConnector.movement + + for (; i > 0; i--) this.flickity.next() + for (; i < 0; i++) this.flickity.previous() + this.selectedIndex = this.flickity.selectedIndex + } + + // load new imgs + // TODO need to make the 11 cells a constant somehow + for (i = 0; i < this.flickity.cells.length; i++) { + const x = (i + this.selectedIndex + 6) % this.flickity.cells.length + const e = this.flickity.cells[x].element + const img = e.firstElementChild + img.src = apiConnector.assetPreviewSrc(apiConnector.assets[i]) + } + } + + /* Flickity function for scrolling to ensure next and prev pics are always + * visible and to transition between states */ + scroll(progress) { + const normalizedProgress = progress / (1 / (this.flickity.cells.length-1)) + const liveSelectedIndex = Math.round(normalizedProgress) + const localizedProgress = normalizedProgress - liveSelectedIndex + + const prevSelectedCell = this.flickity.cells.at((liveSelectedIndex-1) % this.flickity.cells.length).element + const liveSelectedCell = this.flickity.cells.at((liveSelectedIndex ) % this.flickity.cells.length).element + const nextSelectedCell = this.flickity.cells.at((liveSelectedIndex+1) % this.flickity.cells.length).element + + const prevSelectedImage = prevSelectedCell.firstElementChild + const liveSelectedImage = liveSelectedCell.firstElementChild + const nextSelectedImage = nextSelectedCell.firstElementChild + + const prevMargin = prevSelectedCell.clientWidth - prevSelectedImage.clientWidth + const liveMargin = liveSelectedCell.clientWidth - liveSelectedImage.clientWidth + const nextMargin = nextSelectedCell.clientWidth - nextSelectedImage.clientWidth + + liveSelectedImage.style.marginLeft = liveMargin / 2 + "px" + nextSelectedImage.style.marginLeft = Math.max(0, Math.min(nextMargin, nextMargin * (localizedProgress))) + "px" + prevSelectedImage.style.marginLeft = prevMargin - Math.max(0, Math.min(prevMargin, prevMargin * localizedProgress * -1)) + "px" // TODO clean this + } + + /* jump to clicked on slide */ + staticClick(e, pointer, cellElement, cellIndex) { + this.flickity.select(cellIndex) + this.seek() + } + + /* make sure images have correct margin when loaded since scroll function + * depends on them being loaded */ + positionImageStatic(img) { + const i = parseInt(img.dataset.index) + if (i == this.flickity.selectedIndex) + img.style.marginLeft = (img.parentElement.clientWidth - img.clientWidth) / 2 + "px" + else if ((i + 1) % this.flickity.cells.length == this.flickity.selectedIndex) + img.style.marginLeft = img.parentElement.clientWidth - img.clientWidth + "px" + } + + imageLoaded(e) { this.positionImageStatic(e.target) } + initImages() { + const imgs = this.slidesContainer.querySelectorAll("#slideshow-carousel img") + for (let i = 0; i < imgs.length; i++) { + const img = imgs[i] + img.dataset.index = i + img.addEventListener("load", e => { this.imageLoaded(e) }) + if (img.complete) + this.positionImageStatic(img) + } + } +} + +export default slidesContainer => { new Slides(slidesContainer); return true } -- cgit v1.2.3