Implement selecting template for collage #14
6
main.go
6
main.go
@ -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
104
web/index.css
Normal 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;
|
||||||
|
}
|
134
web/index.html
134
web/index.html
@ -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>
|
||||||
balki marked this conversation as resolved
Outdated
|
|||||||
|
<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>
|
||||||
balki marked this conversation as resolved
Outdated
balki
commented
Remove empty line inside div Remove empty line inside 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>
|
||||||
|
148
web/index.js
148
web/index.js
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user
remove onChange