"use strict"; const pageSizes = { "letter-portrait" : { "ap": "85 / 110", "width": 3264, "height": 4224, }, "letter-landscape" : { "ap": "110 / 85", "width": 4224, "height": 3264, }, "fiveseven-portrait" : { "ap": "5 / 7", "width": 2250, "height": 3150, }, "fiveseven-landscape" : { "ap": "7 / 5", "width": 3150, "height": 2250, }, "foursix-portrait" : { "ap": "4 / 6", "width": 1800, "height": 2700, }, "foursix-landscape" : { "ap": "6 / 4", "width": 2700, "height": 1800, }, } // elements /** @type {HTMLButtonElement} */ let snapButton /** @type {HTMLDivElement} */ let collageDiv /** @type {HTMLSelectElement} */ let pageSizeSelect /** @type {HTMLDialogElement} */ let noticeDialog /** @type {HTMLAnchorElement} */ let collageUrlA /** @type {HTMLButtonElement} */ let reorderButton /** @type {HTMLDivElement} */ let previewDiv /** @type {HTMLButtonElement} */ let imagePrevBtn /** @type {HTMLButtonElement} */ let imageNextBtn /** @type {HTMLButtonElement} */ let imageDoneBtn /** @type {HTMLDivElement} */ let imageChooserControls // collage state let crops = []; let currentCropIndex = -1; let pageSize = "letter-landscape"; /** @type {String[]} */ let imageUrls = [] function main() { snapButton = document.getElementById("snapper") collageDiv = document.getElementById("collage") pageSizeSelect = document.getElementById("page_size_selector") noticeDialog = document.getElementById("notice_dialog") collageUrlA = document.getElementById("collage-url") reorderButton = document.getElementById("reorder_btn") previewDiv = document.getElementById("image-preview-box") imageChooserControls = document.getElementById("image-chooser-controls") imagePrevBtn = document.getElementById("image_prev_btn") imageNextBtn = document.getElementById("image_next_btn") imageDoneBtn = document.getElementById("image_done_btn") imagePrevBtn.onclick = () => { let newIndex = currentCropIndex - 1; if(newIndex < 0) { newIndex = 0 } currentCropIndex = newIndex changeOpacity() } imageNextBtn.onclick = () => { let newIndex = currentCropIndex + 1; if(newIndex >= crops.length) { newIndex = crops.length - 1 } currentCropIndex = newIndex changeOpacity() } imageDoneBtn.onclick = () => { currentCropIndex = -1 imageChooserControls.style.display = 'none'; /** @type {HTMLCollectionOf */ const divs = collageDiv.getElementsByClassName("img") for(const elem of divs) { elem.style.opacity = "100%" } } snapButton.onclick = () => snap() pageSizeSelect.onchange = () => pageSizeChange() reorderButton.onclick = () => reorder() for(const tmpl of document.getElementsByClassName("template")) { // Assumes second class in the template is the collage's template const [_, collageTemplate] = tmpl.classList tmpl.dataset.collageTemplate = collageTemplate tmpl.onclick = () => applyTemplate(tmpl) } const queryUrls = loadImageUrlsFromQuery() // Skipping first entry in array to make the images start with index 1 imageUrls = [,].concat(queryUrls) pageSizeChange() applyTemplate(document.getElementById("default_template")) } /** * @param {HTMLDivElement} elem * @param {string} imgUrl */ function makeCroppieElem(elem, imgUrl) { const cpie = new Croppie(elem, { viewport: { width: elem.clientWidth, height: elem.clientHeight, type: 'square' }, showZoomer: false, }); cpie.bind({ url: imgUrl }); return cpie } function initCollage() { for(const cpie of crops) { cpie.destroy() } crops = [] for(const elem of collageDiv.getElementsByClassName("img")) { const cpie = makeCroppieElem(elem, elem.dataset.collageImageUrl) const lastLen = crops.push(cpie) elem.dataset.collageCropieIndex = lastLen - 1 } } async function makeCollage(req) { const resp = await fetch("make-collage", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(req), }) return await resp.text(); } function snap() { const col = collageDiv.offsetLeft; const cot = collageDiv.offsetTop; const req = { background_image: "", aspect: { width: pageSizes[pageSize]["width"], height: pageSizes[pageSize]["height"], }, dimension: { width: collageDiv.clientWidth, height: collageDiv.clientHeight, }, photos: [], }; for(const elem of collageDiv.getElementsByClassName("img")) { const cpie = crops[elem.dataset.collageCropieIndex] const fsx = elem.offsetLeft - col const fsy = elem.offsetTop - cot const [sx, sy, ex, ey] = cpie.get().points; const photo = { image: elem.dataset.collageImageUrl.slice("/photos/".length), crop: { start: { x: parseInt(sx), y: parseInt(sy), }, end: { x: parseInt(ex), y: parseInt(ey), }, }, frame: { start: { x: fsx, y: fsy, }, end: { x: fsx + elem.clientWidth, y: fsy + elem.clientHeight, }, }, }; req.photos.push(photo) } (async () => { noticeDialog.show() collageUrlA.text = "Collage is being generated..."; const collagFile = await makeCollage(req) collageUrlA.href = `collages/${collagFile}`; collageUrlA.text = `${collagFile} generated`; })(); } function pageSizeChange() { // https://stackoverflow.com/a/37802204 document.documentElement.style.setProperty('--collage-ap', pageSizes[pageSizeSelect.value]["ap"]) pageSize = pageSizeSelect.value initCollage() } /** @param {HTMLDivElement} templateDiv */ function applyTemplate(templateDiv) { document.getElementsByClassName("template-selected").item(0)?.classList.remove("template-selected") /** @type {HTMLDivElement} */ const templateClone = templateDiv.cloneNode(true) templateDiv.classList.add("template-selected") for (const index in imageUrls) { const url = imageUrls[index] const imgClass = `img${index}` const [imgDiv] = templateClone.getElementsByClassName(imgClass) if(imgDiv === undefined) { break; } imgDiv.dataset.collageImageUrl = url; } collageDiv.replaceChildren(...templateClone.children) collageDiv.classList.remove(collageDiv.dataset.collageTemplate) collageDiv.classList.add(templateDiv.dataset.collageTemplate) collageDiv.dataset.collageTemplate = templateDiv.dataset.collageTemplate initCollage() imageDoneBtn.click() } function loadImageUrlsFromQuery() { const params = new URLSearchParams(window.location.search) const urlsstr = params.get('urls') return JSON.parse(urlsstr) } function reorder() { imageChooserControls.style.display = 'block'; previewDiv.replaceChildren() currentCropIndex = 0; for (const index in imageUrls) { const url = imageUrls[index] const img = new Image() img.src = url previewDiv.appendChild(img) img.onclick = () => { const cpie = crops[currentCropIndex] const elem = cpie.element elem.dataset.collageImageUrl = url cpie.destroy() crops[currentCropIndex] = makeCroppieElem(elem, url) } } changeOpacity() } function changeOpacity() { /** @type {HTMLCollectionOf */ const divs = collageDiv.getElementsByClassName("img") for(const elem of divs) { if (elem.dataset.collageCropieIndex != currentCropIndex) { elem.style.opacity = "25%" } else { elem.style.opacity = "100%" } } } main()