Implement selecting template for collage #14

Merged
balki merged 6 commits from template-chooser into main 2023-09-06 23:59:07 -04:00
4 changed files with 303 additions and 91 deletions

View File

@ -53,7 +53,10 @@ func main() {
if localAssets { if localAssets {
httpFileServer := http.FileServer(http.Dir("web")) httpFileServer := http.FileServer(http.Dir("web"))
http.Handle("/", httpFileServer) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Cache-Control", "no-cache")
httpFileServer.ServeHTTP(w, r)
})
} else { } else {
fs, err := fs.Sub(webFS, "web") fs, err := fs.Sub(webFS, "web")
@ -123,7 +126,6 @@ func MakeCollage(req *collage.Request) (string, error) {
out, err := os.Create(path.Join(collageDir, collageFile)) out, err := os.Create(path.Join(collageDir, collageFile))
if err != nil { if err != nil {
return "", fmt.Errorf("failed to create collage output file, err: %w", err) return "", fmt.Errorf("failed to create collage output file, err: %w", err)
// slog.Error("failed to create collage output file", "error", err)
} }
if err := collage.Make(req, imagesDirFs, out); err != nil { if err := collage.Make(req, imagesDirFs, out); err != nil {
return "", fmt.Errorf("failed to make collage, err: %w", err) return "", fmt.Errorf("failed to make collage, err: %w", err)

104
web/index.css Normal file
View File

@ -0,0 +1,104 @@
.container {
display: flex;
background-color: lightyellow;
height: calc(100vh - 20px);
}
.controls {
background-color: lightgrey;
display: flex;
align-items: center;
justify-content: space-around;
flex-direction: column;
flex: 25%;
}
.imagebox {
padding: 2rem;
flex: 75%;
}
.image-surface {
overflow: hidden;
margin: auto;
border: 1px solid;
height: 100%;
width: auto;
--collage-ap: 110 / 85;
aspect-ratio: var(--collage-ap);
}
.showbuton {
font-size: 2rem;
}
.templates {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.templates li {
list-style-type: none;
}
#page_size_selector {
width: 100%;
}
.template {
width: 100px;
height: 100px;
}
.template div {
border: 1px solid;
}
.single div {
width: 100%;
height: 100%;
}
.one-two {
display: grid;
grid-template-areas:
"one two"
"one three";
}
.one-two .img1{
grid-area: one;
}
.half-leftright {
display:flex;
}
.half-leftright .img {
flex: 50%;
}
.half-topbottom .img {
width: 100%;
height: 50%;
}
.two-one-two-leftright {
display: grid;
grid-template-areas:
"one two two three"
"four two two five";
}
.two-one-two-leftright .img2 {
grid-area: two;
}
.two-one-two-topbottom {
display: grid;
grid-template-areas:
"one two"
"three three"
"three three"
"four five"
}
.two-one-two-topbottom .img3 {
grid-area: three;
}

View File

@ -4,85 +4,85 @@
<link rel="stylesheet" href="croppie.css" /> <link rel="stylesheet" href="croppie.css" />
<link rel="icon" href="data:;base64,iVBORw0KGgo=" /> <link rel="icon" href="data:;base64,iVBORw0KGgo=" />
<script src="http://localhost:35729/livereload.js"></script> <script src="http://localhost:35729/livereload.js"></script>
<script src="croppie.js"></script> <script src="croppie.js" defer></script>
<script src="index.js"></script> <script src="index.js" defer></script>
<link rel="stylesheet" href="index.css" />
<!-- <!--
width: 3264px; width: 3264px;
height: 4224px; height: 4224px;
width: 8.5in; width: 8.5in;
height: 11in; height: 11in;
--> -->
<style>
.image-surface {
overflow: hidden;
margin: auto;
background-color: lightgreen;
}
.imagebox {
grid-area: image;
display:flex;
align-items: center;
justify-content: center;
padding: 50px;
flex: 70%;
}
.container {
display: flex;
background-color: lightyellow;
height: calc(100vh - 20px);
}
.controls {
background-color: lightgrey;
display: flex;
grid-area: controls;
align-items: center;
justify-content: center;
flex: 30%;
}
.showbuton {
font-size: 2rem;
}
.letter-portrait {
height: 100%;
aspect-ratio: 85 / 110;
}
.letter-portrait .collage-img {
height: 50%;
}
.letter-landscape-2 {
display:flex;
// width: 80vh;
height: 100%;
// margin: auto;
aspect-ratio: 110 / 85;
// aspect-ratio: 7 / 5;
gap: 1rem;
}
.letter-landscape-2 .img1 {
flex: 60%;
}
.letter-landscape-2 .img2 {
flex: 40%;
}
</style>
</head> </head>
<body onload="main()"> <body>
<div class="container"> <div class="container">
<div class="controls"> <div class="controls">
<div>
<button class="showbuton" onClick="snap()">Snap Collage</button>
<p><a href="" target="_blank" id="collage-url"></a></p> <label>
<span>Paper size</span>
<select id="page_size_selector" size=8>
<option value="letter-portrait">Letter (Portrait)</option>
<option selected value="letter-landscape">Letter (Landscape)</option>
<option value="fiveseven-portrait">5 × 7 (Portrait)</option>
<option value="fiveseven-landscape">7 × 5 (Landscape)</option>
<option value="foursix-portrait">4 × 6 (Portrait)</option>
<option value="foursix-landscape">4 × 6 (Landscape)</option>
</select>
</label>
<ul class="templates">
<li>
<div id="default_template" class="template single" data-collage-template="single">
<div class="img img1"></div>
</div> </div>
</li>
<li>
<div class="template one-two" data-collage-template="one-two">
<div class="img img1"></div>
<div class="img img2"></div>
<div class="img img3"></div>
</div>
</li>
<li>
<div class="template half-leftright" data-collage-template="half-leftright">
<div class="img img1"></div>
<div class="img img2"></div>
</div>
</li>
<li>
<div class="template half-topbottom" data-collage-template="half-topbottom">
<div class="img img1"></div>
<div class="img img2"></div>
</div>
</li>
<li>
<div class="template two-one-two-leftright" data-collage-template="two-one-two-leftright">
<div class="img img1"></div>
<div class="img img2"></div>
<div class="img img3"></div>
<div class="img img4"></div>
<div class="img img5"></div>
</div>
</li>
<li>
<div class="template two-one-two-topbottom" data-collage-template="two-one-two-topbottom">
<div class="img img1"></div>
<div class="img img2"></div>
<div class="img img3"></div>
<div class="img img4"></div>
<div class="img img5"></div>
</div>
</li>
</ul>
<button id="snapper" class="showbuton">Snap Collage</button>
<p><a href="" target="_blank" id="collage-url"></a></p>
</div> </div>
<div class="imagebox"> <div class="imagebox">
<div id="collage" class="image-surface letter-landscape-2"> <div id="collage" class="image-surface"></div>
<div class="collage-img img1" data-collage-image-url="images/img1.jpg">
<!-- <img src="img1.jpg"> -->
</div>
<div class="collage-img img2" data-collage-image-url="images/img2.jpg">
<!-- <img src="img2.jpg"> -->
</div>
</div>
</div> </div>
</div> </div>
</body> </body>

View File

@ -1,10 +1,90 @@
"use strict";
function main() { const pageSizes = {
initCollage("collage") "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 {HTMLAnchorElement} */
let collageUrlA
// collage state
let crops = [];
let pageSize = "letter-landscape";
const imageUrls = [
, // images start with index 1
"images/img1.jpg",
"images/img2.jpg",
"images/img3.jpg",
"images/img4.jpg",
"images/img5.jpg",
"images/img6.jpg",
"images/img7.jpg",
]
function main() {
snapButton = document.getElementById("snapper")
collageDiv = document.getElementById("collage")
pageSizeSelect = document.getElementById("page_size_selector")
collageUrlA = document.getElementById("collage-url")
snapButton.onclick = () => snap()
pageSizeSelect.onchange = () => pageSizeChange()
for(const tmpl of document.getElementsByClassName("template")) {
tmpl.onclick = () => applyTemplate(tmpl)
}
applyTemplate(document.getElementById("default_template"))
}
/**
* @param {HTMLDivElement} elem
* @param {string} imgUrl
*/
function makeCroppieElem(elem, imgUrl) { function makeCroppieElem(elem, imgUrl) {
cpie = new Croppie(elem, { const cpie = new Croppie(elem, {
viewport: { viewport: {
width: elem.clientWidth, width: elem.clientWidth,
height: elem.clientHeight, height: elem.clientHeight,
@ -18,18 +98,16 @@ function makeCroppieElem(elem, imgUrl) {
}); });
return cpie return cpie
} }
// collage state
var collageDivId; function initCollage() {
var crops = []; for(const cpie of crops) {
cpie.destroy()
}
crops = []
function initCollage(divId) { for(const elem of collageDiv.getElementsByClassName("img")) {
collageDivId = divId
const collageDiv = document.getElementById(collageDivId)
for(elem of collageDiv.getElementsByClassName("collage-img")) {
const cpie = makeCroppieElem(elem, elem.dataset.collageImageUrl) const cpie = makeCroppieElem(elem, elem.dataset.collageImageUrl)
const lastLen = crops.push(cpie) const lastLen = crops.push(cpie)
elem.dataset.collageCropieIndex = lastLen - 1 elem.dataset.collageCropieIndex = lastLen - 1
@ -56,15 +134,14 @@ async function makeCollage(req) {
} }
function snap() { function snap() {
const collageDiv = document.getElementById(collageDivId) const col = collageDiv.offsetLeft;
col = collageDiv.offsetLeft; const cot = collageDiv.offsetTop;
cot = collageDiv.offsetTop;
console.log("----------------------") console.log("----------------------")
req = { const req = {
background_image: "", background_image: "",
aspect: { aspect: {
width: 528 * 4 * 2, width: pageSizes[pageSize]["width"],
height: 816 * 4, height: pageSizes[pageSize]["height"],
}, },
dimension: { dimension: {
width: collageDiv.clientWidth, width: collageDiv.clientWidth,
@ -73,7 +150,7 @@ function snap() {
photos: [], photos: [],
}; };
for(elem of collageDiv.getElementsByClassName("collage-img")) { for(const elem of collageDiv.getElementsByClassName("img")) {
const cpie = crops[elem.dataset.collageCropieIndex] const cpie = crops[elem.dataset.collageCropieIndex]
// console.log(cpie.get().points) // console.log(cpie.get().points)
// console.log(elem.offsetLeft - col) // console.log(elem.offsetLeft - col)
@ -111,10 +188,39 @@ function snap() {
console.log(JSON.stringify(req)); console.log(JSON.stringify(req));
(async () => { (async () => {
collagFile = await makeCollage(req) const collagFile = await makeCollage(req)
// const collageUrlA = document.createElement("a");
const collageUrlA = document.getElementById("collage-url");
collageUrlA.href = `collages/${collagFile}`; collageUrlA.href = `collages/${collagFile}`;
collageUrlA.text = `${collagFile} generated`; collageUrlA.text = `${collagFile} generated`;
})(); })();
} }
function pageSizeChange() {
collageDiv.style.setProperty('--collage-ap', pageSizes[pageSizeSelect.value]["ap"])
pageSize = pageSizeSelect.value
initCollage()
}
/**
* @param {HTMLDivElement} templateDiv
*/
function applyTemplate(templateDiv) {
/** @type {HTMLDivElement} */
const templateClone = templateDiv.cloneNode(true)
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()
}
main()