Today we are going to be building a meme generator in JavaScript. In this project requires no external frameworks or libraries, and it’s perfect for beginners. Let’s start π
You can see the Demo Here Meme Generator in JavaScript
π Create a πindex.html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>meme generator in Javascript</title>
<link rel="stylesheet" href="style.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@500&display=swap" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="meme-header">
<h1>Meme Generator</h1>
<p>Make memes from images in just a few clicks</p>
</div>
<div class="meme-section">
<div class="meme-generator">
<canvas id="meme"></canvas>
</div>
<div class="meme-input-section">
<div class="input-file-section">
<input type="file" id="imageFileInput">
<label for="imageFileInput">
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" class="rW1DZNdb5THuH-xexbQ-9" style="vertical-align:middle" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"></path></svg>
Choose a File
</label>
</div>
<div class="text-section">
<div class="top-text">
<input type="text" id="topTextInput" placeholder="Top Text">
</div>
<div class="bottom-text">
<input type="text" id="bottomTextInput" placeholder="Bottom Text">
</div>
<div class="button_section">
<button type="button" id="export">Download</button>
</div>
</div>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
β here when the user has uploaded the image and entered the top text and bottom text value. Then javascript is going to generate the image and place it inside the canvas.
π Now Create a πstyle.css file
* {
padding: 0%;
margin: 0%;
box-sizing: border-box;
font-family: "Roboto", sans-serif;
}
.container {
max-width: 1320px;
margin-left: auto;
margin-right: auto;
width: 100%;
}
.meme-header {
text-align: center;
padding: 30px 0px;
}
.meme-header h1 {
font-size: 50px;
}
.meme-section {
background: #f0f0f0;
padding: 20px;
margin: auto;
width: 1000px;
display: flex;
border-radius: 10px;
}
.meme-generator {
width: 400px;
font-family: sans-serif;
}
.meme-generator label {
display: block;
font-weight: bold;
margin-bottom: 10px;
}
.meme-generator input {
width: 100%;
box-sizing: border-box;
margin-bottom: 20px;
}
#meme {
width: 100%;
}
.meme-input-section {
display: flex;
flex-direction: column;
padding: 15px;
margin-left: 50px;
}
.text-section {
margin-top: 70px;
}
input[type="file"] {
display: none;
}
.input-file-section label {
background: #5969e2;
color: #fff;
padding: 15px 20px;
font-size: 18px;
cursor: pointer;
}
.button_section {
display: none;
}
.button_section p {
margin-top: 10px;
}
#export {
margin-top: 20px;
border: 1px solid #5969e2;
padding: 15px 20px;
font-size: 18px;
cursor: pointer;
transition: all 0.1s linear;
}
#export:hover {
background: #5969e2;
color: #fff;
}
.top-text {
margin-bottom: 20px;
}
#topTextInput,
#bottomTextInput {
padding: 0px 50px;
min-height: 40px;
}
π‘ Now Itβs time For Javascript Code π.
π create πindex.js File
β we need to first essentially grab every single one of our HTML elements and refer to them in the javascript. So we are going to be creating some constants here.
const imageFileInput = document.querySelector("#imageFileInput");
const canvas = document.querySelector("#meme");
const topTextInput = document.querySelector("#topTextInput");
const bottomTextInput = document.querySelector("#bottomTextInput");
let image;
β here is basically the image variable that’s going to get updated every time the user selects a new image.
βNow create a updateMemeCanvas() function. this function is going to essentially render out the meme. In this function, we pass four parameters canvas, image, top text, and bottom text.
updateMemeCanvas(
canvas,
image,
topTextInput.value,
bottomTextInput.value
);
β whenever the user picks a new image then updateMemeCanvas() function call. In this function, we are going to be grabbing the first file that exists within the file input field. Then we are going to be converting it into a data URL.
β if you guys don’t know a data URL is simply just essentially just your image represented in text in the form of a URL.
blob:http://127.0.0.1:5500/e79f0cbd-7c44-4e82-a77f-6d3b2aabdf81
β now we are going to be reassigning that image variable to be a new value.
imageFileInput.addEventListener("change",(e)=>{
const imageDataUrl = URL.createObjectURL(e.target.files[0]);
image = new Image();
image.src = imageDataUrl;
})
this image here as a standard image element like this
<img src="blob:null/cb0798d4-ba5e-4c8e-8d36-1dfa4f6b6a71">
β image in javascript so basically it needs to be now provided to the updateMemeCanvas() function. Here we set addEventListner to listen load event on that image inside function we call updateMemeCanvas() function.
imageFileInput.addEventListener("change", (e) => {
const imageDataUrl = URL.createObjectURL(e.target.files[0]);
console.log(imageDataUrl);
image = new Image();
image.src = imageDataUrl;
image.addEventListener(
"load",
() => {
downloadBtnSection.style.display = "block";
updateMemeCanvas(
canvas,
image,
topTextInput.value,
bottomTextInput.value
);
},
{ once: true }
);
});
β Here load image should probably only happen once so we are going to in addEventListener function define once: true
β Now back to in updateMemeCanvas() function. Inside function rendering 2d context then we define width and height same as image width and height. Now when it comes to updating the canvas background. We are going to be set like canvas width provides same as image width and the same goes for the canvas height.
β Then we set canvas width and height is now the exact same dimensions as the image which means drawImage passes through the image element and we can draw this image at the zero position.
function updateMemeCanvas(canvas, image, topText, bottomText) {
const ctx = canvas.getContext("2d");
const width = image.width;
const height = image.height;
// Update canvas background
canvas.width = width;
canvas.height = height;
ctx.drawImage(image, 0, 0);
}
β Now we declare more variables in updateMemeCanvas() function. The first one is going to be a constant font size. The second one is constant yOffset is the height divided by 25. This yOffset the space between the top of the image and text and the bottom and that text.
function updateMemeCanvas(canvas, image, topText, bottomText) {
const ctx = canvas.getContext("2d");
const width = image.width;
const height = image.height;
const fontSize = Math.floor(width / 10);
const yOffset = height / 25;
// Update canvas background
canvas.width = width;
canvas.height = height;
ctx.drawImage(image, 0, 0);
}
β Now prepare text first work on the outer stroke on that text black stroke. and set the stroke width or line width.
function updateMemeCanvas(canvas, image, topText, bottomText) {
const ctx = canvas.getContext("2d");
const width = image.width;
const height = image.height;
const fontSize = Math.floor(width / 10);
const yOffset = height / 25;
// Update canvas background
canvas.width = width;
canvas.height = height;
ctx.drawImage(image, 0, 0);
// Prepare text
ctx.strokeStyle = "black";
ctx.lineWidth = Math.floor(fontSize / 4);
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.lineJoin = "round";
ctx.font = `${fontSize}px sans-serif`;
}
β Now rendering top text and bottom text.
function updateMemeCanvas(canvas, image, topText, bottomText) {
const ctx = canvas.getContext("2d");
const width = image.width;
const height = image.height;
const fontSize = Math.floor(width / 10);
const yOffset = height / 25;
// Update canvas background
canvas.width = width;
canvas.height = height;
ctx.drawImage(image, 0, 0);
// Prepare text
ctx.strokeStyle = "black";
ctx.lineWidth = Math.floor(fontSize / 4);
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.lineJoin = "round";
ctx.font = `${fontSize}px sans-serif`;
// Add top text
ctx.textBaseline = "top";
ctx.strokeText(topText, width / 2, yOffset);
ctx.fillText(topText, width / 2, yOffset);
// Add bottom text
ctx.textBaseline = "bottom";
ctx.strokeText(bottomText, width / 2, height - yOffset);
ctx.fillText(bottomText, width / 2, height - yOffset);
}
βNow add the updateMemeCanvas() function in event listener on top text and bottom text.
topTextInput.addEventListener("keyup", () => {
updateMemeCanvas(canvas, image, topTextInput.value, bottomTextInput.value);
});
bottomTextInput.addEventListener("keyup", () => {
updateMemeCanvas(canvas, image, topTextInput.value, bottomTextInput.value);
});
β Now Making Meme Downloadable
document.getElementById("export").onclick = function () {
var img = canvas.toDataURL("image/png");
var link = document.createElement("a");
link.download = "My Meme";
link.href = img;
link.click();
};
Full source Code: Meme Generator in JavaScript
π watch the video How to Build a Meme Generator with JavaScript (No Frameworks Project)
Also Check: 15 JavaScript Basic Concepts You Should Know