312 lines
8.3 KiB
JavaScript
312 lines
8.3 KiB
JavaScript
"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<HTMLDivElement> */
|
|
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<HTMLDivElement> */
|
|
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()
|