Note: This is a part two, if you need the starting files check part 1: starting files
If you were keen on the index.html
files on the last section, the template links did not have a href
attribute. That's because I wanted to do it dynamically, so create an index.js
file and paste the following code:
"use strict";
const chooseLinks = document.querySelectorAll(".choose");
chooseLinks.forEach(function (link, index) {
link.setAttribute("href", "upload.html?t=" + (index + 1));
});
The links had a class of choose
, the above code stores them in an htmlcollection
which can be traversed using a loop. In this case I use a forEach
loop that takes in the parameters of link and index. Note that an htmlcollection
is just like an array which starts at 0 so in setting the attribute, we add 1 to the index as there is no template 0.
The ?t=
part is the query parameter which look at later.
Inside index.html
, add link to the upload.js
file
Add toindex.html
before closing the body
tag:
<script src="./index.js"></script>
<script src="./upload.js"></script>
That's all about the index.js
, now create upload.js
file and inside it we'll declare the following variables.
upload.js
:
"use strict";
/**Maximum number of files to upload */
const maxFiles = 2;
const inputElement = document.querySelector("#files");
const downloadButton = document.querySelector("#downloadButton");
const previewButton = document.querySelector("#previewButton");
const hiddenImages = document.querySelector("#hidden-images");
/**main canvas */
const cvns = document.querySelector("#cvns");
/**preview canvas */
const preview = document.querySelector("#preview");
/**main canvas context */
const ctx = cvns.getContext("2d");
/**preview canvas context */
const previewCtx = preview.getContext("2d");
Since we're not using any database, we need a place to store our uploaded images, localStorage
is good but some images can be bigger than the localStorage
limit. Now that's why there's a declared hiddenImages
variables, when uploading the images they will appended inside the hiddenImages
element. If you check styles.css
#hidden-images
has a display of none.
Also, before painting the canvas, we need a context which for in case is 2d
. You can refer to MDN for in-depth explanation on canvas context.
Here's the function for saving the images, add it to upload.js
without the line numbers.
/**
* Saves the uploaded image in the dom.
*/
1 function saveImages() {
2 let uploadedFile = inputElement.files;
3 for (let index = 0; index < maxFiles; index++) {
4 if (uploadedFile[index]) {
5 const reader = new FileReader();
6 reader.readAsDataURL(uploadedFile[index]);
7 reader.onloadend = function () {
8 let src = this.result;
9 let img = document.createElement("img");
10 img.setAttribute("src", src.toString());
11 img.setAttribute("id", `img-${index + 1}`);
12 hiddenImages.append(img);
13 };
14 }
15 }
}
The input element for uploading the images was stored inside the inputElement
variable. Input form element of type file have a property of files
which we have stored in uploadedFile
variable on line 2 then loop through it twice to access the two images that will be uploaded.
On line 5 we store a FileReader
object inside the reader variable. FileReader is an object that enables that can read file data just as it's name says. Check documentation here.
FileReader has some event handlers and one one of them is the onloadend
which is triggered after file is read.
On line 7 we define the function to be triggred. The FileReader will return a a result and we store it inside the local variable src
. Then on line 9 we dynamicaly create an image element and set it's source and id on line 10 - 11. Each image will now have an id of img-1
and img-2
respectively.
Our function is now finished but we need to call it when images are uploaded, how do we do that? It easy look:
inputElement.addEventListener("change", saveImages);
Whenever our input changes, it will be called.
The next thing we need to do is painting on the canvas
but before that let me highlight on how the canvas draws images.
The following snippet is a sample of how it works:
context.drawImage(image, dx, dy, dWidth, dHeight);
The dx and dy parameters are x
and y
axis while the dWidth and dHeight are the image width and height respectively.
NOTE:The canvas x and y axis starts at the top-left corner.
Let's draw template 1..
Add inside upload.js
:
function template_1(img1, img2, show) {
if (show.toLowerCase() === "preview") {
/**preview canvas */
previewCtx.drawImage(img1, 0, 0, 275, 275); //first image
previewCtx.drawImage(img2, 100, 100, 137.5, 137.5); //second image
} else if (show.toLowerCase() === "main") {
/**main canvas */
ctx.drawImage(img1, 0, 0, 550, 550); //first image
ctx.drawImage(img2, 200, 200, 275, 275); //second image
}
}
It takes three parameters, two images and a show parameter. If show is defined as preview
then it draws on the smaller canvas and if show is main
it draws on the bigger canvas. Note the context used are the ones we defined as previewCtx
and ctx
at the start.
Template 2 is also the same just different x and y axis.
function template_2(img1, img2, show) {
if (show.toLowerCase() === "preview") {
/**preview canvas */
previewCtx.drawImage(img1, 0, 0, 137.5, 275); //first image
previewCtx.drawImage(img2, 137.5, 0, 137.5, 275); //second image
} else if (show.toLowerCase() === "main") {
/**main canvas */
ctx.drawImage(img1, 0, 0, 275, 550); //first image
ctx.drawImage(img2, 275, 0, 275, 550); //second image
}
}
Template 3 is as followed:
function template_3(img1, img2, show) {
if (show.toLowerCase() === "preview") {
/**preview canvas */
previewCtx.drawImage(img1, 0, 0, 275, 137.5); //first image
previewCtx.drawImage(img2, 0, 137.5, 275, 137.5); //second image
} else if (show.toLowerCase() === "main") {
/**main canvas */
ctx.drawImage(img1, 0, 0, 550, 275); //first image
ctx.drawImage(img2, 0, 275, 550, 275); //second image
}
}
Let's write a function of previewing the collage and then on the next last chapter we'll see how to download from the canvas.
First we'll prevent the previewButton
from redirect as that is the default behaviour of links.
Add to upload.js
:
previewButton.addEventListener("click", (e) => {
e.preventDefault();
preview.style.display = "block";
previewCollage();
});
The preview canvas was also hidden, on clicking as you can see above we display it then we call the previewCollage
function which we define next.
Add to upload.js
without the line numbers:
/**paints the preview canvas. */
1 function previewCollage() {
2 let img1 = document.querySelector("#img-1");
3 let img2 = document.querySelector("#img-2");
4 let query = window.location.search;
5 let pickedTemplate = query.split("=")[1];
6
7 if (img1 !== null && img2 !== null) {
8 if (pickedTemplate === "1") {
9 template_1(img1, img2, "preview");
10 } else if (pickedTemplate === "2") {
11 template_2(img1, img2, "preview");
12 } else if (pickedTemplate === "3") {
13 template_3(img1, img2, "preview");
14 } else {
15 template_1(img1, img2, "preview");
16 }
17 }
18 }
Remember at the start when we dynamically added links to the chooseLinks
variable inside the index.js
file. Now the links had a url path like upload.html?t=index + 1
. The ?t
part as I said is the query parameter/search. To get it you can try on the console
to write:
location.search
>"?t=2" //returns
To get the number we use split
which will return an array as on line 5 . Since we used '=' to split, the array returned will be like:
['?t','1']
Now the template picked can be found on index 1 as arrays start at index 0.
If it doesn't make sense try and re-read or as me in the comments I'll reply. Next section is downloading the collage.
Top comments (0)