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 }