You've already forked collage-maker
							
							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() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	
remove onChange